aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorHelmut Eller2026-04-04 20:59:46 +0200
committerHelmut Eller2026-04-04 20:59:46 +0200
commit6eec001187e8551f32b6498e6dc60cdc58c2e515 (patch)
tree13233de9f0a05ef86a51500e8b1870b75ff20c81 /lisp
parente4ea27119e79012f9d651cb61d1115589d91ef39 (diff)
parent01a9d78a7e4c7d7fa5b799e4fdc2caf77a012734 (diff)
downloademacs-feature/igc3.tar.gz
emacs-feature/igc3.zip
Merge branch 'master' into feature/igc3feature/igc3
Diffstat (limited to 'lisp')
-rw-r--r--lisp/auth-source-pass.el3
-rw-r--r--lisp/cus-edit.el48
-rw-r--r--lisp/dabbrev.el6
-rw-r--r--lisp/desktop.el8
-rw-r--r--lisp/dired.el67
-rw-r--r--lisp/display-fill-column-indicator.el1
-rw-r--r--lisp/emacs-lisp/byte-opt.el2
-rw-r--r--lisp/emacs-lisp/debug.el3
-rw-r--r--lisp/emacs-lisp/shortdoc-doc.el1528
-rw-r--r--lisp/emacs-lisp/shortdoc.el1648
-rw-r--r--lisp/emacs-lisp/warnings.el1
-rw-r--r--lisp/epa-file.el17
-rw-r--r--lisp/erc/erc-track.el2
-rw-r--r--lisp/erc/erc.el17
-rw-r--r--lisp/files.el281
-rw-r--r--lisp/frame.el1
-rw-r--r--lisp/frameset.el10
-rw-r--r--lisp/gnus/gnus-delay.el18
-rw-r--r--lisp/gnus/gnus-icalendar.el472
-rw-r--r--lisp/help.el12
-rw-r--r--lisp/info.el11
-rw-r--r--lisp/international/characters.el6
-rw-r--r--lisp/international/emoji.el8
-rw-r--r--lisp/jsonrpc.el2
-rw-r--r--lisp/kmacro.el32
-rw-r--r--lisp/language/korea-util.el13
-rw-r--r--lisp/menu-bar.el9
-rw-r--r--lisp/minibuffer.el4
-rw-r--r--lisp/net/imap.el3
-rw-r--r--lisp/net/tramp-adb.el22
-rw-r--r--lisp/net/tramp-container.el9
-rw-r--r--lisp/net/tramp-crypt.el22
-rw-r--r--lisp/net/tramp-ftp.el2
-rw-r--r--lisp/net/tramp-fuse.el5
-rw-r--r--lisp/net/tramp-gvfs.el26
-rw-r--r--lisp/net/tramp-sh.el93
-rw-r--r--lisp/net/tramp-smb.el28
-rw-r--r--lisp/net/tramp-sshfs.el2
-rw-r--r--lisp/net/tramp-sudoedit.el28
-rw-r--r--lisp/net/tramp.el243
-rw-r--r--lisp/obsolete/linum.el1
-rw-r--r--lisp/outline.el6
-rw-r--r--lisp/paren.el7
-rw-r--r--lisp/printing.el14
-rw-r--r--lisp/progmodes/c-ts-mode.el1
-rw-r--r--lisp/progmodes/compile.el2
-rw-r--r--lisp/progmodes/eglot.el16
-rw-r--r--lisp/progmodes/flymake.el2
-rw-r--r--lisp/progmodes/grep.el8
-rw-r--r--lisp/progmodes/xref.el108
-rw-r--r--lisp/server.el3
-rw-r--r--lisp/subr.el17
-rw-r--r--lisp/tab-bar.el1
-rw-r--r--lisp/textmodes/css-mode.el4
-rw-r--r--lisp/textmodes/enriched.el10
-rw-r--r--lisp/textmodes/fill.el2
-rw-r--r--lisp/textmodes/markdown-ts-mode.el8
-rw-r--r--lisp/time-stamp.el60
-rw-r--r--lisp/tool-bar.el2
-rw-r--r--lisp/treesit.el50
-rw-r--r--lisp/vc/vc-hooks.el1
-rw-r--r--lisp/whitespace.el23
-rw-r--r--lisp/window.el8
-rw-r--r--lisp/xt-mouse.el8
64 files changed, 2669 insertions, 2406 deletions
diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el
index adaa901612a..15dfa2f358f 100644
--- a/lisp/auth-source-pass.el
+++ b/lisp/auth-source-pass.el
@@ -85,6 +85,9 @@ HOST, USER, PORT, REQUIRE, and MAX."
85 ((null host) 85 ((null host)
86 ;; Do not build a result, as none will match when HOST is nil 86 ;; Do not build a result, as none will match when HOST is nil
87 nil) 87 nil)
88 ((not (file-directory-p auth-source-pass-filename))
89 ;; Do nothing if the password-store folder doesn't exist.
90 nil)
88 (auth-source-pass-extra-query-keywords 91 (auth-source-pass-extra-query-keywords
89 (auth-source-pass--build-result-many host port user require max)) 92 (auth-source-pass--build-result-many host port user require max))
90 (t 93 (t
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index 52677f435ee..87d8ecade54 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -1084,7 +1084,7 @@ even if it doesn't match the type.)
1084\(fn [VARIABLE VALUE]...)" 1084\(fn [VARIABLE VALUE]...)"
1085 (declare (debug setq)) 1085 (declare (debug setq))
1086 (unless (evenp (length pairs)) 1086 (unless (evenp (length pairs))
1087 (error "PAIRS must have an even number of variable/value members")) 1087 (signal 'wrong-number-of-arguments (list 'setopt (length pairs))))
1088 (let ((expr nil)) 1088 (let ((expr nil))
1089 (while pairs 1089 (while pairs
1090 (unless (symbolp (car pairs)) 1090 (unless (symbolp (car pairs))
@@ -1100,12 +1100,54 @@ even if it doesn't match the type.)
1100 ;; Check that the type is correct. 1100 ;; Check that the type is correct.
1101 (when-let* ((type (get variable 'custom-type))) 1101 (when-let* ((type (get variable 'custom-type)))
1102 (unless (widget-apply (widget-convert type) :match value) 1102 (unless (widget-apply (widget-convert type) :match value)
1103 (warn "Value `%S' for variable `%s' does not match its type \"%s\"" 1103 (warn "Value does not match %S's type `%S': %S" variable type value)))
1104 value variable type)))
1105 (put variable 'custom-check-value (list value)) 1104 (put variable 'custom-check-value (list value))
1106 (funcall (or (get variable 'custom-set) #'set-default) variable value)) 1105 (funcall (or (get variable 'custom-set) #'set-default) variable value))
1107 1106
1108;;;###autoload 1107;;;###autoload
1108(defmacro setopt-local (&rest pairs)
1109 "Set buffer local VARIABLE/VALUE pairs, and return the final VALUE.
1110This is like `setq-local', but is meant for user options instead of
1111plain variables. This means that `setopt-local' will execute any
1112`custom-set' form associated with VARIABLE. Unlike `setopt',
1113`setopt-local' does not affect a user option's global value.
1114
1115Note that `setopt-local' will emit a warning if the type of a VALUE does
1116not match the type of the corresponding VARIABLE as declared by
1117`defcustom'. (VARIABLE will be assigned the value even if it doesn't
1118match the type.)
1119
1120Signal an error if a `custom-set' form does not support the
1121`buffer-local' argument.
1122
1123\(fn [VARIABLE VALUE]...)"
1124 (declare (debug setq))
1125 (unless (evenp (length pairs))
1126 (signal 'wrong-number-of-arguments (list 'setopt-local (length pairs))))
1127 (let ((expr nil))
1128 (while pairs
1129 (unless (symbolp (car pairs))
1130 (error "Attempting to set a non-symbol: %s" (car pairs)))
1131 (push `(setopt--set-local ',(car pairs) ,(cadr pairs))
1132 expr)
1133 (setq pairs (cddr pairs)))
1134 (macroexp-progn (nreverse expr))))
1135
1136;;;###autoload
1137(defun setopt--set-local (variable value)
1138 (custom-load-symbol variable)
1139 ;; Check that the type is correct.
1140 (when-let* ((type (get variable 'custom-type)))
1141 (unless (widget-apply (widget-convert type) :match value)
1142 (warn "Value does not match %S's type `%S': %S" variable type value)))
1143 (condition-case _
1144 (funcall (or (get variable 'custom-set)
1145 (lambda (x v &optional _) (set-local x v)))
1146 variable value 'buffer-local)
1147 (wrong-number-of-arguments
1148 (error "The setter of %S does not support setopt-local" variable))))
1149
1150;;;###autoload
1109(defun customize-save-variable (variable value &optional comment) 1151(defun customize-save-variable (variable value &optional comment)
1110 "Set the default for VARIABLE to VALUE, and save it for future sessions. 1152 "Set the default for VARIABLE to VALUE, and save it for future sessions.
1111Return VALUE. 1153Return VALUE.
diff --git a/lisp/dabbrev.el b/lisp/dabbrev.el
index 0e3c8bf6a5f..9fe2904c415 100644
--- a/lisp/dabbrev.el
+++ b/lisp/dabbrev.el
@@ -398,7 +398,11 @@ then it searches *all* buffers."
398 ;; Set it so `dabbrev-capf' won't reset the vars. 398 ;; Set it so `dabbrev-capf' won't reset the vars.
399 (setq dabbrev--last-abbrev-location (point-marker)) 399 (setq dabbrev--last-abbrev-location (point-marker))
400 (let ((completion-at-point-functions '(dabbrev-capf))) 400 (let ((completion-at-point-functions '(dabbrev-capf)))
401 (completion-at-point))) 401 (unless (completion-at-point)
402 (user-error "No dynamic expansion for \"%s\" found%s"
403 (dabbrev--abbrev-at-point)
404 (if dabbrev--check-other-buffers
405 "" " in this-buffer")))))
402 406
403(defun dabbrev-capf () 407(defun dabbrev-capf ()
404 "Dabbrev completion function for `completion-at-point-functions'." 408 "Dabbrev completion function for `completion-at-point-functions'."
diff --git a/lisp/desktop.el b/lisp/desktop.el
index f478cf2307b..0cdd554e295 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -775,6 +775,7 @@ if different)."
775 ;; Don't delete daemon's initial frame, or 775 ;; Don't delete daemon's initial frame, or
776 ;; we'll never be able to close the last 776 ;; we'll never be able to close the last
777 ;; client's frame (Bug#26912). 777 ;; client's frame (Bug#26912).
778 ;; Use `frame-initial-p'?
778 (and (daemonp) (eq frame terminal-frame)) 779 (and (daemonp) (eq frame terminal-frame))
779 (frame-parameter frame 'desktop-dont-clear)) 780 (frame-parameter frame 'desktop-dont-clear))
780 (delete-frame frame)) 781 (delete-frame frame))
@@ -1067,9 +1068,8 @@ DIRNAME must be the directory in which the desktop file will be saved."
1067 (and (not (frame-parameter frame 'desktop-dont-save)) 1068 (and (not (frame-parameter frame 'desktop-dont-save))
1068 ;; Don't save daemon initial frames, since we cannot (and don't 1069 ;; Don't save daemon initial frames, since we cannot (and don't
1069 ;; need to) restore them. 1070 ;; need to) restore them.
1070 (not (and (daemonp) 1071 (not (and (daemonp) ;; FIXME: Remove `daemonp'?
1071 (equal (terminal-name (frame-terminal frame)) 1072 (frame-initial-p frame)))))
1072 "initial_terminal")))))
1073 1073
1074(defconst desktop--app-id `(desktop . ,desktop-file-version)) 1074(defconst desktop--app-id `(desktop . ,desktop-file-version))
1075 1075
@@ -1260,7 +1260,7 @@ This function also sets `desktop-dirname' to nil."
1260 "True if calling `desktop-restore-frameset' will actually restore it." 1260 "True if calling `desktop-restore-frameset' will actually restore it."
1261 (and desktop-restore-frames desktop-saved-frameset 1261 (and desktop-restore-frames desktop-saved-frameset
1262 ;; Don't restore frames when the selected frame is the daemon's 1262 ;; Don't restore frames when the selected frame is the daemon's
1263 ;; initial frame. 1263 ;; initial frame. Use `frame-initial-p'?
1264 (not (and (daemonp) (eq (selected-frame) terminal-frame))) 1264 (not (and (daemonp) (eq (selected-frame) terminal-frame)))
1265 t)) 1265 t))
1266 1266
diff --git a/lisp/dired.el b/lisp/dired.el
index 7f598433a9d..4aded86e40d 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -649,6 +649,10 @@ The match starts at the beginning of the line and ends after the end
649of the line. 649of the line.
650Subexpression 2 must end right before the \\n.") 650Subexpression 2 must end right before the \\n.")
651 651
652(defvar dired--ls-error-buffer nil
653 "Non-nil if the current dired invocation yields an `ls' error.
654The non-nil value is the buffer containing the error message.")
655
652 656
653;;; Faces 657;;; Faces
654 658
@@ -1230,7 +1234,16 @@ Type \\[describe-mode] after entering Dired for more info.
1230If DIRNAME is already in a Dired buffer, that buffer is used without refresh." 1234If DIRNAME is already in a Dired buffer, that buffer is used without refresh."
1231 ;; Cannot use (interactive "D") because of wildcards. 1235 ;; Cannot use (interactive "D") because of wildcards.
1232 (interactive (dired-read-dir-and-switches "")) 1236 (interactive (dired-read-dir-and-switches ""))
1233 (pop-to-buffer-same-window (dired-noselect dirname switches))) 1237 (prog1 (pop-to-buffer-same-window (dired-noselect dirname switches))
1238 (dired--display-ls-error)))
1239
1240;; This is needed to let clicks on the menu bar invoke Dired even if
1241;; some feature remaps the Dired command to another command.
1242;;;###autoload
1243(defun dired-from-menubar (dirname &optional switches)
1244 "Edit an existing directory."
1245 (interactive (dired-read-dir-and-switches ""))
1246 (dired dirname switches))
1234 1247
1235;;;###autoload (keymap-set ctl-x-4-map "d" #'dired-other-window) 1248;;;###autoload (keymap-set ctl-x-4-map "d" #'dired-other-window)
1236;;;###autoload 1249;;;###autoload
@@ -1240,21 +1253,24 @@ If this command needs to split the current window, it by default obeys
1240the user options `split-height-threshold' and `split-width-threshold', 1253the user options `split-height-threshold' and `split-width-threshold',
1241when it decides whether to split the window horizontally or vertically." 1254when it decides whether to split the window horizontally or vertically."
1242 (interactive (dired-read-dir-and-switches "in other window ")) 1255 (interactive (dired-read-dir-and-switches "in other window "))
1243 (switch-to-buffer-other-window (dired-noselect dirname switches))) 1256 (prog1 (switch-to-buffer-other-window (dired-noselect dirname switches))
1257 (dired--display-ls-error)))
1244 1258
1245;;;###autoload (keymap-set ctl-x-5-map "d" #'dired-other-frame) 1259;;;###autoload (keymap-set ctl-x-5-map "d" #'dired-other-frame)
1246;;;###autoload 1260;;;###autoload
1247(defun dired-other-frame (dirname &optional switches) 1261(defun dired-other-frame (dirname &optional switches)
1248 "\"Edit\" directory DIRNAME. Like `dired' but make a new frame." 1262 "\"Edit\" directory DIRNAME. Like `dired' but make a new frame."
1249 (interactive (dired-read-dir-and-switches "in other frame ")) 1263 (interactive (dired-read-dir-and-switches "in other frame "))
1250 (switch-to-buffer-other-frame (dired-noselect dirname switches))) 1264 (prog1 (switch-to-buffer-other-frame (dired-noselect dirname switches))
1265 (dired--display-ls-error)))
1251 1266
1252;;;###autoload (keymap-set tab-prefix-map "d" #'dired-other-tab) 1267;;;###autoload (keymap-set tab-prefix-map "d" #'dired-other-tab)
1253;;;###autoload 1268;;;###autoload
1254(defun dired-other-tab (dirname &optional switches) 1269(defun dired-other-tab (dirname &optional switches)
1255 "\"Edit\" directory DIRNAME. Like `dired' but make a new tab." 1270 "\"Edit\" directory DIRNAME. Like `dired' but make a new tab."
1256 (interactive (dired-read-dir-and-switches "in other tab ")) 1271 (interactive (dired-read-dir-and-switches "in other tab "))
1257 (switch-to-buffer-other-tab (dired-noselect dirname switches))) 1272 (prog1 (switch-to-buffer-other-tab (dired-noselect dirname switches))
1273 (dired--display-ls-error)))
1258 1274
1259;;;###autoload 1275;;;###autoload
1260(defun dired-noselect (dir-or-list &optional switches) 1276(defun dired-noselect (dir-or-list &optional switches)
@@ -1439,10 +1455,19 @@ The return value is the target column for the file names."
1439 (let ((failed t)) 1455 (let ((failed t))
1440 (unwind-protect 1456 (unwind-protect
1441 (progn (dired-readin) 1457 (progn (dired-readin)
1442 (setq failed nil)) 1458 ;; Check for file entries (they are listed below the
1443 ;; dired-readin can fail if parent directories are inaccessible. 1459 ;; directory name and (if present) wildcard lines).
1444 ;; Don't leave an empty buffer around in that case. 1460 (while (and (skip-syntax-forward "\s")
1445 (if failed (kill-buffer buffer)))) 1461 (looking-at "\\(.+:$\\|wildcard\\)"))
1462 (forward-line))
1463 (unless (eobp)
1464 (setq failed nil)))
1465 ;; No file entries indicates an `ls' error, and `dired-readin'
1466 ;; can fail if parent directories are inaccessible. In either
1467 ;; case don't leave the Dired buffer around.
1468 (when failed
1469 (kill-buffer buffer)
1470 (setq buffer nil))))
1446 (goto-char (point-min)) 1471 (goto-char (point-min))
1447 (dired-initial-position dirname)) 1472 (dired-initial-position dirname))
1448 (when (consp dired-directory) 1473 (when (consp dired-directory)
@@ -4003,20 +4028,11 @@ Considers buffers closer to the car of `buffer-list' to be more recent."
4003 (not (memq buffer1 (memq buffer2 (buffer-list)))))) 4028 (not (memq buffer1 (memq buffer2 (buffer-list))))))
4004 4029
4005(defun dired--filename-with-newline-p () 4030(defun dired--filename-with-newline-p ()
4006 "Check if a file name in this directory has a newline. 4031 "Check whether a file name in this directory has a newline.
4007Return non-nil if at least one file name in this directory contains 4032Return non-nil if at least one file name in this directory contains a
4008either a literal newline or the string \"\\n\")." 4033newline character (regardless of whether Dired displays the character as
4009 (save-excursion 4034a literal newline or as \"\\n\")."
4010 (goto-char (point-min)) 4035 (directory-files default-directory nil "\n"))
4011 (catch 'found
4012 (while (not (eobp))
4013 (when (dired-move-to-filename)
4014 (let ((fn (buffer-substring-no-properties
4015 (point) (dired-move-to-end-of-filename))))
4016 (when (or (memq 10 (seq-into fn 'list))
4017 (string-search "\\n" fn))
4018 (throw 'found t))))
4019 (forward-line)))))
4020 4036
4021(defun dired--remove-b-switch () 4037(defun dired--remove-b-switch ()
4022 "Remove all variants of the `b' switch from `dired-actual-switches'. 4038 "Remove all variants of the `b' switch from `dired-actual-switches'.
@@ -4094,6 +4110,13 @@ See `%s' for other alternatives and more information."))
4094 (set-window-point (get-buffer-window) 4110 (set-window-point (get-buffer-window)
4095 (search-backward "Warning (dired)"))))) 4111 (search-backward "Warning (dired)")))))
4096 4112
4113(defun dired--display-ls-error ()
4114 "Pop up a buffer displaying the current `ls' error, if any."
4115 (when dired--ls-error-buffer
4116 (let* ((errwin (display-buffer dired--ls-error-buffer)))
4117 (fit-window-to-buffer errwin))
4118 (setq dired--ls-error-buffer nil)))
4119
4097 4120
4098;;; Deleting files 4121;;; Deleting files
4099 4122
diff --git a/lisp/display-fill-column-indicator.el b/lisp/display-fill-column-indicator.el
index 349a470ab41..b661f20e22a 100644
--- a/lisp/display-fill-column-indicator.el
+++ b/lisp/display-fill-column-indicator.el
@@ -102,6 +102,7 @@ See Info node `Displaying Boundaries' for details."
102(defun display-fill-column-indicator--turn-on () 102(defun display-fill-column-indicator--turn-on ()
103 "Turn on `display-fill-column-indicator-mode'." 103 "Turn on `display-fill-column-indicator-mode'."
104 (unless (or (minibufferp) 104 (unless (or (minibufferp)
105 ;; Use `frame-initial-p'?
105 (and (daemonp) (eq (selected-frame) terminal-frame))) 106 (and (daemonp) (eq (selected-frame) terminal-frame)))
106 (display-fill-column-indicator-mode))) 107 (display-fill-column-indicator-mode)))
107 108
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index ce2d8ac47c4..7ed71346451 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -1901,6 +1901,8 @@ See Info node `(elisp) Integer Basics'."
1901 sqlite-available-p sqlitep 1901 sqlite-available-p sqlitep
1902 ;; syntax.c 1902 ;; syntax.c
1903 standard-syntax-table syntax-table syntax-table-p 1903 standard-syntax-table syntax-table syntax-table-p
1904 ;; terminal.c
1905 frame-initial-p
1904 ;; thread.c 1906 ;; thread.c
1905 current-thread 1907 current-thread
1906 ;; timefns.c 1908 ;; timefns.c
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 3019ada1bbd..ec2aa0ad728 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -195,8 +195,7 @@ the debugger will not be entered."
195 ;; backtrace to stdout. This happens for example while 195 ;; backtrace to stdout. This happens for example while
196 ;; handling an error in code from early-init.el with 196 ;; handling an error in code from early-init.el with
197 ;; --debug-init. 197 ;; --debug-init.
198 (and (eq t (framep (selected-frame))) 198 (frame-initial-p)))
199 (equal "initial_terminal" (terminal-name)))))
200 ;; Don't let `inhibit-message' get in our way (especially important if 199 ;; Don't let `inhibit-message' get in our way (especially important if
201 ;; `non-interactive-frame' evaluated to a non-nil value. 200 ;; `non-interactive-frame' evaluated to a non-nil value.
202 (inhibit-message nil) 201 (inhibit-message nil)
diff --git a/lisp/emacs-lisp/shortdoc-doc.el b/lisp/emacs-lisp/shortdoc-doc.el
new file mode 100644
index 00000000000..eb642c1600b
--- /dev/null
+++ b/lisp/emacs-lisp/shortdoc-doc.el
@@ -0,0 +1,1528 @@
1;;; shortdoc-doc.el --- Builtin shortdoc groups -*- lexical-binding: t -*-
2
3;; Copyright (C) 2020-2026 Free Software Foundation, Inc.
4
5;; Keywords: lisp, help
6;; Package: emacs
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software: you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
22
23;;; Commentary:
24
25;; This file defines builtin Emacs shortdoc groups.
26;;
27;; If a shortdoc group describes builtin functions, functions from
28;; subr.el or simple.el or otherwise preloaded files, or functions from
29;; different files, then you should probably define it in this file.
30;; Otherwise, you might as well define the shortdoc group in the file
31;; where the documented functions live, like treesit.el does it.
32
33;;; Code:
34
35(define-short-documentation-group alist
36 "Alist Basics"
37 (assoc
38 :eval (assoc 'foo '((foo . bar) (zot . baz))))
39 (rassoc
40 :eval (rassoc 'bar '((foo . bar) (zot . baz))))
41 (assq
42 :eval (assq 'foo '((foo . bar) (zot . baz))))
43 (rassq
44 :eval (rassq 'bar '((foo . bar) (zot . baz))))
45 (assoc-string
46 :eval (assoc-string "foo" '(("foo" . "bar") ("zot" "baz"))))
47 "Manipulating Alists"
48 (assoc-delete-all
49 :eval (assoc-delete-all "b" (list '("a" . a) '("b" . b) '("b" . c))))
50 (assq-delete-all
51 :eval (assq-delete-all 2 (list '(1 . a) '(2 . b) '(2 . c))))
52 (rassq-delete-all
53 :eval (rassq-delete-all 'b (list '(1 . a) '(2 . b) '(2 . c))))
54 (alist-get
55 :eval (let ((foo '((bar . baz))))
56 (setf (alist-get 'bar foo) 'zot)
57 foo))
58 "Misc"
59 (assoc-default
60 :eval (assoc-default "foobar" '(("foo" . baz)) #'string-match))
61 (copy-alist
62 :eval (let* ((old '((foo . bar)))
63 (new (copy-alist old)))
64 (eq old new)))
65 ;; FIXME: Outputs "\.rose" for the symbol `.rose'. It would be
66 ;; better if that could be cleaned up.
67 (let-alist
68 :eval (let ((colors '((rose . red)
69 (lily . white))))
70 (let-alist colors
71 (if (eq .rose 'red)
72 .lily)))))
73
74(define-short-documentation-group map
75 "Map Basics"
76 (mapp
77 :eval (mapp (list 'bar 1 'foo 2 'baz 3))
78 :eval (mapp (list '(bar . 1) '(foo . 2) '(baz . 3)))
79 :eval (mapp [bar foo baz])
80 :eval (mapp "this is a string")
81 :eval (mapp #s(hash-table data (bar 1 foo 2 baz 3)))
82 :eval (mapp '())
83 :eval (mapp nil)
84 :eval (mapp (make-char-table 'shortdoc-test)))
85 (map-empty-p
86 :args (map)
87 :eval (map-empty-p nil)
88 :eval (map-empty-p [])
89 :eval (map-empty-p '()))
90 (map-elt
91 :args (map key)
92 :eval (map-elt (list 'bar 1 'foo 2 'baz 3) 'foo)
93 :eval (map-elt (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo)
94 :eval (map-elt [bar foo baz] 1)
95 :eval (map-elt #s(hash-table data (bar 1 foo 2 baz 3)) 'foo))
96 (map-contains-key
97 :args (map key)
98 :eval (map-contains-key (list 'bar 1 'foo 2 'baz 3) 'foo)
99 :eval (map-contains-key (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo)
100 :eval (map-contains-key [bar foo baz] 1)
101 :eval (map-contains-key #s(hash-table data (bar 1 foo 2 baz 3)) 'foo))
102 (map-put!
103 :args (map key value)
104 :eval
105"(let ((map (list 'bar 1 'baz 3)))
106 (map-put! map 'foo 2)
107 map)"
108;; This signals map-not-inplace when used in shortdoc.el :-(
109;; :eval
110;; "(let ((map (list '(bar . 1) '(baz . 3))))
111;; (map-put! map 'foo 2)
112;; map)"
113 :eval
114"(let ((map [bar bot baz]))
115 (map-put! map 1 'foo)
116 map)"
117 :eval
118"(let ((map #s(hash-table data (bar 1 baz 3))))
119 (map-put! map 'foo 2)
120 map)")
121 (map-insert
122 :args (map key value)
123 :eval (map-insert (list 'bar 1 'baz 3 'foo 7) 'foo 2)
124 :eval (map-insert (list '(bar . 1) '(baz . 3) '(foo . 7)) 'foo 2)
125 :eval (map-insert [bar bot baz] 1 'foo)
126 :eval (map-insert #s(hash-table data (bar 1 baz 3 foo 7)) 'foo 2))
127 (map-delete
128 :args (map key)
129 :eval (map-delete (list 'bar 1 'foo 2 'baz 3) 'foo)
130 :eval (map-delete (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo)
131 :eval (map-delete [bar foo baz] 1)
132 :eval (map-delete #s(hash-table data (bar 1 foo 2 baz 3)) 'foo))
133 (map-keys
134 :eval (map-keys (list 'bar 1 'foo 2 'baz 3))
135 :eval (map-keys (list '(bar . 1) '(foo . 2) '(baz . 3)))
136 :eval (map-keys [bar foo baz])
137 :eval (map-keys #s(hash-table data (bar 1 foo 2 baz 3))))
138 (map-values
139 :args (map)
140 :eval (map-values (list 'bar 1 'foo 2 'baz 3))
141 :eval (map-values (list '(bar . 1) '(foo . 2) '(baz . 3)))
142 :eval (map-values [bar foo baz])
143 :eval (map-values #s(hash-table data (bar 1 foo 2 baz 3))))
144 (map-pairs
145 :eval (map-pairs (list 'bar 1 'foo 2 'baz 3))
146 :eval (map-pairs (list '(bar . 1) '(foo . 2) '(baz . 3)))
147 :eval (map-pairs [bar foo baz])
148 :eval (map-pairs #s(hash-table data (bar 1 foo 2 baz 3))))
149 (map-length
150 :args (map)
151 :eval (map-length (list 'bar 1 'foo 2 'baz 3))
152 :eval (map-length (list '(bar . 1) '(foo . 2) '(baz . 3)))
153 :eval (map-length [bar foo baz])
154 :eval (map-length #s(hash-table data (bar 1 foo 2 baz 3))))
155 (map-copy
156 :args (map)
157 :eval (map-copy (list 'bar 1 'foo 2 'baz 3))
158 :eval (map-copy (list '(bar . 1) '(foo . 2) '(baz . 3)))
159 :eval (map-copy [bar foo baz])
160 :eval (map-copy #s(hash-table data (bar 1 foo 2 baz 3))))
161 "Doing things to maps and their contents"
162 (map-apply
163 :args (function map)
164 :eval (map-apply #'+ (list '(1 . 2) '(3 . 4))))
165 (map-do
166 :args (function map)
167 :eval
168"(let ((map (list '(1 . 1) '(2 . 3)))
169 acc)
170 (map-do (lambda (k v) (push (+ k v) acc)) map)
171 (nreverse acc))")
172 (map-keys-apply
173 :eval (map-keys-apply #'1+ (list '(1 . 2) '(3 . 4))))
174 (map-values-apply
175 :args (function map)
176 :eval (map-values-apply #'1+ (list '(1 . 2) '(3 . 4))))
177 (map-filter
178 :eval (map-filter (lambda (k _) (oddp k)) (list '(1 . 2) '(4 . 6)))
179 :eval (map-filter (lambda (k v) (evenp (+ k v))) (list '(1 . 2) '(4 . 6))))
180 (map-remove
181 :eval (map-remove (lambda (k _) (oddp k)) (list '(1 . 2) '(4 . 6)))
182 :eval (map-remove (lambda (k v) (evenp (+ k v))) (list '(1 . 2) '(4 . 6))))
183 (map-some
184 :eval (map-some (lambda (k _) (oddp k)) (list '(1 . 2) '(4 . 6)))
185 :eval (map-some (lambda (k v) (evenp (+ k v))) (list '(1 . 2) '(4 . 6))))
186 (map-every-p
187 :eval (map-every-p (lambda (k _) (oddp k)) (list '(1 . 2) '(4 . 6)))
188 :eval (map-every-p (lambda (k v) (evenp (+ k v))) (list '(1 . 3) '(4 . 6))))
189 "Combining and changing maps"
190 (map-merge
191 :eval (map-merge 'alist '(1 2 3 4) #s(hash-table data (5 6 7 8)))
192 :eval (map-merge 'list '(1 2 3 4) #s(hash-table data (5 6 7 8)))
193 :eval (map-merge 'plist '(1 2 3 4) #s(hash-table data (5 6 7 8)))
194 :eval (map-merge 'hash-table '(1 2 3 4) #s(hash-table data (5 6 7 8))))
195 (map-merge-with
196 :eval (map-merge-with 'alist #'max '(1 2 3 4) #s(hash-table data (1 1 3 5)))
197 :eval (map-merge-with 'alist #'min '(1 2 3 4) #s(hash-table data (1 1 3 5)))
198 :eval (map-merge-with 'hash-table #'min '(1 2 3 4) #s(hash-table data (1 1 3 5))))
199 (map-into
200 :args (map type)
201 :eval (map-into #s(hash-table data '(5 6 7 8)) 'list)
202 :eval (map-into '((5 . 6) (7 . 8)) 'plist)
203 :eval (map-into '((5 . 6) (7 . 8)) 'hash-table)))
204
205(define-short-documentation-group string
206 "Making Strings"
207 (make-string
208 :args (length init)
209 :eval "(make-string 5 ?x)")
210 (string
211 :eval "(string ?a ?b ?c)")
212 (concat
213 :eval (concat "foo" "bar" "zot"))
214 (string-join
215 :no-manual t
216 :eval (string-join '("foo" "bar" "zot") " "))
217 (mapconcat
218 :eval (mapconcat (lambda (a) (concat "[" a "]"))
219 '("foo" "bar" "zot") " "))
220 (string-pad
221 :eval (string-pad "foo" 5)
222 :eval (string-pad "foobar" 5)
223 :eval (string-pad "foo" 5 ?- t))
224 (mapcar
225 :eval (mapcar #'identity "123"))
226 (format
227 :eval (format "This number is %d" 4))
228 "Manipulating Strings"
229 (substring
230 :eval (substring "abcde" 1 3)
231 :eval (substring "abcde" 2)
232 :eval (substring "abcde" 1 -1)
233 :eval (substring "abcde" -4 4))
234 (string-limit
235 :eval (string-limit "foobar" 3)
236 :eval (string-limit "foobar" 3 t)
237 :eval (string-limit "foobar" 10)
238 :eval (string-limit "fo好" 3 nil 'utf-8))
239 (truncate-string-to-width
240 :eval (truncate-string-to-width "foobar" 3)
241 :eval (truncate-string-to-width "你好bar" 5))
242 (split-string
243 :eval (split-string "foo bar")
244 :eval (split-string "|foo|bar|" "|")
245 :eval (split-string "|foo|bar|" "|" t))
246 (split-string-and-unquote
247 :eval (split-string-and-unquote "foo \"bar zot\""))
248 (split-string-shell-command
249 :eval (split-string-shell-command "ls /tmp/'foo bar'"))
250 (string-lines
251 :eval (string-lines "foo\n\nbar")
252 :eval (string-lines "foo\n\nbar" t))
253 (string-replace
254 :eval (string-replace "foo" "bar" "foozot"))
255 (replace-regexp-in-string
256 :eval (replace-regexp-in-string "[a-z]+" "_" "*foo*"))
257 (string-trim
258 :args (string)
259 :doc "Trim STRING of leading and trailing white space."
260 :eval (string-trim " foo "))
261 (string-trim-left
262 :eval (string-trim-left "oofoo" "o+"))
263 (string-trim-right
264 :eval (string-trim-right "barkss" "s+"))
265 (string-truncate-left
266 :no-manual t
267 :eval (string-truncate-left "longstring" 8))
268 (string-remove-suffix
269 :no-manual t
270 :eval (string-remove-suffix "bar" "foobar"))
271 (string-remove-prefix
272 :no-manual t
273 :eval (string-remove-prefix "foo" "foobar"))
274 (string-chop-newline
275 :eval (string-chop-newline "foo\n"))
276 (string-clean-whitespace
277 :eval (string-clean-whitespace " foo bar "))
278 (string-fill
279 :eval (string-fill "Three short words" 12)
280 :eval (string-fill "Long-word" 3))
281 (reverse
282 :eval (reverse "foo"))
283 (substring-no-properties
284 :eval (substring-no-properties (propertize "foobar" 'face 'bold) 0 3))
285 (try-completion
286 :eval (try-completion "foo" '("foobar" "foozot" "gazonk")))
287 "Unicode Strings"
288 (string-glyph-split
289 :eval (string-glyph-split "Hello, 👼🏻🧑🏼‍🤝‍🧑🏻"))
290 (string-glyph-compose
291 :eval (string-glyph-compose "Å"))
292 (string-glyph-decompose
293 :eval (string-glyph-decompose "Å"))
294 "Predicates for Strings"
295 (string-equal
296 :eval (string-equal "abc" "abc")
297 :eval (string-equal "abc" "ABC"))
298 (string-equal-ignore-case
299 :eval (string-equal-ignore-case "foo" "FOO"))
300 (equal
301 :eval (equal "foo" "foo"))
302 (cl-equalp
303 :eval (cl-equalp "Foo" "foo"))
304 (stringp
305 :eval (stringp "a")
306 :eval (stringp 'a)
307 :eval "(stringp ?a)")
308 (string-or-null-p
309 :eval (string-or-null-p "a")
310 :eval (string-or-null-p nil))
311 (char-or-string-p
312 :eval "(char-or-string-p ?a)"
313 :eval (char-or-string-p "a"))
314 (string-empty-p
315 :no-manual t
316 :eval (string-empty-p ""))
317 (string-blank-p
318 :no-manual t
319 :eval (string-blank-p " \n"))
320 (string-lessp
321 :eval (string-lessp "abc" "def")
322 :eval (string-lessp "pic4.png" "pic32.png")
323 :eval (string-lessp "1.1" "1.2"))
324 (string-greaterp
325 :eval (string-greaterp "foo" "bar"))
326 (string-version-lessp
327 :eval (string-version-lessp "pic4.png" "pic32.png")
328 :eval (string-version-lessp "1.9.3" "1.10.2"))
329 (string-collate-lessp
330 :eval (string-collate-lessp "abc" "abd"))
331 (string-prefix-p
332 :eval (string-prefix-p "foo" "foobar"))
333 (string-suffix-p
334 :eval (string-suffix-p "bar" "foobar"))
335 "Case Manipulation"
336 (upcase
337 :eval (upcase "foo"))
338 (downcase
339 :eval (downcase "FOObar"))
340 (capitalize
341 :eval (capitalize "foo bar zot"))
342 (upcase-initials
343 :eval (upcase-initials "The CAT in the hAt"))
344 "Converting Strings"
345 (string-to-number
346 :eval (string-to-number "42")
347 :eval (string-to-number "deadbeef" 16)
348 :eval (string-to-number "2.5e+03"))
349 (number-to-string
350 :eval (number-to-string 42))
351 (char-uppercase-p
352 :eval "(char-uppercase-p ?A)"
353 :eval "(char-uppercase-p ?a)")
354 "Data About Strings"
355 (length
356 :eval (length "foo")
357 :eval (length "avocado: 🥑"))
358 (string-width
359 :eval (string-width "foo")
360 :eval (string-width "avocado: 🥑"))
361 (string-pixel-width
362 :eval (string-pixel-width "foo")
363 :eval (string-pixel-width "avocado: 🥑"))
364 (string-search
365 :eval (string-search "bar" "foobarzot"))
366 (assoc-string
367 :eval (assoc-string "foo" '(("a" 1) (foo 2))))
368 (seq-position
369 :eval "(seq-position \"foobarzot\" ?z)"))
370
371(define-short-documentation-group file-name
372 "File Name Manipulation"
373 (file-name-directory
374 :eval (file-name-directory "/tmp/foo")
375 :eval (file-name-directory "/tmp/foo/"))
376 (file-name-nondirectory
377 :eval (file-name-nondirectory "/tmp/foo")
378 :eval (file-name-nondirectory "/tmp/foo/"))
379 (file-name-sans-versions
380 :args (filename)
381 :eval (file-name-sans-versions "/tmp/foo~"))
382 (file-name-extension
383 :eval (file-name-extension "/tmp/foo.txt"))
384 (file-name-sans-extension
385 :eval (file-name-sans-extension "/tmp/foo.txt"))
386 (file-name-with-extension
387 :eval (file-name-with-extension "foo.txt" "bin")
388 :eval (file-name-with-extension "foo" "bin"))
389 (file-name-base
390 :eval (file-name-base "/tmp/foo.txt"))
391 (file-relative-name
392 :eval (file-relative-name "/tmp/foo" "/tmp"))
393 (file-name-split
394 :eval (file-name-split "/tmp/foo")
395 :eval (file-name-split "foo/bar"))
396 (make-temp-name
397 :eval (make-temp-name "/tmp/foo-"))
398 (file-name-concat
399 :eval (file-name-concat "/tmp/" "foo")
400 :eval (file-name-concat "/tmp" "foo")
401 :eval (file-name-concat "/tmp" "foo" "bar/" "zot")
402 :eval (file-name-concat "/tmp" "~"))
403 (expand-file-name
404 :eval (expand-file-name "foo" "/tmp/")
405 :eval (expand-file-name "foo" "/tmp///")
406 :eval (expand-file-name "foo" "/tmp/foo/.././")
407 :eval (expand-file-name "~" "/tmp/"))
408 (substitute-in-file-name
409 :eval (substitute-in-file-name "$HOME/foo"))
410 "Directory Functions"
411 (file-name-as-directory
412 :eval (file-name-as-directory "/tmp/foo"))
413 (directory-file-name
414 :eval (directory-file-name "/tmp/foo/"))
415 (abbreviate-file-name
416 :no-eval (abbreviate-file-name "/home/some-user")
417 :eg-result "~some-user")
418 (file-name-parent-directory
419 :eval (file-name-parent-directory "/foo/bar")
420 :eval (file-name-parent-directory "/foo/")
421 :eval (file-name-parent-directory "foo/bar")
422 :eval (file-name-parent-directory "foo"))
423 "Quoted File Names"
424 (file-name-quote
425 :args (name)
426 :eval (file-name-quote "/tmp/foo"))
427 (file-name-unquote
428 :args (name)
429 :eval (file-name-unquote "/:/tmp/foo"))
430 "Predicates"
431 (file-name-absolute-p
432 :eval (file-name-absolute-p "/tmp/foo")
433 :eval (file-name-absolute-p "foo"))
434 (directory-name-p
435 :eval (directory-name-p "/tmp/foo/"))
436 (file-name-quoted-p
437 :eval (file-name-quoted-p "/:/tmp/foo")))
438
439(define-short-documentation-group file
440 "Inserting Contents"
441 (insert-file-contents
442 :no-eval (insert-file-contents "/tmp/foo")
443 :eg-result ("/tmp/foo" 6))
444 (insert-file-contents-literally
445 :no-eval (insert-file-contents-literally "/tmp/foo")
446 :eg-result ("/tmp/foo" 6))
447 (find-file
448 :no-eval (find-file "/tmp/foo")
449 :eg-result-string "#<buffer foo>")
450 "Predicates"
451 (file-symlink-p
452 :no-eval (file-symlink-p "/tmp/foo")
453 :eg-result t)
454 (file-directory-p
455 :no-eval (file-directory-p "/tmp")
456 :eg-result t)
457 (file-regular-p
458 :no-eval (file-regular-p "/tmp/foo")
459 :eg-result t)
460 (file-exists-p
461 :no-eval (file-exists-p "/tmp/foo")
462 :eg-result t)
463 (file-readable-p
464 :no-eval (file-readable-p "/tmp/foo")
465 :eg-result t)
466 (file-writable-p
467 :no-eval (file-writable-p "/tmp/foo")
468 :eg-result t)
469 (file-accessible-directory-p
470 :no-eval (file-accessible-directory-p "/tmp")
471 :eg-result t)
472 (file-executable-p
473 :no-eval (file-executable-p "/bin/cat")
474 :eg-result t)
475 (file-newer-than-file-p
476 :no-eval (file-newer-than-file-p "/tmp/foo" "/tmp/bar")
477 :eg-result nil)
478 (file-has-changed-p
479 :no-eval (file-has-changed-p "/tmp/foo")
480 :eg-result t)
481 (file-equal-p
482 :no-eval (file-equal-p "/tmp/foo" "/tmp/bar")
483 :eg-result nil)
484 (file-in-directory-p
485 :no-eval (file-in-directory-p "/tmp/foo" "/tmp/")
486 :eg-result t)
487 (file-locked-p
488 :no-eval (file-locked-p "/tmp/foo")
489 :eg-result nil)
490 "Information"
491 (file-attributes
492 :no-eval* (file-attributes "/tmp"))
493 (file-truename
494 :no-eval (file-truename "/tmp/foo/bar")
495 :eg-result "/tmp/foo/zot")
496 (file-chase-links
497 :no-eval (file-chase-links "/tmp/foo/bar")
498 :eg-result "/tmp/foo/zot")
499 (vc-responsible-backend
500 :args (file &optional no-error)
501 :no-eval (vc-responsible-backend "/src/foo/bar.c")
502 :eg-result Git)
503 (file-acl
504 :no-eval (file-acl "/tmp/foo")
505 :eg-result "user::rw-\ngroup::r--\nother::r--\n")
506 (file-extended-attributes
507 :no-eval* (file-extended-attributes "/tmp/foo"))
508 (file-selinux-context
509 :no-eval* (file-selinux-context "/tmp/foo"))
510 (locate-file
511 :no-eval (locate-file "syslog" '("/var/log" "/usr/bin"))
512 :eg-result "/var/log/syslog")
513 (executable-find
514 :no-eval (executable-find "ls")
515 :eg-result "/usr/bin/ls")
516 "Creating"
517 (make-temp-file
518 :no-eval (make-temp-file "/tmp/foo-")
519 :eg-result "/tmp/foo-ZcXFMj")
520 (make-nearby-temp-file
521 :no-eval (make-nearby-temp-file "/tmp/foo-")
522 :eg-result "/tmp/foo-xe8iON")
523 (write-region
524 :no-value (write-region (point-min) (point-max) "/tmp/foo"))
525 "Directories"
526 (make-directory
527 :no-value (make-directory "/tmp/bar/zot/" t))
528 (directory-files
529 :no-eval (directory-files "/tmp/")
530 :eg-result ("." ".." ".ICE-unix" ".Test-unix"))
531 (directory-files-recursively
532 :no-eval (directory-files-recursively "/tmp/" "\\.png\\'")
533 :eg-result ("/tmp/foo.png" "/tmp/zot.png" "/tmp/bar/foobar.png"))
534 (directory-files-and-attributes
535 :no-eval* (directory-files-and-attributes "/tmp/foo"))
536 (file-expand-wildcards
537 :no-eval (file-expand-wildcards "/tmp/*.png")
538 :eg-result ("/tmp/foo.png" "/tmp/zot.png")
539 :no-eval (file-expand-wildcards "/*/foo.png")
540 :eg-result ("/tmp/foo.png" "/var/foo.png"))
541 (locate-dominating-file
542 :no-eval (locate-dominating-file "foo.png" "/tmp/foo/bar/zot")
543 :eg-result "/tmp/foo.png")
544 (copy-directory
545 :no-value (copy-directory "/tmp/bar/" "/tmp/barcopy"))
546 (delete-directory
547 :no-value (delete-directory "/tmp/bar/"))
548 "File Operations"
549 (rename-file
550 :no-value (rename-file "/tmp/foo" "/tmp/newname"))
551 (copy-file
552 :no-value (copy-file "/tmp/foo" "/tmp/foocopy"))
553 (delete-file
554 :no-value (delete-file "/tmp/foo"))
555 (make-empty-file
556 :no-value (make-empty-file "/tmp/foo"))
557 (make-symbolic-link
558 :no-value (make-symbolic-link "/tmp/foo" "/tmp/foosymlink"))
559 (add-name-to-file
560 :no-value (add-name-to-file "/tmp/foo" "/tmp/bar"))
561 (set-file-modes
562 :no-value "(set-file-modes \"/tmp/foo\" #o644)")
563 (set-file-times
564 :no-value (set-file-times "/tmp/foo"))
565 "File Modes"
566 (set-default-file-modes
567 :no-value "(set-default-file-modes #o755)")
568 (default-file-modes
569 :no-eval (default-file-modes)
570 :eg-result-string "#o755")
571 (file-modes-symbolic-to-number
572 :no-eval (file-modes-symbolic-to-number "a+r")
573 :eg-result-string "#o444")
574 (file-modes-number-to-symbolic
575 :eval "(file-modes-number-to-symbolic #o444)")
576 (set-file-extended-attributes
577 :no-eval (set-file-extended-attributes
578 "/tmp/foo" '((acl . "group::rxx")))
579 :eg-result t)
580 (set-file-selinux-context
581 :no-eval (set-file-selinux-context
582 "/tmp/foo" '(unconfined_u object_r user_home_t s0))
583 :eg-result t)
584 (set-file-acl
585 :no-eval (set-file-acl "/tmp/foo" "group::rxx")
586 :eg-result t))
587
588(define-short-documentation-group hash-table
589 "Hash Table Basics"
590 (make-hash-table
591 :no-eval (make-hash-table)
592 :result-string "#s(hash-table ...)")
593 (puthash
594 :no-eval (puthash 'key "value" table))
595 (gethash
596 :no-eval (gethash 'key table)
597 :eg-result "value")
598 (remhash
599 :no-eval (remhash 'key table)
600 :result nil)
601 (clrhash
602 :no-eval (clrhash table)
603 :result-string "#s(hash-table ...)")
604 (maphash
605 :no-eval (maphash (lambda (key value) (message value)) table)
606 :result nil)
607 "Other Hash Table Functions"
608 (hash-table-p
609 :eval (hash-table-p 123))
610 (hash-table-contains-p
611 :no-eval (hash-table-contains-p 'key table))
612 (copy-hash-table
613 :no-eval (copy-hash-table table)
614 :result-string "#s(hash-table ...)")
615 (hash-table-count
616 :no-eval (hash-table-count table)
617 :eg-result 15))
618
619(define-short-documentation-group list
620 "Making Lists"
621 (make-list
622 :eval (make-list 5 'a))
623 (cons
624 :eval (cons 1 '(2 3 4)))
625 (list
626 :eval (list 1 2 3))
627 (number-sequence
628 :eval (number-sequence 5 8))
629 (ensure-list
630 :eval (ensure-list "foo")
631 :eval (ensure-list '(1 2 3))
632 :eval (ensure-list '(1 . 2)))
633 (ensure-proper-list
634 :eval (ensure-proper-list "foo")
635 :eval (ensure-proper-list '(1 2 3))
636 :eval (ensure-proper-list '(1 . 2)))
637 "Operations on Lists"
638 (append
639 :eval (append '("foo" "bar") '("zot")))
640 (copy-tree
641 :eval (copy-tree '(1 (2 3) 4)))
642 (flatten-tree
643 :eval (flatten-tree '(1 (2 3) 4)))
644 (car
645 :eval (car '(one two three))
646 :eval (car '(one . two))
647 :eval (car nil))
648 (cdr
649 :eval (cdr '(one two three))
650 :eval (cdr '(one . two))
651 :eval (cdr nil))
652 (last
653 :eval (last '(one two three)))
654 (butlast
655 :eval (butlast '(one two three)))
656 (nbutlast
657 :eval (nbutlast (list 'one 'two 'three)))
658 (nth
659 :eval (nth 1 '(one two three)))
660 (nthcdr
661 :eval (nthcdr 1 '(one two three)))
662 (take
663 :eval (take 3 '(one two three four)))
664 (ntake
665 :eval (ntake 3 (list 'one 'two 'three 'four)))
666 (take-while
667 :eval (take-while #'numberp '(1 2 three 4 five)))
668 (drop-while
669 :eval (drop-while #'numberp '(1 2 three 4 five)))
670 (any
671 :eval (any #'symbolp '(1 2 three 4 five)))
672 (all
673 :eval (all #'symbolp '(one 2 three))
674 :eval (all #'symbolp '(one two three)))
675 (elt
676 :eval (elt '(one two three) 1))
677 (car-safe
678 :eval (car-safe '(one two three)))
679 (cdr-safe
680 :eval (cdr-safe '(one two three)))
681 (push
682 :no-eval* (push 'a list))
683 (pop
684 :no-eval* (pop list))
685 (setcar
686 :no-eval (setcar list 'c)
687 :result c)
688 (setcdr
689 :no-eval (setcdr list (list c))
690 :result '(c))
691 (nconc
692 :eval (nconc (list 1) (list 2 3 4)))
693 (delq
694 :eval (delq 'a (list 'a 'b 'c 'd)))
695 (delete
696 :eval (delete 2 (list 1 2 3 4))
697 :eval (delete "a" (list "a" "b" "c" "d")))
698 (remq
699 :eval (remq 'b '(a b c)))
700 (remove
701 :eval (remove 2 '(1 2 3 4))
702 :eval (remove "a" '("a" "b" "c" "d")))
703 (delete-dups
704 :eval (delete-dups (list 1 2 4 3 2 4)))
705 "Mapping Over Lists"
706 (mapcar
707 :eval (mapcar #'list '(1 2 3)))
708 (mapcan
709 :eval (mapcan #'list '(1 2 3)))
710 (mapc
711 :eval (mapc #'insert '("1" "2" "3")))
712 (seq-reduce
713 :eval (seq-reduce #'+ '(1 2 3) 0))
714 (mapconcat
715 :eval (mapconcat #'identity '("foo" "bar") "|"))
716 "Predicates"
717 (listp
718 :eval (listp '(1 2 3))
719 :eval (listp nil)
720 :eval (listp '(1 . 2)))
721 (consp
722 :eval (consp '(1 2 3))
723 :eval (consp nil))
724 (proper-list-p
725 :eval (proper-list-p '(1 2 3))
726 :eval (proper-list-p nil)
727 :eval (proper-list-p '(1 . 2)))
728 (null
729 :eval (null nil))
730 (atom
731 :eval (atom 'a))
732 (nlistp
733 :eval (nlistp '(1 2 3))
734 :eval (nlistp t)
735 :eval (nlistp '(1 . 2)))
736 "Finding Elements"
737 (memq
738 :eval (memq 'b '(a b c)))
739 (memql
740 :eval (memql 2.0 '(1.0 2.0 3.0)))
741 (member
742 :eval (member 2 '(1 2 3))
743 :eval (member "b" '("a" "b" "c")))
744 (member-ignore-case
745 :eval (member-ignore-case "foo" '("bar" "Foo" "zot")))
746 "Association Lists"
747 (assoc
748 :eval (assoc "b" '(("a" . 1) ("b" . 2))))
749 (rassoc
750 :eval (rassoc "b" '((1 . "a") (2 . "b"))))
751 (assq
752 :eval (assq 'b '((a . 1) (b . 2))))
753 (rassq
754 :eval (rassq 'b '((1 . a) (2 . b))))
755 (assoc-string
756 :eval (assoc-string "foo" '(("a" 1) (foo 2))))
757 (alist-get
758 :eval (alist-get 2 '((1 . a) (2 . b))))
759 (assoc-default
760 :eval (assoc-default 2 '((1 . a) (2 . b) #'=)))
761 (copy-alist
762 :eval (copy-alist '((1 . a) (2 . b))))
763 (assoc-delete-all
764 :eval (assoc-delete-all "b" (list '("a" . a) '("b" . b) '("b" . c))))
765 (assq-delete-all
766 :eval (assq-delete-all 2 (list '(1 . a) '(2 . b) '(2 . c))))
767 (rassq-delete-all
768 :eval (rassq-delete-all 'b (list '(1 . a) '(2 . b) '(2 . c))))
769 "Property Lists"
770 (plist-get
771 :eval (plist-get '(a 1 b 2 c 3) 'b))
772 (plist-put
773 :no-eval (setq plist (plist-put plist 'd 4))
774 :eg-result (a 1 b 2 c 3 d 4))
775 (plist-member
776 :eval (plist-member '(a 1 b 2 c 3) 'b))
777 "Data About Lists"
778 (length
779 :eval (length '(a b c)))
780 (length<
781 :eval (length< '(a b c) 1))
782 (length>
783 :eval (length> '(a b c) 1))
784 (length=
785 :eval (length= '(a b c) 3))
786 (safe-length
787 :eval (safe-length '(a b c))))
788
789(define-short-documentation-group symbol
790 "Making symbols"
791 (intern
792 :eval (intern "abc"))
793 (intern-soft
794 :eval (intern-soft "list")
795 :eval (intern-soft "Phooey!"))
796 (make-symbol
797 :eval (make-symbol "abc"))
798 (gensym
799 :no-eval (gensym)
800 :eg-result g37)
801 "Comparing symbols"
802 (eq
803 :eval (eq 'abc 'abc)
804 :eval (eq 'abc 'abd))
805 (eql
806 :eval (eql 'abc 'abc))
807 (equal
808 :eval (equal 'abc 'abc))
809 "Name"
810 (symbol-name
811 :eval (symbol-name 'abc))
812 "Obarrays"
813 (obarray-make
814 :eval (obarray-make))
815 (obarrayp
816 :eval (obarrayp (obarray-make))
817 :eval (obarrayp nil))
818 (unintern
819 :no-eval (unintern "abc" my-obarray)
820 :eg-result t)
821 (mapatoms
822 :no-eval (mapatoms (lambda (symbol) (print symbol)) my-obarray))
823 (obarray-clear
824 :no-eval (obarray-clear my-obarray)))
825
826(define-short-documentation-group comparison
827 "General-purpose"
828 (eq
829 :eval (eq 'a 'a)
830 :eval "(eq ?A ?A)"
831 :eval (let ((x (list 'a "b" '(c) 4 5.0)))
832 (eq x x)))
833 (eql
834 :eval (eql 2 2)
835 :eval (eql 2.0 2.0)
836 :eval (eql 2.0 2))
837 (equal
838 :eval (equal "abc" "abc")
839 :eval (equal 2.0 2.0)
840 :eval (equal 2.0 2)
841 :eval (equal '(a "b" (c) 4.0) '(a "b" (c) 4.0)))
842 (cl-equalp
843 :eval (cl-equalp 2 2.0)
844 :eval (cl-equalp "ABC" "abc"))
845 "Numeric"
846 (=
847 :args (number &rest numbers)
848 :eval (= 2 2)
849 :eval (= 2.0 2.0)
850 :eval (= 2.0 2)
851 :eval (= 4 4 4 4))
852 (/=
853 :eval (/= 4 4))
854 (<
855 :args (number &rest numbers)
856 :eval (< 4 4)
857 :eval (< 1 2 3))
858 (<=
859 :args (number &rest numbers)
860 :eval (<= 4 4)
861 :eval (<= 1 2 2 3))
862 (>
863 :args (number &rest numbers)
864 :eval (> 4 4)
865 :eval (> 3 2 1))
866 (>=
867 :args (number &rest numbers)
868 :eval (>= 4 4)
869 :eval (>= 3 2 2 1))
870 "String"
871 (string-equal
872 :eval (string-equal "abc" "abc")
873 :eval (string-equal "abc" "ABC"))
874 (string-equal-ignore-case
875 :eval (string-equal-ignore-case "abc" "ABC"))
876 (string-lessp
877 :eval (string-lessp "abc" "abd")
878 :eval (string-lessp "abc" "abc")
879 :eval (string-lessp "pic4.png" "pic32.png"))
880 (string-greaterp
881 :eval (string-greaterp "abd" "abc")
882 :eval (string-greaterp "abc" "abc"))
883 (string-version-lessp
884 :eval (string-version-lessp "pic4.png" "pic32.png")
885 :eval (string-version-lessp "1.9.3" "1.10.2"))
886 (string-collate-lessp
887 :eval (string-collate-lessp "abc" "abd")))
888
889(define-short-documentation-group vector
890 "Making Vectors"
891 (make-vector
892 :eval (make-vector 5 "foo"))
893 (vector
894 :eval (vector 1 "b" 3))
895 "Operations on Vectors"
896 (vectorp
897 :eval (vectorp [1])
898 :eval (vectorp "1"))
899 (vconcat
900 :eval (vconcat '(1 2) [3 4]))
901 (append
902 :eval (append [1 2] nil))
903 (length
904 :eval (length [1 2 3]))
905 (seq-reduce
906 :eval (seq-reduce #'+ [1 2 3] 0))
907 (seq-subseq
908 :eval (seq-subseq [1 2 3 4 5] 1 3)
909 :eval (seq-subseq [1 2 3 4 5] 1))
910 (copy-tree
911 :eval (copy-tree [1 (2 3) [4 5]] t))
912 "Mapping Over Vectors"
913 (mapcar
914 :eval (mapcar #'identity [1 2 3]))
915 (mapc
916 :eval (mapc #'insert ["1" "2" "3"])))
917
918(define-short-documentation-group regexp
919 "Matching Strings"
920 (replace-regexp-in-string
921 :eval (replace-regexp-in-string "[a-z]+" "_" "*foo*"))
922 (string-match-p
923 :eval (string-match-p "^[fo]+" "foobar"))
924 "Looking in Buffers"
925 (re-search-forward
926 :no-eval (re-search-forward "^foo$" nil t)
927 :eg-result 43)
928 (re-search-backward
929 :no-eval (re-search-backward "^foo$" nil t)
930 :eg-result 43)
931 (looking-at-p
932 :no-eval (looking-at-p "f[0-9]")
933 :eg-result t)
934 "Match Data"
935 (match-string
936 :eval (and (string-match "^\\([fo]+\\)b" "foobar")
937 (match-string 0 "foobar")))
938 (match-beginning
939 :no-eval (match-beginning 1)
940 :eg-result 0)
941 (match-end
942 :no-eval (match-end 1)
943 :eg-result 3)
944 (save-match-data
945 :no-eval (save-match-data ...))
946 "Replacing Match"
947 (replace-match
948 :no-eval (replace-match "new")
949 :eg-result nil)
950 (match-substitute-replacement
951 :no-eval (match-substitute-replacement "new")
952 :eg-result "new")
953 (replace-regexp-in-region
954 :no-value (replace-regexp-in-region "[0-9]+" "Num \\&"))
955 "Utilities"
956 (regexp-quote
957 :eval (regexp-quote "foo.*bar"))
958 (regexp-opt
959 :eval (regexp-opt '("foo" "bar")))
960 (regexp-opt-depth
961 :eval (regexp-opt-depth "\\(a\\(b\\)\\)"))
962 (regexp-opt-charset
963 :eval (regexp-opt-charset '(?a ?b ?c ?d ?e)))
964 "The `rx' Structured Regexp Notation"
965 (rx
966 :eval (rx "IP=" (+ digit) (= 3 "." (+ digit))))
967 (rx-to-string
968 :eval (rx-to-string '(| "foo" "bar")))
969 (rx-define
970 :no-eval "(and (rx-define haskell-comment (seq \"--\" (zero-or-more nonl)))
971 (rx haskell-comment))"
972 :result "--.*")
973 (rx-let
974 :eval "(rx-let ((comma-separated (item) (seq item (0+ \",\" item)))
975 (number (1+ digit))
976 (numbers (comma-separated number)))
977 (rx \"(\" numbers \")\"))"
978 :result "([[:digit:]]+\\(?:,[[:digit:]]+\\)*)")
979 (rx-let-eval
980 :eval "(rx-let-eval
981 '((ponder (x) (seq \"Where have all the \" x \" gone?\")))
982 (rx-to-string
983 '(ponder (or \"flowers\" \"cars\" \"socks\"))))"
984 :result "\\(?:Where have all the \\(?:\\(?:car\\|flower\\|sock\\)s\\) gone\\?\\)"))
985
986(define-short-documentation-group sequence
987 "Sequence Predicates"
988 (seq-contains-p
989 :eval (seq-contains-p '(a b c) 'b)
990 :eval (seq-contains-p '(a b c) 'd))
991 (seq-every-p
992 :eval (seq-every-p #'numberp '(1 2 3)))
993 (seq-empty-p
994 :eval (seq-empty-p []))
995 (seq-set-equal-p
996 :eval (seq-set-equal-p '(1 2 3) '(3 1 2)))
997 (seq-some
998 :eval (seq-some #'floatp '(1 2.0 3)))
999 "Building Sequences"
1000 (seq-concatenate
1001 :eval (seq-concatenate 'vector '(1 2) '(c d)))
1002 (seq-copy
1003 :eval (seq-copy '(a 2)))
1004 (seq-into
1005 :eval (seq-into '(1 2 3) 'vector))
1006 "Utility Functions"
1007 (seq-count
1008 :eval (seq-count #'numberp '(1 b c 4)))
1009 (seq-elt
1010 :eval (seq-elt '(a b c) 1))
1011 (seq-random-elt
1012 :no-eval (seq-random-elt '(a b c))
1013 :eg-result c)
1014 (seq-find
1015 :eval (seq-find #'numberp '(a b 3 4 f 6)))
1016 (seq-position
1017 :eval (seq-position '(a b c) 'c))
1018 (seq-positions
1019 :eval (seq-positions '(a b c a d) 'a)
1020 :eval (seq-positions '(a b c a d) 'z)
1021 :eval (seq-positions '(11 5 7 12 9 15) 10 #'>=))
1022 (seq-length
1023 :eval (seq-length "abcde"))
1024 (seq-max
1025 :eval (seq-max [1 2 3]))
1026 (seq-min
1027 :eval (seq-min [1 2 3]))
1028 (seq-first
1029 :eval (seq-first [a b c]))
1030 (seq-rest
1031 :eval (seq-rest '[1 2 3]))
1032 (seq-reverse
1033 :eval (seq-reverse '(1 2 3)))
1034 (seq-sort
1035 :eval (seq-sort #'> '(1 2 3)))
1036 (seq-sort-by
1037 :eval (seq-sort-by (lambda (a) (/ 1.0 a)) #'< '(1 2 3)))
1038 "Mapping Over Sequences"
1039 (seq-map
1040 :eval (seq-map #'1+ '(1 2 3)))
1041 (seq-map-indexed
1042 :eval (seq-map-indexed (lambda (a i) (cons i a)) '(a b c)))
1043 (seq-mapcat
1044 :eval (seq-mapcat #'upcase '("a" "b" "c") 'string))
1045 (seq-doseq
1046 :no-eval (seq-doseq (a '("foo" "bar")) (insert a))
1047 :eg-result ("foo" "bar"))
1048 (seq-do
1049 :no-eval (seq-do (lambda (a) (insert a)) '("foo" "bar"))
1050 :eg-result ("foo" "bar"))
1051 (seq-do-indexed
1052 :no-eval (seq-do-indexed
1053 (lambda (a index) (message "%s:%s" index a))
1054 '("foo" "bar"))
1055 :eg-result nil)
1056 (seq-reduce
1057 :eval (seq-reduce #'* [1 2 3] 2))
1058 "Excerpting Sequences"
1059 (seq-drop
1060 :eval (seq-drop '(a b c) 2))
1061 (seq-drop-while
1062 :eval (seq-drop-while #'numberp '(1 2 c d 5)))
1063 (seq-filter
1064 :eval (seq-filter #'numberp '(a b 3 4 f 6)))
1065 (seq-keep
1066 :eval (seq-keep #'car-safe '((1 2) 3 t (a . b))))
1067 (seq-remove
1068 :eval (seq-remove #'numberp '(1 2 c d 5)))
1069 (seq-remove-at-position
1070 :eval (seq-remove-at-position '(a b c d e) 3)
1071 :eval (seq-remove-at-position [a b c d e] 0))
1072 (seq-group-by
1073 :eval (seq-group-by #'natnump '(-1 2 3 -4 -5 6)))
1074 (seq-union
1075 :eval (seq-union '(1 2 3) '(3 5)))
1076 (seq-difference
1077 :eval (seq-difference '(1 2 3) '(2 3 4)))
1078 (seq-intersection
1079 :eval (seq-intersection '(1 2 3) '(2 3 4)))
1080 (seq-partition
1081 :eval (seq-partition '(a b c d e f g h) 3))
1082 (seq-subseq
1083 :eval (seq-subseq '(a b c d e) 2 4))
1084 (seq-take
1085 :eval (seq-take '(a b c d e) 3))
1086 (seq-split
1087 :eval (seq-split [0 1 2 3 5] 2))
1088 (seq-take-while
1089 :eval (seq-take-while #'integerp [1 2 3.0 4]))
1090 (seq-uniq
1091 :eval (seq-uniq '(a b d b a c))))
1092
1093(define-short-documentation-group buffer
1094 "Buffer Basics"
1095 (current-buffer
1096 :no-eval (current-buffer)
1097 :eg-result-string "#<buffer shortdoc.el>")
1098 (bufferp
1099 :eval (bufferp 23))
1100 (buffer-live-p
1101 :no-eval (buffer-live-p some-buffer)
1102 :eg-result t)
1103 (buffer-modified-p
1104 :eval (buffer-modified-p (current-buffer)))
1105 (buffer-name
1106 :eval (buffer-name))
1107 (window-buffer
1108 :eval (window-buffer))
1109 "Selecting Buffers"
1110 (get-buffer-create
1111 :no-eval (get-buffer-create "*foo*")
1112 :eg-result-string "#<buffer *foo*>")
1113 (pop-to-buffer
1114 :no-eval (pop-to-buffer "*foo*")
1115 :eg-result-string "#<buffer *foo*>")
1116 (with-current-buffer
1117 :no-eval* (with-current-buffer buffer (buffer-size)))
1118 "Points and Positions"
1119 (point
1120 :eval (point))
1121 (point-min
1122 :eval (point-min))
1123 (point-max
1124 :eval (point-max))
1125 (pos-bol
1126 :eval (pos-bol))
1127 (pos-eol
1128 :eval (pos-eol))
1129 (bolp
1130 :eval (bolp))
1131 (eolp
1132 :eval (eolp))
1133 (line-beginning-position
1134 :eval (line-beginning-position))
1135 (line-end-position
1136 :eval (line-end-position))
1137 (buffer-size
1138 :eval (buffer-size))
1139 (bobp
1140 :eval (bobp))
1141 (eobp
1142 :eval (eobp))
1143 "Moving Around"
1144 (goto-char
1145 :no-eval (goto-char (point-max))
1146 :eg-result 342)
1147 (search-forward
1148 :no-eval (search-forward "some-string" nil t)
1149 :eg-result 245)
1150 (re-search-forward
1151 :no-eval (re-search-forward "some-s.*g" nil t)
1152 :eg-result 245)
1153 (forward-line
1154 :no-eval (forward-line 1)
1155 :eg-result 0
1156 :no-eval (forward-line -2)
1157 :eg-result 0)
1158 "Strings from Buffers"
1159 (buffer-string
1160 :no-eval* (buffer-string))
1161 (buffer-substring
1162 :eval (buffer-substring (point-min) (+ (point-min) 10)))
1163 (buffer-substring-no-properties
1164 :eval (buffer-substring-no-properties (point-min) (+ (point-min) 10)))
1165 (following-char
1166 :no-eval (following-char)
1167 :eg-result 67)
1168 (preceding-char
1169 :no-eval (preceding-char)
1170 :eg-result 38)
1171 (char-after
1172 :eval (char-after 45))
1173 (char-before
1174 :eval (char-before 13))
1175 (get-byte
1176 :no-eval (get-byte 45)
1177 :eg-result-string "#xff")
1178 "Altering Buffers"
1179 (delete-region
1180 :no-value (delete-region (point-min) (point-max)))
1181 (erase-buffer
1182 :no-value (erase-buffer))
1183 (delete-line
1184 :no-value (delete-line))
1185 (insert
1186 :no-value (insert "This string will be inserted in the buffer\n"))
1187 (subst-char-in-region
1188 :no-eval "(subst-char-in-region (point-min) (point-max) ?+ ?-)")
1189 (replace-string-in-region
1190 :no-value (replace-string-in-region "foo" "bar"))
1191 "Locking"
1192 (lock-buffer
1193 :no-value (lock-buffer "/tmp/foo"))
1194 (unlock-buffer
1195 :no-value (unlock-buffer)))
1196
1197(define-short-documentation-group overlay
1198 "Predicates"
1199 (overlayp
1200 :no-eval (overlayp some-overlay)
1201 :eg-result t)
1202 "Creation and Deletion"
1203 (make-overlay
1204 :args (beg end &optional buffer)
1205 :no-eval (make-overlay 1 10)
1206 :eg-result-string "#<overlay from 1 to 10 in *foo*>")
1207 (delete-overlay
1208 :no-eval (delete-overlay foo)
1209 :eg-result t)
1210 "Searching Overlays"
1211 (overlays-at
1212 :no-eval (overlays-at 15)
1213 :eg-result-string "(#<overlay from 1 to 10 in *foo*>)")
1214 (overlays-in
1215 :no-eval (overlays-in 1 30)
1216 :eg-result-string "(#<overlay from 1 to 10 in *foo*>)")
1217 (next-overlay-change
1218 :no-eval (next-overlay-change 1)
1219 :eg-result 20)
1220 (previous-overlay-change
1221 :no-eval (previous-overlay-change 30)
1222 :eg-result 20)
1223 "Overlay Properties"
1224 (overlay-start
1225 :no-eval (overlay-start foo)
1226 :eg-result 1)
1227 (overlay-end
1228 :no-eval (overlay-end foo)
1229 :eg-result 10)
1230 (overlay-put
1231 :no-eval (overlay-put foo 'happy t)
1232 :eg-result t)
1233 (overlay-get
1234 :no-eval (overlay-get foo 'happy)
1235 :eg-result t)
1236 (overlay-buffer
1237 :no-eval (overlay-buffer foo))
1238 "Moving Overlays"
1239 (move-overlay
1240 :no-eval (move-overlay foo 5 20)
1241 :eg-result-string "#<overlay from 5 to 20 in *foo*>"))
1242
1243(define-short-documentation-group process
1244 (make-process
1245 :no-eval (make-process :name "foo" :command '("cat" "/tmp/foo"))
1246 :eg-result-string "#<process foo>")
1247 (processp
1248 :eval (processp t))
1249 (process-status
1250 :no-eval (process-status process)
1251 :eg-result exit)
1252 (delete-process
1253 :no-value (delete-process process))
1254 (kill-process
1255 :no-value (kill-process process))
1256 (set-process-sentinel
1257 :no-value (set-process-sentinel process (lambda (proc string))))
1258 (process-buffer
1259 :no-eval (process-buffer process)
1260 :eg-result-string "#<buffer *foo*>")
1261 (get-buffer-process
1262 :no-eval (get-buffer-process buffer)
1263 :eg-result-string "#<process foo>")
1264 (process-live-p
1265 :no-eval (process-live-p process)
1266 :eg-result t))
1267
1268(define-short-documentation-group number
1269 "Arithmetic"
1270 (+
1271 :args (&rest numbers)
1272 :eval (+ 1 2)
1273 :eval (+ 1 2 3 4))
1274 (-
1275 :args (&rest numbers)
1276 :eval (- 3 2)
1277 :eval (- 6 3 2))
1278 (*
1279 :args (&rest numbers)
1280 :eval (* 3 4 5))
1281 (/
1282 :eval (/ 10 5)
1283 :eval (/ 10 6)
1284 :eval (/ 10.0 6)
1285 :eval (/ 10.0 3 3))
1286 (%
1287 :eval (% 10 5)
1288 :eval (% 10 6))
1289 (mod
1290 :eval (mod 10 5)
1291 :eval (mod 10 6)
1292 :eval (mod 10.5 6))
1293 (1+
1294 :eval (1+ 2)
1295 :eval (let ((x 2)) (1+ x) x))
1296 (1-
1297 :eval (1- 4)
1298 :eval (let ((x 4)) (1- x) x))
1299 (incf
1300 :eval (let ((x 2)) (incf x) x)
1301 :eval (let ((x 2)) (incf x 2) x))
1302 (decf
1303 :eval (let ((x 4)) (decf x) x)
1304 :eval (let ((x 4)) (decf x 2) x))
1305 "Predicates"
1306 (=
1307 :args (number &rest numbers)
1308 :eval (= 4 4)
1309 :eval (= 4.0 4.0)
1310 :eval (= 4 4.0)
1311 :eval (= 4 4 4 4))
1312 (eql
1313 :eval (eql 4 4)
1314 :eval (eql 4.0 4.0))
1315 (/=
1316 :eval (/= 4 4))
1317 (<
1318 :args (number &rest numbers)
1319 :eval (< 4 4)
1320 :eval (< 1 2 3))
1321 (<=
1322 :args (number &rest numbers)
1323 :eval (<= 4 4)
1324 :eval (<= 1 2 2 3))
1325 (>
1326 :args (number &rest numbers)
1327 :eval (> 4 4)
1328 :eval (> 3 2 1))
1329 (>=
1330 :args (number &rest numbers)
1331 :eval (>= 4 4)
1332 :eval (>= 3 2 2 1))
1333 (zerop
1334 :eval (zerop 0))
1335 (natnump
1336 :eval (natnump -1)
1337 :eval (natnump 0)
1338 :eval (natnump 23))
1339 (plusp
1340 :eval (plusp 0)
1341 :eval (plusp 1))
1342 (minusp
1343 :eval (minusp 0)
1344 :eval (minusp -1))
1345 (oddp
1346 :eval (oddp 3))
1347 (evenp
1348 :eval (evenp 6))
1349 (bignump
1350 :eval (bignump 4)
1351 :eval (bignump (expt 2 90)))
1352 (fixnump
1353 :eval (fixnump 4)
1354 :eval (fixnump (expt 2 90)))
1355 (floatp
1356 :eval (floatp 5.4))
1357 (integerp
1358 :eval (integerp 5.4))
1359 (numberp
1360 :eval (numberp "5.4"))
1361 (cl-digit-char-p
1362 :eval (cl-digit-char-p ?5 10)
1363 :eval (cl-digit-char-p ?f 16))
1364 "Operations"
1365 (max
1366 :args (number &rest numbers)
1367 :eval (max 7 9 3))
1368 (min
1369 :args (number &rest numbers)
1370 :eval (min 7 9 3))
1371 (abs
1372 :eval (abs -4))
1373 (float
1374 :eval (float 2))
1375 (truncate
1376 :eval (truncate 1.2)
1377 :eval (truncate -1.2)
1378 :eval (truncate 5.4 2))
1379 (floor
1380 :eval (floor 1.2)
1381 :eval (floor -1.2)
1382 :eval (floor 5.4 2))
1383 (ceiling
1384 :eval (ceiling 1.2)
1385 :eval (ceiling -1.2)
1386 :eval (ceiling 5.4 2))
1387 (round
1388 :eval (round 1.2)
1389 :eval (round -1.2)
1390 :eval (round 5.4 2))
1391 (random
1392 :eval (random 6))
1393 "Bit Operations"
1394 (ash
1395 :eval (ash 1 4)
1396 :eval (ash 16 -1))
1397 (logand
1398 :no-eval "(logand #b10 #b111)"
1399 :result-string "#b10")
1400 (logior
1401 :eval (logior 4 16))
1402 (logxor
1403 :eval (logxor 4 16))
1404 (lognot
1405 :eval (lognot 5))
1406 (logcount
1407 :eval (logcount 5))
1408 "Floating Point"
1409 (isnan
1410 :eval (isnan 5.0))
1411 (frexp
1412 :eval (frexp 5.7))
1413 (ldexp
1414 :eval (ldexp 0.7125 3))
1415 (logb
1416 :eval (logb 10.5))
1417 (ffloor
1418 :eval (ffloor 1.2))
1419 (fceiling
1420 :eval (fceiling 1.2))
1421 (ftruncate
1422 :eval (ftruncate 1.2))
1423 (fround
1424 :eval (fround 1.2))
1425 "Standard Math Functions"
1426 (sin
1427 :eval (sin float-pi))
1428 (cos
1429 :eval (cos float-pi))
1430 (tan
1431 :eval (tan float-pi))
1432 (asin
1433 :eval (asin float-pi))
1434 (acos
1435 :eval (acos float-pi))
1436 (atan
1437 :eval (atan float-pi))
1438 (exp
1439 :eval (exp 4))
1440 (log
1441 :eval (log 54.59))
1442 (expt
1443 :eval (expt 2 16))
1444 (sqrt
1445 :eval (sqrt -1)))
1446
1447(define-short-documentation-group text-properties
1448 "Examining Text Properties"
1449 (get-text-property
1450 :eval (get-text-property 0 'foo (propertize "x" 'foo t)))
1451 (get-char-property
1452 :eval (get-char-property 0 'foo (propertize "x" 'foo t)))
1453 (get-pos-property
1454 :eval (get-pos-property 0 'foo (propertize "x" 'foo t)))
1455 (get-char-property-and-overlay
1456 :eval (get-char-property-and-overlay 0 'foo (propertize "x" 'foo t)))
1457 (text-properties-at
1458 :eval (text-properties-at (point)))
1459 "Changing Text Properties"
1460 (put-text-property
1461 :eval (let ((s (copy-sequence "abc"))) (put-text-property 0 1 'foo t s) s)
1462 :no-eval (put-text-property (point) (1+ (point)) 'face 'error))
1463 (add-text-properties
1464 :no-eval (add-text-properties (point) (1+ (point)) '(face error)))
1465 (remove-text-properties
1466 :no-eval (remove-text-properties (point) (1+ (point)) '(face nil)))
1467 (remove-list-of-text-properties
1468 :no-eval (remove-list-of-text-properties (point) (1+ (point)) '(face font-lock-face)))
1469 (set-text-properties
1470 :no-eval (set-text-properties (point) (1+ (point)) '(face error)))
1471 (add-face-text-property
1472 :no-eval (add-face-text-property START END '(:foreground "green")))
1473 (propertize
1474 :eval (propertize "foo" 'face 'italic 'mouse-face 'bold-italic))
1475 "Searching for Text Properties"
1476 (next-property-change
1477 :no-eval (next-property-change (point) (current-buffer)))
1478 (previous-property-change
1479 :no-eval (previous-property-change (point) (current-buffer)))
1480 (next-single-property-change
1481 :no-eval (next-single-property-change (point) 'face (current-buffer)))
1482 (previous-single-property-change
1483 :no-eval (previous-single-property-change (point) 'face (current-buffer)))
1484 ;; TODO: There are some more that could be added here.
1485 (text-property-search-forward
1486 :no-eval (text-property-search-forward 'face nil t))
1487 (text-property-search-backward
1488 :no-eval (text-property-search-backward 'face nil t)))
1489
1490(define-short-documentation-group keymaps
1491 "Defining keymaps or adding bindings to existing keymaps"
1492 (define-keymap
1493 :no-eval (define-keymap "C-c C-c" #'quit-buffer)
1494 :no-eval (define-keymap :keymap ctl-x-map
1495 "C-r" #'recentf-open
1496 "k" #'kill-current-buffer))
1497 (defvar-keymap
1498 :no-eval (defvar-keymap my-keymap "C-c C-c" #'quit-buffer))
1499 "Setting keys"
1500 (keymap-set
1501 :no-eval (keymap-set map "C-c C-c" #'quit-buffer))
1502 (keymap-local-set
1503 :no-eval (keymap-local-set "C-c C-c" #'quit-buffer))
1504 (keymap-global-set
1505 :no-eval (keymap-global-set "C-c C-c" #'quit-buffer))
1506 (keymap-unset
1507 :no-eval (keymap-unset map "C-c C-c"))
1508 (keymap-local-unset
1509 :no-eval (keymap-local-unset "C-c C-c"))
1510 (keymap-global-unset
1511 :no-eval (keymap-global-unset "C-c C-c"))
1512 (keymap-substitute
1513 :no-eval (keymap-substitute map "C-c C-c" "M-a"))
1514 (keymap-set-after
1515 :no-eval (keymap-set-after map "<separator-2>" menu-bar-separator))
1516 "Predicates"
1517 (keymapp
1518 :eval (keymapp (define-keymap)))
1519 (key-valid-p
1520 :eval (key-valid-p "C-c C-c")
1521 :eval (key-valid-p "C-cC-c"))
1522 "Lookup"
1523 (keymap-lookup
1524 :eval (keymap-lookup (current-global-map) "C-x x g")))
1525
1526(provide 'shortdoc-doc)
1527
1528;;; shortdoc-doc.el ends here
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index ea6910c60fc..e8ba6ededc0 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -25,8 +25,8 @@
25;; This package lists functions based on various groupings. 25;; This package lists functions based on various groupings.
26;; 26;;
27;; For instance, `string-trim' and `mapconcat' are `string' functions, 27;; For instance, `string-trim' and `mapconcat' are `string' functions,
28;; so `M-x shortdoc RET string RET' will give an overview of functions 28;; so `M-x shortdoc RET string RET' will give an overview of these and
29;; that operate on strings. 29;; other functions that operate on strings.
30;; 30;;
31;; The documentation groups are created with the 31;; The documentation groups are created with the
32;; `define-short-documentation-group' macro. 32;; `define-short-documentation-group' macro.
@@ -50,23 +50,109 @@
50 '((t :inherit variable-pitch)) 50 '((t :inherit variable-pitch))
51 "Face used for a section.") 51 "Face used for a section.")
52 52
53;;;###autoload 53
54(defun shortdoc--check (group functions) 54;; Almost all past Emacs versions (but see note on Emacs 30 below)
55 (let ((keywords '( :no-manual :args :eval :no-eval :no-value :no-eval* 55;; understand the following shortdoc group structure:
56 :result :result-string :eg-result :eg-result-string :doc))) 56;;
57 (dolist (f functions) 57;; (SYMBOL ;; shortdoc group name
58 (when (consp f) 58;; (:group [:KEYWORD VALUE ...]) ;; group properties
59 (dolist (x f) 59;; STRING ;; shortdoc section title
60 (when (and (keywordp x) (not (memq x keywords))) 60;; (:section [:KEYWORD VALUE ...]) ;; section properties
61 (error "Shortdoc %s function `%s': bad keyword `%s'" 61;;
62 group (car f) x))))))) 62;; (SYMBOL ;; shortdoc item
63;; [:KEYWORD VALUE ...]) ;; item properties
64;; ([:item] FORM ;; generalized shortdoc item
65;; [:KEYWORD VALUE ...])) ;; item properties
66;;
67;; Where:
68;; - a group definition must contain at least one section title or item;
69;; - group and section properties must occur at most once after the
70;; group name and a section title, respectively;
71;; - the leading `:item' keyword of a generalized shortdoc item may be
72;; omitted if the shortdoc group is not intended to be used on Emacs
73;; versions older than Emacs 32;
74;; - the group, secion, or item properties may be empty.
75;;
76;; That does not mean that any such shortdoc group is meaningful. And
77;; that does not mean that past Emacs version actually use all the bits
78;; available in such a definition. But they will not error out when
79;; processing a definition with the format layed out above, they will
80;; simply silently ignore those bits unknown to them (specifically
81;; unknown keywords) and attempt to make the best out of the rest.
82;;
83;; Why is this important? Because it gives package authors a guarantee
84;; that they can use shortdoc features of newer Emacs versions without
85;; older Emacs versions breaking on them.
86;;
87;; So Emacs developers, please
88;;
89;; - stick to above structure when extending shortdoc.el (so that past
90;; Emacs versions can grok your extensions without breaking); and
91;;
92;; - do not impose any additional restrictions on the format described
93;; above and on the allowed keywords (so that you do not limit the
94;; options of future Emacs versions).
95;;
96;; Emacs 30, for example, had introduced some restrictions on item
97;; property keywords. As a result, we need that hack mentioned in the
98;; "boilerplate template for Emacs package authors" above.
99
100(defun shortdoc--keyword-plist-p (object)
101 "Return non-nil if OBJECT is a plist with keywords as property names."
102 (let ((ok (proper-list-p object)))
103 (while (and ok object)
104 (setq ok (and (keywordp (car object)) (cdr object))
105 object (cddr object)))
106 ok))
107
108(defun shortdoc--check (group definition)
109 "Ensure that (GROUP DEFINITION) is a valid shortdoc group definition.
110Signal an error if that is not the case."
111 (unless (symbolp group)
112 (signal 'wrong-type-argument (list 'symbolp group)))
113 (unless (proper-list-p definition)
114 (signal 'wrong-type-argument (list 'proper-list-p definition)))
115 (let ((has-content nil)
116 entry keyword type
117 (prev-type 'group-name))
118 (while definition
119 (setq entry (car definition)
120 keyword (car-safe entry)
121 type (cond
122 ((and (eq keyword :group)
123 (shortdoc--keyword-plist-p (cdr entry)))
124 'group-properties)
125 ((stringp entry) 'section-title)
126 ((and (eq keyword :section)
127 (shortdoc--keyword-plist-p (cdr entry)))
128 'section-properties)
129 ((and (eq keyword :item)
130 (shortdoc--keyword-plist-p entry))
131 'item-definition)
132 ((and (consp entry)
133 (shortdoc--keyword-plist-p (cdr entry)))
134 'item-definition)
135 (t 'invalid)))
136 (cond ((memq type '(section-title item-definition))
137 (setq has-content t))
138 ((and (eq type 'group-properties)
139 (eq prev-type 'group-name)))
140 ((and (eq type 'section-properties)
141 (eq prev-type 'section-title)))
142 (t
143 (error "Shortdoc group %s with invalid entry %S"
144 group entry)))
145 (setq prev-type type
146 definition (cdr definition)))
147 (unless has-content
148 (error "Shortdoc group %s without content" group))))
63 149
64;;;###autoload 150;;;###autoload
65(progn 151(defvar shortdoc--groups nil)
66 (defvar shortdoc--groups nil)
67 152
68 (defmacro define-short-documentation-group (group &rest functions) 153;;;###autoload
69 "Add GROUP to the list of defined documentation groups. 154(defmacro define-short-documentation-group (group &rest functions)
155 "Add GROUP to the list of defined documentation groups.
70FUNCTIONS is a list of elements on the form: 156FUNCTIONS is a list of elements on the form:
71 157
72 (FUNC 158 (FUNC
@@ -128,1504 +214,28 @@ execution of the documented form depends on some conditions.
128A FUNC form can have any number of `:no-eval' (or `:no-value'), 214A FUNC form can have any number of `:no-eval' (or `:no-value'),
129`:no-eval*', `:result', `:result-string', `:eg-result' and 215`:no-eval*', `:result', `:result-string', `:eg-result' and
130`:eg-result-string' properties." 216`:eg-result-string' properties."
131 (declare (indent defun)) 217 (declare (indent defun))
132 (shortdoc--check group functions) 218 (let ((err
133 `(progn 219 (condition-case err
134 (setq shortdoc--groups (delq (assq ',group shortdoc--groups) 220 (progn (shortdoc--check group functions) nil)
135 shortdoc--groups)) 221 (error err)))
136 (push (cons ',group ',functions) shortdoc--groups)))) 222 (exp
137 223 `(progn
138(define-short-documentation-group alist 224 (setq shortdoc--groups (delq (assq ',group shortdoc--groups)
139 "Alist Basics" 225 shortdoc--groups))
140 (assoc 226 (push (cons ',group ',functions) shortdoc--groups))))
141 :eval (assoc 'foo '((foo . bar) (zot . baz)))) 227 (if (null err)
142 (rassoc 228 exp
143 :eval (rassoc 'bar '((foo . bar) (zot . baz)))) 229 (macroexp-warn-and-return
144 (assq 230 (error-message-string err) exp nil t))))
145 :eval (assq 'foo '((foo . bar) (zot . baz)))) 231
146 (rassq 232;; FIXME: As long as we do not have a better mechanism to load shortdoc
147 :eval (rassq 'bar '((foo . bar) (zot . baz)))) 233;; definitions on demand, we must require `shortdoc-doc' after above
148 (assoc-string 234;; macro to avoid loading cycles. But at least we do not require
149 :eval (assoc-string "foo" '(("foo" . "bar") ("zot" "baz")))) 235;; `shortdoc-doc' while compiling this file, only when loading it.
150 "Manipulating Alists" 236(if t (require 'shortdoc-doc))
151 (assoc-delete-all 237
152 :eval (assoc-delete-all "b" (list '("a" . a) '("b" . b) '("b" . c)))) 238
153 (assq-delete-all
154 :eval (assq-delete-all 2 (list '(1 . a) '(2 . b) '(2 . c))))
155 (rassq-delete-all
156 :eval (rassq-delete-all 'b (list '(1 . a) '(2 . b) '(2 . c))))
157 (alist-get
158 :eval (let ((foo '((bar . baz))))
159 (setf (alist-get 'bar foo) 'zot)
160 foo))
161 "Misc"
162 (assoc-default
163 :eval (assoc-default "foobar" '(("foo" . baz)) #'string-match))
164 (copy-alist
165 :eval (let* ((old '((foo . bar)))
166 (new (copy-alist old)))
167 (eq old new)))
168 ;; FIXME: Outputs "\.rose" for the symbol `.rose'. It would be
169 ;; better if that could be cleaned up.
170 (let-alist
171 :eval (let ((colors '((rose . red)
172 (lily . white))))
173 (let-alist colors
174 (if (eq .rose 'red)
175 .lily)))))
176
177(define-short-documentation-group map
178 "Map Basics"
179 (mapp
180 :eval (mapp (list 'bar 1 'foo 2 'baz 3))
181 :eval (mapp (list '(bar . 1) '(foo . 2) '(baz . 3)))
182 :eval (mapp [bar foo baz])
183 :eval (mapp "this is a string")
184 :eval (mapp #s(hash-table data (bar 1 foo 2 baz 3)))
185 :eval (mapp '())
186 :eval (mapp nil)
187 :eval (mapp (make-char-table 'shortdoc-test)))
188 (map-empty-p
189 :args (map)
190 :eval (map-empty-p nil)
191 :eval (map-empty-p [])
192 :eval (map-empty-p '()))
193 (map-elt
194 :args (map key)
195 :eval (map-elt (list 'bar 1 'foo 2 'baz 3) 'foo)
196 :eval (map-elt (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo)
197 :eval (map-elt [bar foo baz] 1)
198 :eval (map-elt #s(hash-table data (bar 1 foo 2 baz 3)) 'foo))
199 (map-contains-key
200 :args (map key)
201 :eval (map-contains-key (list 'bar 1 'foo 2 'baz 3) 'foo)
202 :eval (map-contains-key (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo)
203 :eval (map-contains-key [bar foo baz] 1)
204 :eval (map-contains-key #s(hash-table data (bar 1 foo 2 baz 3)) 'foo))
205 (map-put!
206 (map key value)
207 :eval
208"(let ((map (list 'bar 1 'baz 3)))
209 (map-put! map 'foo 2)
210 map)"
211;; This signals map-not-inplace when used in shortdoc.el :-(
212;; :eval
213;; "(let ((map (list '(bar . 1) '(baz . 3))))
214;; (map-put! map 'foo 2)
215;; map)"
216 :eval
217"(let ((map [bar bot baz]))
218 (map-put! map 1 'foo)
219 map)"
220 :eval
221"(let ((map #s(hash-table data (bar 1 baz 3))))
222 (map-put! map 'foo 2)
223 map)")
224 (map-insert
225 :args (map key value)
226 :eval (map-insert (list 'bar 1 'baz 3 'foo 7) 'foo 2)
227 :eval (map-insert (list '(bar . 1) '(baz . 3) '(foo . 7)) 'foo 2)
228 :eval (map-insert [bar bot baz] 1 'foo)
229 :eval (map-insert #s(hash-table data (bar 1 baz 3 foo 7)) 'foo 2))
230 (map-delete
231 :args (map key)
232 :eval (map-delete (list 'bar 1 'foo 2 'baz 3) 'foo)
233 :eval (map-delete (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo)
234 :eval (map-delete [bar foo baz] 1)
235 :eval (map-delete #s(hash-table data (bar 1 foo 2 baz 3)) 'foo))
236 (map-keys
237 :eval (map-keys (list 'bar 1 'foo 2 'baz 3))
238 :eval (map-keys (list '(bar . 1) '(foo . 2) '(baz . 3)))
239 :eval (map-keys [bar foo baz])
240 :eval (map-keys #s(hash-table data (bar 1 foo 2 baz 3))))
241 (map-values
242 :args (map)
243 :eval (map-values (list 'bar 1 'foo 2 'baz 3))
244 :eval (map-values (list '(bar . 1) '(foo . 2) '(baz . 3)))
245 :eval (map-values [bar foo baz])
246 :eval (map-values #s(hash-table data (bar 1 foo 2 baz 3))))
247 (map-pairs
248 :eval (map-pairs (list 'bar 1 'foo 2 'baz 3))
249 :eval (map-pairs (list '(bar . 1) '(foo . 2) '(baz . 3)))
250 :eval (map-pairs [bar foo baz])
251 :eval (map-pairs #s(hash-table data (bar 1 foo 2 baz 3))))
252 (map-length
253 :args (map)
254 :eval (map-length (list 'bar 1 'foo 2 'baz 3))
255 :eval (map-length (list '(bar . 1) '(foo . 2) '(baz . 3)))
256 :eval (map-length [bar foo baz])
257 :eval (map-length #s(hash-table data (bar 1 foo 2 baz 3))))
258 (map-copy
259 :args (map)
260 :eval (map-copy (list 'bar 1 'foo 2 'baz 3))
261 :eval (map-copy (list '(bar . 1) '(foo . 2) '(baz . 3)))
262 :eval (map-copy [bar foo baz])
263 :eval (map-copy #s(hash-table data (bar 1 foo 2 baz 3))))
264 "Doing things to maps and their contents"
265 (map-apply
266 :args (function map)
267 :eval (map-apply #'+ (list '(1 . 2) '(3 . 4))))
268 (map-do
269 :args (function map)
270 :eval
271"(let ((map (list '(1 . 1) '(2 . 3)))
272 acc)
273 (map-do (lambda (k v) (push (+ k v) acc)) map)
274 (nreverse acc))")
275 (map-keys-apply
276 :eval (map-keys-apply #'1+ (list '(1 . 2) '(3 . 4))))
277 (map-values-apply
278 :args (function map)
279 :eval (map-values-apply #'1+ (list '(1 . 2) '(3 . 4))))
280 (map-filter
281 :eval (map-filter (lambda (k _) (oddp k)) (list '(1 . 2) '(4 . 6)))
282 :eval (map-filter (lambda (k v) (evenp (+ k v))) (list '(1 . 2) '(4 . 6))))
283 (map-remove
284 :eval (map-remove (lambda (k _) (oddp k)) (list '(1 . 2) '(4 . 6)))
285 :eval (map-remove (lambda (k v) (evenp (+ k v))) (list '(1 . 2) '(4 . 6))))
286 (map-some
287 :eval (map-some (lambda (k _) (oddp k)) (list '(1 . 2) '(4 . 6)))
288 :eval (map-some (lambda (k v) (evenp (+ k v))) (list '(1 . 2) '(4 . 6))))
289 (map-every-p
290 :eval (map-every-p (lambda (k _) (oddp k)) (list '(1 . 2) '(4 . 6)))
291 :eval (map-every-p (lambda (k v) (evenp (+ k v))) (list '(1 . 3) '(4 . 6))))
292 "Combining and changing maps"
293 (map-merge
294 :eval (map-merge 'alist '(1 2 3 4) #s(hash-table data (5 6 7 8)))
295 :eval (map-merge 'list '(1 2 3 4) #s(hash-table data (5 6 7 8)))
296 :eval (map-merge 'plist '(1 2 3 4) #s(hash-table data (5 6 7 8)))
297 :eval (map-merge 'hash-table '(1 2 3 4) #s(hash-table data (5 6 7 8))))
298 (map-merge-with
299 :eval (map-merge-with 'alist #'max '(1 2 3 4) #s(hash-table data (1 1 3 5)))
300 :eval (map-merge-with 'alist #'min '(1 2 3 4) #s(hash-table data (1 1 3 5)))
301 :eval (map-merge-with 'hash-table #'min '(1 2 3 4) #s(hash-table data (1 1 3 5))))
302 (map-into
303 :args (map type)
304 :eval (map-into #s(hash-table data '(5 6 7 8)) 'list)
305 :eval (map-into '((5 . 6) (7 . 8)) 'plist)
306 :eval (map-into '((5 . 6) (7 . 8)) 'hash-table)))
307
308(define-short-documentation-group string
309 "Making Strings"
310 (make-string
311 :args (length init)
312 :eval "(make-string 5 ?x)")
313 (string
314 :eval "(string ?a ?b ?c)")
315 (concat
316 :eval (concat "foo" "bar" "zot"))
317 (string-join
318 :no-manual t
319 :eval (string-join '("foo" "bar" "zot") " "))
320 (mapconcat
321 :eval (mapconcat (lambda (a) (concat "[" a "]"))
322 '("foo" "bar" "zot") " "))
323 (string-pad
324 :eval (string-pad "foo" 5)
325 :eval (string-pad "foobar" 5)
326 :eval (string-pad "foo" 5 ?- t))
327 (mapcar
328 :eval (mapcar #'identity "123"))
329 (format
330 :eval (format "This number is %d" 4))
331 "Manipulating Strings"
332 (substring
333 :eval (substring "abcde" 1 3)
334 :eval (substring "abcde" 2)
335 :eval (substring "abcde" 1 -1)
336 :eval (substring "abcde" -4 4))
337 (string-limit
338 :eval (string-limit "foobar" 3)
339 :eval (string-limit "foobar" 3 t)
340 :eval (string-limit "foobar" 10)
341 :eval (string-limit "fo好" 3 nil 'utf-8))
342 (truncate-string-to-width
343 :eval (truncate-string-to-width "foobar" 3)
344 :eval (truncate-string-to-width "你好bar" 5))
345 (split-string
346 :eval (split-string "foo bar")
347 :eval (split-string "|foo|bar|" "|")
348 :eval (split-string "|foo|bar|" "|" t))
349 (split-string-and-unquote
350 :eval (split-string-and-unquote "foo \"bar zot\""))
351 (split-string-shell-command
352 :eval (split-string-shell-command "ls /tmp/'foo bar'"))
353 (string-lines
354 :eval (string-lines "foo\n\nbar")
355 :eval (string-lines "foo\n\nbar" t))
356 (string-replace
357 :eval (string-replace "foo" "bar" "foozot"))
358 (replace-regexp-in-string
359 :eval (replace-regexp-in-string "[a-z]+" "_" "*foo*"))
360 (string-trim
361 :args (string)
362 :doc "Trim STRING of leading and trailing white space."
363 :eval (string-trim " foo "))
364 (string-trim-left
365 :eval (string-trim-left "oofoo" "o+"))
366 (string-trim-right
367 :eval (string-trim-right "barkss" "s+"))
368 (string-truncate-left
369 :no-manual t
370 :eval (string-truncate-left "longstring" 8))
371 (string-remove-suffix
372 :no-manual t
373 :eval (string-remove-suffix "bar" "foobar"))
374 (string-remove-prefix
375 :no-manual t
376 :eval (string-remove-prefix "foo" "foobar"))
377 (string-chop-newline
378 :eval (string-chop-newline "foo\n"))
379 (string-clean-whitespace
380 :eval (string-clean-whitespace " foo bar "))
381 (string-fill
382 :eval (string-fill "Three short words" 12)
383 :eval (string-fill "Long-word" 3))
384 (reverse
385 :eval (reverse "foo"))
386 (substring-no-properties
387 :eval (substring-no-properties (propertize "foobar" 'face 'bold) 0 3))
388 (try-completion
389 :eval (try-completion "foo" '("foobar" "foozot" "gazonk")))
390 "Unicode Strings"
391 (string-glyph-split
392 :eval (string-glyph-split "Hello, 👼🏻🧑🏼‍🤝‍🧑🏻"))
393 (string-glyph-compose
394 :eval (string-glyph-compose "Å"))
395 (string-glyph-decompose
396 :eval (string-glyph-decompose "Å"))
397 "Predicates for Strings"
398 (string-equal
399 :eval (string-equal "abc" "abc")
400 :eval (string-equal "abc" "ABC"))
401 (string-equal-ignore-case
402 :eval (string-equal-ignore-case "foo" "FOO"))
403 (equal
404 :eval (equal "foo" "foo"))
405 (cl-equalp
406 :eval (cl-equalp "Foo" "foo"))
407 (stringp
408 :eval (stringp "a")
409 :eval (stringp 'a)
410 :eval "(stringp ?a)")
411 (string-or-null-p
412 :eval (string-or-null-p "a")
413 :eval (string-or-null-p nil))
414 (char-or-string-p
415 :eval "(char-or-string-p ?a)"
416 :eval (char-or-string-p "a"))
417 (string-empty-p
418 :no-manual t
419 :eval (string-empty-p ""))
420 (string-blank-p
421 :no-manual t
422 :eval (string-blank-p " \n"))
423 (string-lessp
424 :eval (string-lessp "abc" "def")
425 :eval (string-lessp "pic4.png" "pic32.png")
426 :eval (string-lessp "1.1" "1.2"))
427 (string-greaterp
428 :eval (string-greaterp "foo" "bar"))
429 (string-version-lessp
430 :eval (string-version-lessp "pic4.png" "pic32.png")
431 :eval (string-version-lessp "1.9.3" "1.10.2"))
432 (string-collate-lessp
433 :eval (string-collate-lessp "abc" "abd"))
434 (string-prefix-p
435 :eval (string-prefix-p "foo" "foobar"))
436 (string-suffix-p
437 :eval (string-suffix-p "bar" "foobar"))
438 "Case Manipulation"
439 (upcase
440 :eval (upcase "foo"))
441 (downcase
442 :eval (downcase "FOObar"))
443 (capitalize
444 :eval (capitalize "foo bar zot"))
445 (upcase-initials
446 :eval (upcase-initials "The CAT in the hAt"))
447 "Converting Strings"
448 (string-to-number
449 :eval (string-to-number "42")
450 :eval (string-to-number "deadbeef" 16)
451 :eval (string-to-number "2.5e+03"))
452 (number-to-string
453 :eval (number-to-string 42))
454 (char-uppercase-p
455 :eval "(char-uppercase-p ?A)"
456 :eval "(char-uppercase-p ?a)")
457 "Data About Strings"
458 (length
459 :eval (length "foo")
460 :eval (length "avocado: 🥑"))
461 (string-width
462 :eval (string-width "foo")
463 :eval (string-width "avocado: 🥑"))
464 (string-pixel-width
465 :eval (string-pixel-width "foo")
466 :eval (string-pixel-width "avocado: 🥑"))
467 (string-search
468 :eval (string-search "bar" "foobarzot"))
469 (assoc-string
470 :eval (assoc-string "foo" '(("a" 1) (foo 2))))
471 (seq-position
472 :eval "(seq-position \"foobarzot\" ?z)"))
473
474(define-short-documentation-group file-name
475 "File Name Manipulation"
476 (file-name-directory
477 :eval (file-name-directory "/tmp/foo")
478 :eval (file-name-directory "/tmp/foo/"))
479 (file-name-nondirectory
480 :eval (file-name-nondirectory "/tmp/foo")
481 :eval (file-name-nondirectory "/tmp/foo/"))
482 (file-name-sans-versions
483 :args (filename)
484 :eval (file-name-sans-versions "/tmp/foo~"))
485 (file-name-extension
486 :eval (file-name-extension "/tmp/foo.txt"))
487 (file-name-sans-extension
488 :eval (file-name-sans-extension "/tmp/foo.txt"))
489 (file-name-with-extension
490 :eval (file-name-with-extension "foo.txt" "bin")
491 :eval (file-name-with-extension "foo" "bin"))
492 (file-name-base
493 :eval (file-name-base "/tmp/foo.txt"))
494 (file-relative-name
495 :eval (file-relative-name "/tmp/foo" "/tmp"))
496 (file-name-split
497 :eval (file-name-split "/tmp/foo")
498 :eval (file-name-split "foo/bar"))
499 (make-temp-name
500 :eval (make-temp-name "/tmp/foo-"))
501 (file-name-concat
502 :eval (file-name-concat "/tmp/" "foo")
503 :eval (file-name-concat "/tmp" "foo")
504 :eval (file-name-concat "/tmp" "foo" "bar/" "zot")
505 :eval (file-name-concat "/tmp" "~"))
506 (expand-file-name
507 :eval (expand-file-name "foo" "/tmp/")
508 :eval (expand-file-name "foo" "/tmp///")
509 :eval (expand-file-name "foo" "/tmp/foo/.././")
510 :eval (expand-file-name "~" "/tmp/"))
511 (substitute-in-file-name
512 :eval (substitute-in-file-name "$HOME/foo"))
513 "Directory Functions"
514 (file-name-as-directory
515 :eval (file-name-as-directory "/tmp/foo"))
516 (directory-file-name
517 :eval (directory-file-name "/tmp/foo/"))
518 (abbreviate-file-name
519 :no-eval (abbreviate-file-name "/home/some-user")
520 :eg-result "~some-user")
521 (file-name-parent-directory
522 :eval (file-name-parent-directory "/foo/bar")
523 :eval (file-name-parent-directory "/foo/")
524 :eval (file-name-parent-directory "foo/bar")
525 :eval (file-name-parent-directory "foo"))
526 "Quoted File Names"
527 (file-name-quote
528 :args (name)
529 :eval (file-name-quote "/tmp/foo"))
530 (file-name-unquote
531 :args (name)
532 :eval (file-name-unquote "/:/tmp/foo"))
533 "Predicates"
534 (file-name-absolute-p
535 :eval (file-name-absolute-p "/tmp/foo")
536 :eval (file-name-absolute-p "foo"))
537 (directory-name-p
538 :eval (directory-name-p "/tmp/foo/"))
539 (file-name-quoted-p
540 :eval (file-name-quoted-p "/:/tmp/foo")))
541
542(define-short-documentation-group file
543 "Inserting Contents"
544 (insert-file-contents
545 :no-eval (insert-file-contents "/tmp/foo")
546 :eg-result ("/tmp/foo" 6))
547 (insert-file-contents-literally
548 :no-eval (insert-file-contents-literally "/tmp/foo")
549 :eg-result ("/tmp/foo" 6))
550 (find-file
551 :no-eval (find-file "/tmp/foo")
552 :eg-result-string "#<buffer foo>")
553 "Predicates"
554 (file-symlink-p
555 :no-eval (file-symlink-p "/tmp/foo")
556 :eg-result t)
557 (file-directory-p
558 :no-eval (file-directory-p "/tmp")
559 :eg-result t)
560 (file-regular-p
561 :no-eval (file-regular-p "/tmp/foo")
562 :eg-result t)
563 (file-exists-p
564 :no-eval (file-exists-p "/tmp/foo")
565 :eg-result t)
566 (file-readable-p
567 :no-eval (file-readable-p "/tmp/foo")
568 :eg-result t)
569 (file-writable-p
570 :no-eval (file-writable-p "/tmp/foo")
571 :eg-result t)
572 (file-accessible-directory-p
573 :no-eval (file-accessible-directory-p "/tmp")
574 :eg-result t)
575 (file-executable-p
576 :no-eval (file-executable-p "/bin/cat")
577 :eg-result t)
578 (file-newer-than-file-p
579 :no-eval (file-newer-than-file-p "/tmp/foo" "/tmp/bar")
580 :eg-result nil)
581 (file-has-changed-p
582 :no-eval (file-has-changed-p "/tmp/foo")
583 :eg-result t)
584 (file-equal-p
585 :no-eval (file-equal-p "/tmp/foo" "/tmp/bar")
586 :eg-result nil)
587 (file-in-directory-p
588 :no-eval (file-in-directory-p "/tmp/foo" "/tmp/")
589 :eg-result t)
590 (file-locked-p
591 :no-eval (file-locked-p "/tmp/foo")
592 :eg-result nil)
593 "Information"
594 (file-attributes
595 :no-eval* (file-attributes "/tmp"))
596 (file-truename
597 :no-eval (file-truename "/tmp/foo/bar")
598 :eg-result "/tmp/foo/zot")
599 (file-chase-links
600 :no-eval (file-chase-links "/tmp/foo/bar")
601 :eg-result "/tmp/foo/zot")
602 (vc-responsible-backend
603 :args (file &optional no-error)
604 :no-eval (vc-responsible-backend "/src/foo/bar.c")
605 :eg-result Git)
606 (file-acl
607 :no-eval (file-acl "/tmp/foo")
608 :eg-result "user::rw-\ngroup::r--\nother::r--\n")
609 (file-extended-attributes
610 :no-eval* (file-extended-attributes "/tmp/foo"))
611 (file-selinux-context
612 :no-eval* (file-selinux-context "/tmp/foo"))
613 (locate-file
614 :no-eval (locate-file "syslog" '("/var/log" "/usr/bin"))
615 :eg-result "/var/log/syslog")
616 (executable-find
617 :no-eval (executable-find "ls")
618 :eg-result "/usr/bin/ls")
619 "Creating"
620 (make-temp-file
621 :no-eval (make-temp-file "/tmp/foo-")
622 :eg-result "/tmp/foo-ZcXFMj")
623 (make-nearby-temp-file
624 :no-eval (make-nearby-temp-file "/tmp/foo-")
625 :eg-result "/tmp/foo-xe8iON")
626 (write-region
627 :no-value (write-region (point-min) (point-max) "/tmp/foo"))
628 "Directories"
629 (make-directory
630 :no-value (make-directory "/tmp/bar/zot/" t))
631 (directory-files
632 :no-eval (directory-files "/tmp/")
633 :eg-result ("." ".." ".ICE-unix" ".Test-unix"))
634 (directory-files-recursively
635 :no-eval (directory-files-recursively "/tmp/" "\\.png\\'")
636 :eg-result ("/tmp/foo.png" "/tmp/zot.png" "/tmp/bar/foobar.png"))
637 (directory-files-and-attributes
638 :no-eval* (directory-files-and-attributes "/tmp/foo"))
639 (file-expand-wildcards
640 :no-eval (file-expand-wildcards "/tmp/*.png")
641 :eg-result ("/tmp/foo.png" "/tmp/zot.png")
642 :no-eval (file-expand-wildcards "/*/foo.png")
643 :eg-result ("/tmp/foo.png" "/var/foo.png"))
644 (locate-dominating-file
645 :no-eval (locate-dominating-file "foo.png" "/tmp/foo/bar/zot")
646 :eg-result "/tmp/foo.png")
647 (copy-directory
648 :no-value (copy-directory "/tmp/bar/" "/tmp/barcopy"))
649 (delete-directory
650 :no-value (delete-directory "/tmp/bar/"))
651 "File Operations"
652 (rename-file
653 :no-value (rename-file "/tmp/foo" "/tmp/newname"))
654 (copy-file
655 :no-value (copy-file "/tmp/foo" "/tmp/foocopy"))
656 (delete-file
657 :no-value (delete-file "/tmp/foo"))
658 (make-empty-file
659 :no-value (make-empty-file "/tmp/foo"))
660 (make-symbolic-link
661 :no-value (make-symbolic-link "/tmp/foo" "/tmp/foosymlink"))
662 (add-name-to-file
663 :no-value (add-name-to-file "/tmp/foo" "/tmp/bar"))
664 (set-file-modes
665 :no-value "(set-file-modes \"/tmp/foo\" #o644)")
666 (set-file-times
667 :no-value (set-file-times "/tmp/foo"))
668 "File Modes"
669 (set-default-file-modes
670 :no-value "(set-default-file-modes #o755)")
671 (default-file-modes
672 :no-eval (default-file-modes)
673 :eg-result-string "#o755")
674 (file-modes-symbolic-to-number
675 :no-eval (file-modes-symbolic-to-number "a+r")
676 :eg-result-string "#o444")
677 (file-modes-number-to-symbolic
678 :eval "(file-modes-number-to-symbolic #o444)")
679 (set-file-extended-attributes
680 :no-eval (set-file-extended-attributes
681 "/tmp/foo" '((acl . "group::rxx")))
682 :eg-result t)
683 (set-file-selinux-context
684 :no-eval (set-file-selinux-context
685 "/tmp/foo" '(unconfined_u object_r user_home_t s0))
686 :eg-result t)
687 (set-file-acl
688 :no-eval (set-file-acl "/tmp/foo" "group::rxx")
689 :eg-result t))
690
691(define-short-documentation-group hash-table
692 "Hash Table Basics"
693 (make-hash-table
694 :no-eval (make-hash-table)
695 :result-string "#s(hash-table ...)")
696 (puthash
697 :no-eval (puthash 'key "value" table))
698 (gethash
699 :no-eval (gethash 'key table)
700 :eg-result "value")
701 (remhash
702 :no-eval (remhash 'key table)
703 :result nil)
704 (clrhash
705 :no-eval (clrhash table)
706 :result-string "#s(hash-table ...)")
707 (maphash
708 :no-eval (maphash (lambda (key value) (message value)) table)
709 :result nil)
710 "Other Hash Table Functions"
711 (hash-table-p
712 :eval (hash-table-p 123))
713 (hash-table-contains-p
714 :no-eval (hash-table-contains-p 'key table))
715 (copy-hash-table
716 :no-eval (copy-hash-table table)
717 :result-string "#s(hash-table ...)")
718 (hash-table-count
719 :no-eval (hash-table-count table)
720 :eg-result 15))
721
722(define-short-documentation-group list
723 "Making Lists"
724 (make-list
725 :eval (make-list 5 'a))
726 (cons
727 :eval (cons 1 '(2 3 4)))
728 (list
729 :eval (list 1 2 3))
730 (number-sequence
731 :eval (number-sequence 5 8))
732 (ensure-list
733 :eval (ensure-list "foo")
734 :eval (ensure-list '(1 2 3))
735 :eval (ensure-list '(1 . 2)))
736 (ensure-proper-list
737 :eval (ensure-proper-list "foo")
738 :eval (ensure-proper-list '(1 2 3))
739 :eval (ensure-proper-list '(1 . 2)))
740 "Operations on Lists"
741 (append
742 :eval (append '("foo" "bar") '("zot")))
743 (copy-tree
744 :eval (copy-tree '(1 (2 3) 4)))
745 (flatten-tree
746 :eval (flatten-tree '(1 (2 3) 4)))
747 (car
748 :eval (car '(one two three))
749 :eval (car '(one . two))
750 :eval (car nil))
751 (cdr
752 :eval (cdr '(one two three))
753 :eval (cdr '(one . two))
754 :eval (cdr nil))
755 (last
756 :eval (last '(one two three)))
757 (butlast
758 :eval (butlast '(one two three)))
759 (nbutlast
760 :eval (nbutlast (list 'one 'two 'three)))
761 (nth
762 :eval (nth 1 '(one two three)))
763 (nthcdr
764 :eval (nthcdr 1 '(one two three)))
765 (take
766 :eval (take 3 '(one two three four)))
767 (ntake
768 :eval (ntake 3 (list 'one 'two 'three 'four)))
769 (take-while
770 :eval (take-while #'numberp '(1 2 three 4 five)))
771 (drop-while
772 :eval (drop-while #'numberp '(1 2 three 4 five)))
773 (any
774 :eval (any #'symbolp '(1 2 three 4 five)))
775 (all
776 :eval (all #'symbolp '(one 2 three))
777 :eval (all #'symbolp '(one two three)))
778 (elt
779 :eval (elt '(one two three) 1))
780 (car-safe
781 :eval (car-safe '(one two three)))
782 (cdr-safe
783 :eval (cdr-safe '(one two three)))
784 (push
785 :no-eval* (push 'a list))
786 (pop
787 :no-eval* (pop list))
788 (setcar
789 :no-eval (setcar list 'c)
790 :result c)
791 (setcdr
792 :no-eval (setcdr list (list c))
793 :result '(c))
794 (nconc
795 :eval (nconc (list 1) (list 2 3 4)))
796 (delq
797 :eval (delq 'a (list 'a 'b 'c 'd)))
798 (delete
799 :eval (delete 2 (list 1 2 3 4))
800 :eval (delete "a" (list "a" "b" "c" "d")))
801 (remq
802 :eval (remq 'b '(a b c)))
803 (remove
804 :eval (remove 2 '(1 2 3 4))
805 :eval (remove "a" '("a" "b" "c" "d")))
806 (delete-dups
807 :eval (delete-dups (list 1 2 4 3 2 4)))
808 "Mapping Over Lists"
809 (mapcar
810 :eval (mapcar #'list '(1 2 3)))
811 (mapcan
812 :eval (mapcan #'list '(1 2 3)))
813 (mapc
814 :eval (mapc #'insert '("1" "2" "3")))
815 (seq-reduce
816 :eval (seq-reduce #'+ '(1 2 3) 0))
817 (mapconcat
818 :eval (mapconcat #'identity '("foo" "bar") "|"))
819 "Predicates"
820 (listp
821 :eval (listp '(1 2 3))
822 :eval (listp nil)
823 :eval (listp '(1 . 2)))
824 (consp
825 :eval (consp '(1 2 3))
826 :eval (consp nil))
827 (proper-list-p
828 :eval (proper-list-p '(1 2 3))
829 :eval (proper-list-p nil)
830 :eval (proper-list-p '(1 . 2)))
831 (null
832 :eval (null nil))
833 (atom
834 :eval (atom 'a))
835 (nlistp
836 :eval (nlistp '(1 2 3))
837 :eval (nlistp t)
838 :eval (nlistp '(1 . 2)))
839 "Finding Elements"
840 (memq
841 :eval (memq 'b '(a b c)))
842 (memql
843 :eval (memql 2.0 '(1.0 2.0 3.0)))
844 (member
845 :eval (member 2 '(1 2 3))
846 :eval (member "b" '("a" "b" "c")))
847 (member-ignore-case
848 :eval (member-ignore-case "foo" '("bar" "Foo" "zot")))
849 "Association Lists"
850 (assoc
851 :eval (assoc "b" '(("a" . 1) ("b" . 2))))
852 (rassoc
853 :eval (rassoc "b" '((1 . "a") (2 . "b"))))
854 (assq
855 :eval (assq 'b '((a . 1) (b . 2))))
856 (rassq
857 :eval (rassq 'b '((1 . a) (2 . b))))
858 (assoc-string
859 :eval (assoc-string "foo" '(("a" 1) (foo 2))))
860 (alist-get
861 :eval (alist-get 2 '((1 . a) (2 . b))))
862 (assoc-default
863 :eval (assoc-default 2 '((1 . a) (2 . b) #'=)))
864 (copy-alist
865 :eval (copy-alist '((1 . a) (2 . b))))
866 (assoc-delete-all
867 :eval (assoc-delete-all "b" (list '("a" . a) '("b" . b) '("b" . c))))
868 (assq-delete-all
869 :eval (assq-delete-all 2 (list '(1 . a) '(2 . b) '(2 . c))))
870 (rassq-delete-all
871 :eval (rassq-delete-all 'b (list '(1 . a) '(2 . b) '(2 . c))))
872 "Property Lists"
873 (plist-get
874 :eval (plist-get '(a 1 b 2 c 3) 'b))
875 (plist-put
876 :no-eval (setq plist (plist-put plist 'd 4))
877 :eg-result (a 1 b 2 c 3 d 4))
878 (plist-member
879 :eval (plist-member '(a 1 b 2 c 3) 'b))
880 "Data About Lists"
881 (length
882 :eval (length '(a b c)))
883 (length<
884 :eval (length< '(a b c) 1))
885 (length>
886 :eval (length> '(a b c) 1))
887 (length=
888 :eval (length= '(a b c) 3))
889 (safe-length
890 :eval (safe-length '(a b c))))
891
892(define-short-documentation-group symbol
893 "Making symbols"
894 (intern
895 :eval (intern "abc"))
896 (intern-soft
897 :eval (intern-soft "list")
898 :eval (intern-soft "Phooey!"))
899 (make-symbol
900 :eval (make-symbol "abc"))
901 (gensym
902 :no-eval (gensym)
903 :eg-result g37)
904 "Comparing symbols"
905 (eq
906 :eval (eq 'abc 'abc)
907 :eval (eq 'abc 'abd))
908 (eql
909 :eval (eql 'abc 'abc))
910 (equal
911 :eval (equal 'abc 'abc))
912 "Name"
913 (symbol-name
914 :eval (symbol-name 'abc))
915 "Obarrays"
916 (obarray-make
917 :eval (obarray-make))
918 (obarrayp
919 :eval (obarrayp (obarray-make))
920 :eval (obarrayp nil))
921 (unintern
922 :no-eval (unintern "abc" my-obarray)
923 :eg-result t)
924 (mapatoms
925 :no-eval (mapatoms (lambda (symbol) (print symbol)) my-obarray))
926 (obarray-clear
927 :no-eval (obarray-clear my-obarray)))
928
929(define-short-documentation-group comparison
930 "General-purpose"
931 (eq
932 :eval (eq 'a 'a)
933 :eval "(eq ?A ?A)"
934 :eval (let ((x (list 'a "b" '(c) 4 5.0)))
935 (eq x x)))
936 (eql
937 :eval (eql 2 2)
938 :eval (eql 2.0 2.0)
939 :eval (eql 2.0 2))
940 (equal
941 :eval (equal "abc" "abc")
942 :eval (equal 2.0 2.0)
943 :eval (equal 2.0 2)
944 :eval (equal '(a "b" (c) 4.0) '(a "b" (c) 4.0)))
945 (cl-equalp
946 :eval (cl-equalp 2 2.0)
947 :eval (cl-equalp "ABC" "abc"))
948 "Numeric"
949 (=
950 :args (number &rest numbers)
951 :eval (= 2 2)
952 :eval (= 2.0 2.0)
953 :eval (= 2.0 2)
954 :eval (= 4 4 4 4))
955 (/=
956 :eval (/= 4 4))
957 (<
958 :args (number &rest numbers)
959 :eval (< 4 4)
960 :eval (< 1 2 3))
961 (<=
962 :args (number &rest numbers)
963 :eval (<= 4 4)
964 :eval (<= 1 2 2 3))
965 (>
966 :args (number &rest numbers)
967 :eval (> 4 4)
968 :eval (> 3 2 1))
969 (>=
970 :args (number &rest numbers)
971 :eval (>= 4 4)
972 :eval (>= 3 2 2 1))
973 "String"
974 (string-equal
975 :eval (string-equal "abc" "abc")
976 :eval (string-equal "abc" "ABC"))
977 (string-equal-ignore-case
978 :eval (string-equal-ignore-case "abc" "ABC"))
979 (string-lessp
980 :eval (string-lessp "abc" "abd")
981 :eval (string-lessp "abc" "abc")
982 :eval (string-lessp "pic4.png" "pic32.png"))
983 (string-greaterp
984 :eval (string-greaterp "abd" "abc")
985 :eval (string-greaterp "abc" "abc"))
986 (string-version-lessp
987 :eval (string-version-lessp "pic4.png" "pic32.png")
988 :eval (string-version-lessp "1.9.3" "1.10.2"))
989 (string-collate-lessp
990 :eval (string-collate-lessp "abc" "abd")))
991
992(define-short-documentation-group vector
993 "Making Vectors"
994 (make-vector
995 :eval (make-vector 5 "foo"))
996 (vector
997 :eval (vector 1 "b" 3))
998 "Operations on Vectors"
999 (vectorp
1000 :eval (vectorp [1])
1001 :eval (vectorp "1"))
1002 (vconcat
1003 :eval (vconcat '(1 2) [3 4]))
1004 (append
1005 :eval (append [1 2] nil))
1006 (length
1007 :eval (length [1 2 3]))
1008 (seq-reduce
1009 :eval (seq-reduce #'+ [1 2 3] 0))
1010 (seq-subseq
1011 :eval (seq-subseq [1 2 3 4 5] 1 3)
1012 :eval (seq-subseq [1 2 3 4 5] 1))
1013 (copy-tree
1014 :eval (copy-tree [1 (2 3) [4 5]] t))
1015 "Mapping Over Vectors"
1016 (mapcar
1017 :eval (mapcar #'identity [1 2 3]))
1018 (mapc
1019 :eval (mapc #'insert ["1" "2" "3"])))
1020
1021(define-short-documentation-group regexp
1022 "Matching Strings"
1023 (replace-regexp-in-string
1024 :eval (replace-regexp-in-string "[a-z]+" "_" "*foo*"))
1025 (string-match-p
1026 :eval (string-match-p "^[fo]+" "foobar"))
1027 "Looking in Buffers"
1028 (re-search-forward
1029 :no-eval (re-search-forward "^foo$" nil t)
1030 :eg-result 43)
1031 (re-search-backward
1032 :no-eval (re-search-backward "^foo$" nil t)
1033 :eg-result 43)
1034 (looking-at-p
1035 :no-eval (looking-at-p "f[0-9]")
1036 :eg-result t)
1037 "Match Data"
1038 (match-string
1039 :eval (and (string-match "^\\([fo]+\\)b" "foobar")
1040 (match-string 0 "foobar")))
1041 (match-beginning
1042 :no-eval (match-beginning 1)
1043 :eg-result 0)
1044 (match-end
1045 :no-eval (match-end 1)
1046 :eg-result 3)
1047 (save-match-data
1048 :no-eval (save-match-data ...))
1049 "Replacing Match"
1050 (replace-match
1051 :no-eval (replace-match "new")
1052 :eg-result nil)
1053 (match-substitute-replacement
1054 :no-eval (match-substitute-replacement "new")
1055 :eg-result "new")
1056 (replace-regexp-in-region
1057 :no-value (replace-regexp-in-region "[0-9]+" "Num \\&"))
1058 "Utilities"
1059 (regexp-quote
1060 :eval (regexp-quote "foo.*bar"))
1061 (regexp-opt
1062 :eval (regexp-opt '("foo" "bar")))
1063 (regexp-opt-depth
1064 :eval (regexp-opt-depth "\\(a\\(b\\)\\)"))
1065 (regexp-opt-charset
1066 :eval (regexp-opt-charset '(?a ?b ?c ?d ?e)))
1067 "The `rx' Structured Regexp Notation"
1068 (rx
1069 :eval (rx "IP=" (+ digit) (= 3 "." (+ digit))))
1070 (rx-to-string
1071 :eval (rx-to-string '(| "foo" "bar")))
1072 (rx-define
1073 :no-eval "(and (rx-define haskell-comment (seq \"--\" (zero-or-more nonl)))
1074 (rx haskell-comment))"
1075 :result "--.*")
1076 (rx-let
1077 :eval "(rx-let ((comma-separated (item) (seq item (0+ \",\" item)))
1078 (number (1+ digit))
1079 (numbers (comma-separated number)))
1080 (rx \"(\" numbers \")\"))"
1081 :result "([[:digit:]]+\\(?:,[[:digit:]]+\\)*)")
1082 (rx-let-eval
1083 :eval "(rx-let-eval
1084 '((ponder (x) (seq \"Where have all the \" x \" gone?\")))
1085 (rx-to-string
1086 '(ponder (or \"flowers\" \"cars\" \"socks\"))))"
1087 :result "\\(?:Where have all the \\(?:\\(?:car\\|flower\\|sock\\)s\\) gone\\?\\)"))
1088
1089(define-short-documentation-group sequence
1090 "Sequence Predicates"
1091 (seq-contains-p
1092 :eval (seq-contains-p '(a b c) 'b)
1093 :eval (seq-contains-p '(a b c) 'd))
1094 (seq-every-p
1095 :eval (seq-every-p #'numberp '(1 2 3)))
1096 (seq-empty-p
1097 :eval (seq-empty-p []))
1098 (seq-set-equal-p
1099 :eval (seq-set-equal-p '(1 2 3) '(3 1 2)))
1100 (seq-some
1101 :eval (seq-some #'floatp '(1 2.0 3)))
1102 "Building Sequences"
1103 (seq-concatenate
1104 :eval (seq-concatenate 'vector '(1 2) '(c d)))
1105 (seq-copy
1106 :eval (seq-copy '(a 2)))
1107 (seq-into
1108 :eval (seq-into '(1 2 3) 'vector))
1109 "Utility Functions"
1110 (seq-count
1111 :eval (seq-count #'numberp '(1 b c 4)))
1112 (seq-elt
1113 :eval (seq-elt '(a b c) 1))
1114 (seq-random-elt
1115 :no-eval (seq-random-elt '(a b c))
1116 :eg-result c)
1117 (seq-find
1118 :eval (seq-find #'numberp '(a b 3 4 f 6)))
1119 (seq-position
1120 :eval (seq-position '(a b c) 'c))
1121 (seq-positions
1122 :eval (seq-positions '(a b c a d) 'a)
1123 :eval (seq-positions '(a b c a d) 'z)
1124 :eval (seq-positions '(11 5 7 12 9 15) 10 #'>=))
1125 (seq-length
1126 :eval (seq-length "abcde"))
1127 (seq-max
1128 :eval (seq-max [1 2 3]))
1129 (seq-min
1130 :eval (seq-min [1 2 3]))
1131 (seq-first
1132 :eval (seq-first [a b c]))
1133 (seq-rest
1134 :eval (seq-rest '[1 2 3]))
1135 (seq-reverse
1136 :eval (seq-reverse '(1 2 3)))
1137 (seq-sort
1138 :eval (seq-sort #'> '(1 2 3)))
1139 (seq-sort-by
1140 :eval (seq-sort-by (lambda (a) (/ 1.0 a)) #'< '(1 2 3)))
1141 "Mapping Over Sequences"
1142 (seq-map
1143 :eval (seq-map #'1+ '(1 2 3)))
1144 (seq-map-indexed
1145 :eval (seq-map-indexed (lambda (a i) (cons i a)) '(a b c)))
1146 (seq-mapcat
1147 :eval (seq-mapcat #'upcase '("a" "b" "c") 'string))
1148 (seq-doseq
1149 :no-eval (seq-doseq (a '("foo" "bar")) (insert a))
1150 :eg-result ("foo" "bar"))
1151 (seq-do
1152 :no-eval (seq-do (lambda (a) (insert a)) '("foo" "bar"))
1153 :eg-result ("foo" "bar"))
1154 (seq-do-indexed
1155 :no-eval (seq-do-indexed
1156 (lambda (a index) (message "%s:%s" index a))
1157 '("foo" "bar"))
1158 :eg-result nil)
1159 (seq-reduce
1160 :eval (seq-reduce #'* [1 2 3] 2))
1161 "Excerpting Sequences"
1162 (seq-drop
1163 :eval (seq-drop '(a b c) 2))
1164 (seq-drop-while
1165 :eval (seq-drop-while #'numberp '(1 2 c d 5)))
1166 (seq-filter
1167 :eval (seq-filter #'numberp '(a b 3 4 f 6)))
1168 (seq-keep
1169 :eval (seq-keep #'car-safe '((1 2) 3 t (a . b))))
1170 (seq-remove
1171 :eval (seq-remove #'numberp '(1 2 c d 5)))
1172 (seq-remove-at-position
1173 :eval (seq-remove-at-position '(a b c d e) 3)
1174 :eval (seq-remove-at-position [a b c d e] 0))
1175 (seq-group-by
1176 :eval (seq-group-by #'natnump '(-1 2 3 -4 -5 6)))
1177 (seq-union
1178 :eval (seq-union '(1 2 3) '(3 5)))
1179 (seq-difference
1180 :eval (seq-difference '(1 2 3) '(2 3 4)))
1181 (seq-intersection
1182 :eval (seq-intersection '(1 2 3) '(2 3 4)))
1183 (seq-partition
1184 :eval (seq-partition '(a b c d e f g h) 3))
1185 (seq-subseq
1186 :eval (seq-subseq '(a b c d e) 2 4))
1187 (seq-take
1188 :eval (seq-take '(a b c d e) 3))
1189 (seq-split
1190 :eval (seq-split [0 1 2 3 5] 2))
1191 (seq-take-while
1192 :eval (seq-take-while #'integerp [1 2 3.0 4]))
1193 (seq-uniq
1194 :eval (seq-uniq '(a b d b a c))))
1195
1196(define-short-documentation-group buffer
1197 "Buffer Basics"
1198 (current-buffer
1199 :no-eval (current-buffer)
1200 :eg-result-string "#<buffer shortdoc.el>")
1201 (bufferp
1202 :eval (bufferp 23))
1203 (buffer-live-p
1204 :no-eval (buffer-live-p some-buffer)
1205 :eg-result t)
1206 (buffer-modified-p
1207 :eval (buffer-modified-p (current-buffer)))
1208 (buffer-name
1209 :eval (buffer-name))
1210 (window-buffer
1211 :eval (window-buffer))
1212 "Selecting Buffers"
1213 (get-buffer-create
1214 :no-eval (get-buffer-create "*foo*")
1215 :eg-result-string "#<buffer *foo*>")
1216 (pop-to-buffer
1217 :no-eval (pop-to-buffer "*foo*")
1218 :eg-result-string "#<buffer *foo*>")
1219 (with-current-buffer
1220 :no-eval* (with-current-buffer buffer (buffer-size)))
1221 "Points and Positions"
1222 (point
1223 :eval (point))
1224 (point-min
1225 :eval (point-min))
1226 (point-max
1227 :eval (point-max))
1228 (pos-bol
1229 :eval (pos-bol))
1230 (pos-eol
1231 :eval (pos-eol))
1232 (bolp
1233 :eval (bolp))
1234 (eolp
1235 :eval (eolp))
1236 (line-beginning-position
1237 :eval (line-beginning-position))
1238 (line-end-position
1239 :eval (line-end-position))
1240 (buffer-size
1241 :eval (buffer-size))
1242 (bobp
1243 :eval (bobp))
1244 (eobp
1245 :eval (eobp))
1246 "Moving Around"
1247 (goto-char
1248 :no-eval (goto-char (point-max))
1249 :eg-result 342)
1250 (search-forward
1251 :no-eval (search-forward "some-string" nil t)
1252 :eg-result 245)
1253 (re-search-forward
1254 :no-eval (re-search-forward "some-s.*g" nil t)
1255 :eg-result 245)
1256 (forward-line
1257 :no-eval (forward-line 1)
1258 :eg-result 0
1259 :no-eval (forward-line -2)
1260 :eg-result 0)
1261 "Strings from Buffers"
1262 (buffer-string
1263 :no-eval* (buffer-string))
1264 (buffer-substring
1265 :eval (buffer-substring (point-min) (+ (point-min) 10)))
1266 (buffer-substring-no-properties
1267 :eval (buffer-substring-no-properties (point-min) (+ (point-min) 10)))
1268 (following-char
1269 :no-eval (following-char)
1270 :eg-result 67)
1271 (preceding-char
1272 :no-eval (preceding-char)
1273 :eg-result 38)
1274 (char-after
1275 :eval (char-after 45))
1276 (char-before
1277 :eval (char-before 13))
1278 (get-byte
1279 :no-eval (get-byte 45)
1280 :eg-result-string "#xff")
1281 "Altering Buffers"
1282 (delete-region
1283 :no-value (delete-region (point-min) (point-max)))
1284 (erase-buffer
1285 :no-value (erase-buffer))
1286 (delete-line
1287 :no-value (delete-line))
1288 (insert
1289 :no-value (insert "This string will be inserted in the buffer\n"))
1290 (subst-char-in-region
1291 :no-eval "(subst-char-in-region (point-min) (point-max) ?+ ?-)")
1292 (replace-string-in-region
1293 :no-value (replace-string-in-region "foo" "bar"))
1294 "Locking"
1295 (lock-buffer
1296 :no-value (lock-buffer "/tmp/foo"))
1297 (unlock-buffer
1298 :no-value (unlock-buffer)))
1299
1300(define-short-documentation-group overlay
1301 "Predicates"
1302 (overlayp
1303 :no-eval (overlayp some-overlay)
1304 :eg-result t)
1305 "Creation and Deletion"
1306 (make-overlay
1307 :args (beg end &optional buffer)
1308 :no-eval (make-overlay 1 10)
1309 :eg-result-string "#<overlay from 1 to 10 in *foo*>")
1310 (delete-overlay
1311 :no-eval (delete-overlay foo)
1312 :eg-result t)
1313 "Searching Overlays"
1314 (overlays-at
1315 :no-eval (overlays-at 15)
1316 :eg-result-string "(#<overlay from 1 to 10 in *foo*>)")
1317 (overlays-in
1318 :no-eval (overlays-in 1 30)
1319 :eg-result-string "(#<overlay from 1 to 10 in *foo*>)")
1320 (next-overlay-change
1321 :no-eval (next-overlay-change 1)
1322 :eg-result 20)
1323 (previous-overlay-change
1324 :no-eval (previous-overlay-change 30)
1325 :eg-result 20)
1326 "Overlay Properties"
1327 (overlay-start
1328 :no-eval (overlay-start foo)
1329 :eg-result 1)
1330 (overlay-end
1331 :no-eval (overlay-end foo)
1332 :eg-result 10)
1333 (overlay-put
1334 :no-eval (overlay-put foo 'happy t)
1335 :eg-result t)
1336 (overlay-get
1337 :no-eval (overlay-get foo 'happy)
1338 :eg-result t)
1339 (overlay-buffer
1340 :no-eval (overlay-buffer foo))
1341 "Moving Overlays"
1342 (move-overlay
1343 :no-eval (move-overlay foo 5 20)
1344 :eg-result-string "#<overlay from 5 to 20 in *foo*>"))
1345
1346(define-short-documentation-group process
1347 (make-process
1348 :no-eval (make-process :name "foo" :command '("cat" "/tmp/foo"))
1349 :eg-result-string "#<process foo>")
1350 (processp
1351 :eval (processp t))
1352 (process-status
1353 :no-eval (process-status process)
1354 :eg-result exit)
1355 (delete-process
1356 :no-value (delete-process process))
1357 (kill-process
1358 :no-value (kill-process process))
1359 (set-process-sentinel
1360 :no-value (set-process-sentinel process (lambda (proc string))))
1361 (process-buffer
1362 :no-eval (process-buffer process)
1363 :eg-result-string "#<buffer *foo*>")
1364 (get-buffer-process
1365 :no-eval (get-buffer-process buffer)
1366 :eg-result-string "#<process foo>")
1367 (process-live-p
1368 :no-eval (process-live-p process)
1369 :eg-result t))
1370
1371(define-short-documentation-group number
1372 "Arithmetic"
1373 (+
1374 :args (&rest numbers)
1375 :eval (+ 1 2)
1376 :eval (+ 1 2 3 4))
1377 (-
1378 :args (&rest numbers)
1379 :eval (- 3 2)
1380 :eval (- 6 3 2))
1381 (*
1382 :args (&rest numbers)
1383 :eval (* 3 4 5))
1384 (/
1385 :eval (/ 10 5)
1386 :eval (/ 10 6)
1387 :eval (/ 10.0 6)
1388 :eval (/ 10.0 3 3))
1389 (%
1390 :eval (% 10 5)
1391 :eval (% 10 6))
1392 (mod
1393 :eval (mod 10 5)
1394 :eval (mod 10 6)
1395 :eval (mod 10.5 6))
1396 (1+
1397 :eval (1+ 2)
1398 :eval (let ((x 2)) (1+ x) x))
1399 (1-
1400 :eval (1- 4)
1401 :eval (let ((x 4)) (1- x) x))
1402 (incf
1403 :eval (let ((x 2)) (incf x) x)
1404 :eval (let ((x 2)) (incf x 2) x))
1405 (decf
1406 :eval (let ((x 4)) (decf x) x)
1407 :eval (let ((x 4)) (decf x 2)) x)
1408 "Predicates"
1409 (=
1410 :args (number &rest numbers)
1411 :eval (= 4 4)
1412 :eval (= 4.0 4.0)
1413 :eval (= 4 4.0)
1414 :eval (= 4 4 4 4))
1415 (eql
1416 :eval (eql 4 4)
1417 :eval (eql 4.0 4.0))
1418 (/=
1419 :eval (/= 4 4))
1420 (<
1421 :args (number &rest numbers)
1422 :eval (< 4 4)
1423 :eval (< 1 2 3))
1424 (<=
1425 :args (number &rest numbers)
1426 :eval (<= 4 4)
1427 :eval (<= 1 2 2 3))
1428 (>
1429 :args (number &rest numbers)
1430 :eval (> 4 4)
1431 :eval (> 3 2 1))
1432 (>=
1433 :args (number &rest numbers)
1434 :eval (>= 4 4)
1435 :eval (>= 3 2 2 1))
1436 (zerop
1437 :eval (zerop 0))
1438 (natnump
1439 :eval (natnump -1)
1440 :eval (natnump 0)
1441 :eval (natnump 23))
1442 (plusp
1443 :eval (plusp 0)
1444 :eval (plusp 1))
1445 (minusp
1446 :eval (minusp 0)
1447 :eval (minusp -1))
1448 (oddp
1449 :eval (oddp 3))
1450 (evenp
1451 :eval (evenp 6))
1452 (bignump
1453 :eval (bignump 4)
1454 :eval (bignump (expt 2 90)))
1455 (fixnump
1456 :eval (fixnump 4)
1457 :eval (fixnump (expt 2 90)))
1458 (floatp
1459 :eval (floatp 5.4))
1460 (integerp
1461 :eval (integerp 5.4))
1462 (numberp
1463 :eval (numberp "5.4"))
1464 (cl-digit-char-p
1465 :eval (cl-digit-char-p ?5 10)
1466 :eval (cl-digit-char-p ?f 16))
1467 "Operations"
1468 (max
1469 :args (number &rest numbers)
1470 :eval (max 7 9 3))
1471 (min
1472 :args (number &rest numbers)
1473 :eval (min 7 9 3))
1474 (abs
1475 :eval (abs -4))
1476 (float
1477 :eval (float 2))
1478 (truncate
1479 :eval (truncate 1.2)
1480 :eval (truncate -1.2)
1481 :eval (truncate 5.4 2))
1482 (floor
1483 :eval (floor 1.2)
1484 :eval (floor -1.2)
1485 :eval (floor 5.4 2))
1486 (ceiling
1487 :eval (ceiling 1.2)
1488 :eval (ceiling -1.2)
1489 :eval (ceiling 5.4 2))
1490 (round
1491 :eval (round 1.2)
1492 :eval (round -1.2)
1493 :eval (round 5.4 2))
1494 (random
1495 :eval (random 6))
1496 "Bit Operations"
1497 (ash
1498 :eval (ash 1 4)
1499 :eval (ash 16 -1))
1500 (logand
1501 :no-eval "(logand #b10 #b111)"
1502 :result-string "#b10")
1503 (logior
1504 :eval (logior 4 16))
1505 (logxor
1506 :eval (logxor 4 16))
1507 (lognot
1508 :eval (lognot 5))
1509 (logcount
1510 :eval (logcount 5))
1511 "Floating Point"
1512 (isnan
1513 :eval (isnan 5.0))
1514 (frexp
1515 :eval (frexp 5.7))
1516 (ldexp
1517 :eval (ldexp 0.7125 3))
1518 (logb
1519 :eval (logb 10.5))
1520 (ffloor
1521 :eval (ffloor 1.2))
1522 (fceiling
1523 :eval (fceiling 1.2))
1524 (ftruncate
1525 :eval (ftruncate 1.2))
1526 (fround
1527 :eval (fround 1.2))
1528 "Standard Math Functions"
1529 (sin
1530 :eval (sin float-pi))
1531 (cos
1532 :eval (cos float-pi))
1533 (tan
1534 :eval (tan float-pi))
1535 (asin
1536 :eval (asin float-pi))
1537 (acos
1538 :eval (acos float-pi))
1539 (atan
1540 :eval (atan float-pi))
1541 (exp
1542 :eval (exp 4))
1543 (log
1544 :eval (log 54.59))
1545 (expt
1546 :eval (expt 2 16))
1547 (sqrt
1548 :eval (sqrt -1)))
1549
1550(define-short-documentation-group text-properties
1551 "Examining Text Properties"
1552 (get-text-property
1553 :eval (get-text-property 0 'foo (propertize "x" 'foo t)))
1554 (get-char-property
1555 :eval (get-char-property 0 'foo (propertize "x" 'foo t)))
1556 (get-pos-property
1557 :eval (get-pos-property 0 'foo (propertize "x" 'foo t)))
1558 (get-char-property-and-overlay
1559 :eval (get-char-property-and-overlay 0 'foo (propertize "x" 'foo t)))
1560 (text-properties-at
1561 :eval (text-properties-at (point)))
1562 "Changing Text Properties"
1563 (put-text-property
1564 :eval (let ((s (copy-sequence "abc"))) (put-text-property 0 1 'foo t s) s)
1565 :no-eval (put-text-property (point) (1+ (point)) 'face 'error))
1566 (add-text-properties
1567 :no-eval (add-text-properties (point) (1+ (point)) '(face error)))
1568 (remove-text-properties
1569 :no-eval (remove-text-properties (point) (1+ (point)) '(face nil)))
1570 (remove-list-of-text-properties
1571 :no-eval (remove-list-of-text-properties (point) (1+ (point)) '(face font-lock-face)))
1572 (set-text-properties
1573 :no-eval (set-text-properties (point) (1+ (point)) '(face error)))
1574 (add-face-text-property
1575 :no-eval (add-face-text-property START END '(:foreground "green")))
1576 (propertize
1577 :eval (propertize "foo" 'face 'italic 'mouse-face 'bold-italic))
1578 "Searching for Text Properties"
1579 (next-property-change
1580 :no-eval (next-property-change (point) (current-buffer)))
1581 (previous-property-change
1582 :no-eval (previous-property-change (point) (current-buffer)))
1583 (next-single-property-change
1584 :no-eval (next-single-property-change (point) 'face (current-buffer)))
1585 (previous-single-property-change
1586 :no-eval (previous-single-property-change (point) 'face (current-buffer)))
1587 ;; TODO: There are some more that could be added here.
1588 (text-property-search-forward
1589 :no-eval (text-property-search-forward 'face nil t))
1590 (text-property-search-backward
1591 :no-eval (text-property-search-backward 'face nil t)))
1592
1593(define-short-documentation-group keymaps
1594 "Defining keymaps or adding bindings to existing keymaps"
1595 (define-keymap
1596 :no-eval (define-keymap "C-c C-c" #'quit-buffer)
1597 :no-eval (define-keymap :keymap ctl-x-map
1598 "C-r" #'recentf-open
1599 "k" #'kill-current-buffer))
1600 (defvar-keymap
1601 :no-eval (defvar-keymap my-keymap "C-c C-c" #'quit-buffer))
1602 "Setting keys"
1603 (keymap-set
1604 :no-eval (keymap-set map "C-c C-c" #'quit-buffer))
1605 (keymap-local-set
1606 :no-eval (keymap-local-set "C-c C-c" #'quit-buffer))
1607 (keymap-global-set
1608 :no-eval (keymap-global-set "C-c C-c" #'quit-buffer))
1609 (keymap-unset
1610 :no-eval (keymap-unset map "C-c C-c"))
1611 (keymap-local-unset
1612 :no-eval (keymap-local-unset "C-c C-c"))
1613 (keymap-global-unset
1614 :no-eval (keymap-global-unset "C-c C-c"))
1615 (keymap-substitute
1616 :no-eval (keymap-substitute map "C-c C-c" "M-a"))
1617 (keymap-set-after
1618 :no-eval (keymap-set-after map "<separator-2>" menu-bar-separator))
1619 "Predicates"
1620 (keymapp
1621 :eval (keymapp (define-keymap)))
1622 (key-valid-p
1623 :eval (key-valid-p "C-c C-c")
1624 :eval (key-valid-p "C-cC-c"))
1625 "Lookup"
1626 (keymap-lookup
1627 :eval (keymap-lookup (current-global-map) "C-x x g")))
1628
1629;;;###autoload 239;;;###autoload
1630(defun shortdoc-display-group (group &optional function same-window) 240(defun shortdoc-display-group (group &optional function same-window)
1631 "Pop to a buffer with short documentation summary for functions in GROUP. 241 "Pop to a buffer with short documentation summary for functions in GROUP.
@@ -1650,6 +260,9 @@ If SAME-WINDOW, don't pop to a new window."
1650 (text-property-search-forward 'shortdoc-function function t) 260 (text-property-search-forward 'shortdoc-function function t)
1651 (beginning-of-line))) 261 (beginning-of-line)))
1652 262
263;;;###autoload
264(defalias 'shortdoc #'shortdoc-display-group)
265
1653(defun shortdoc--insert-group-in-buffer (group &optional buf) 266(defun shortdoc--insert-group-in-buffer (group &optional buf)
1654 "Insert a short documentation summary for functions in GROUP in buffer BUF. 267 "Insert a short documentation summary for functions in GROUP in buffer BUF.
1655BUF defaults to the current buffer if nil or omitted." 268BUF defaults to the current buffer if nil or omitted."
@@ -1685,9 +298,6 @@ BUF defaults to the current buffer if nil or omitted."
1685 (shortdoc--display-function data)))) 298 (shortdoc--display-function data))))
1686 (cdr (assq group shortdoc--groups)))))) 299 (cdr (assq group shortdoc--groups))))))
1687 300
1688;;;###autoload
1689(defalias 'shortdoc #'shortdoc-display-group)
1690
1691(defun shortdoc--display-function (data) 301(defun shortdoc--display-function (data)
1692 (let ((function (pop data)) 302 (let ((function (pop data))
1693 (start-section (point)) 303 (start-section (point))
@@ -1875,6 +485,10 @@ Example:
1875 (shortdoc-add-function 485 (shortdoc-add-function
1876 \\='file \"Predicates\" 486 \\='file \"Predicates\"
1877 \\='(file-locked-p :no-eval (file-locked-p \"/tmp\")))" 487 \\='(file-locked-p :no-eval (file-locked-p \"/tmp\")))"
488 ;; Rely on `shortdoc--check' checking GROUP.
489 (unless (stringp section)
490 (signal 'wrong-type-argument (list 'stringp section)))
491 (shortdoc--check group (list section elem))
1878 (let ((glist (assq group shortdoc--groups))) 492 (let ((glist (assq group shortdoc--groups)))
1879 (unless glist 493 (unless glist
1880 (setq glist (list group)) 494 (setq glist (list group))
diff --git a/lisp/emacs-lisp/warnings.el b/lisp/emacs-lisp/warnings.el
index ddf3b594e12..7db316acda7 100644
--- a/lisp/emacs-lisp/warnings.el
+++ b/lisp/emacs-lisp/warnings.el
@@ -372,6 +372,7 @@ entirely by setting `warning-suppress-types' or
372 (if (bolp) 372 (if (bolp)
373 (forward-char -1)) 373 (forward-char -1))
374 (message "%s" (buffer-substring start (point)))))) 374 (message "%s" (buffer-substring start (point))))))
375 ;; Use `frame-initial-p'?
375 ((and (daemonp) (eq (selected-frame) terminal-frame)) 376 ((and (daemonp) (eq (selected-frame) terminal-frame))
376 ;; Display daemon startup warnings on the first client frame. 377 ;; Display daemon startup warnings on the first client frame.
377 (letrec ((afterfun 378 (letrec ((afterfun
diff --git a/lisp/epa-file.el b/lisp/epa-file.el
index b2a89907867..95202851544 100644
--- a/lisp/epa-file.el
+++ b/lisp/epa-file.el
@@ -232,7 +232,22 @@ encryption is used."
232 (epa-file-decode-and-insert 232 (epa-file-decode-and-insert
233 string file visit beg end replace)))) 233 string file visit beg end replace))))
234 (if visit 234 (if visit
235 (set-visited-file-modtime)))) 235 (set-visited-file-modtime)))
236 ;; The decoded file could still need another massage from a
237 ;; file name handler, for example a file like
238 ;; "folder.sym.tar.gz.gpg". (Bug#80641)
239 (when (find-file-name-handler
240 (file-name-sans-extension file)
241 'insert-file-contents)
242 (let ((tmpfile
243 (make-temp-file
244 nil nil
245 (file-name-extension (file-name-base file) 'period))))
246 (let (file-name-handler-alist) (write-region nil nil tmpfile))
247 (erase-buffer)
248 (insert-file-contents tmpfile)
249 (setq length (- (point-max) (point-min)))
250 (delete-file tmpfile))))
236 (if (and local-copy 251 (if (and local-copy
237 (file-exists-p local-copy)) 252 (file-exists-p local-copy))
238 (delete-file local-copy))) 253 (delete-file local-copy)))
diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el
index f5ea63ae764..6306df3fa2a 100644
--- a/lisp/erc/erc-track.el
+++ b/lisp/erc/erc-track.el
@@ -1006,7 +1006,7 @@ Failing that, choose the first face in both NEW-FACES and NORMALS."
1006 (dolist (candidate (cdr ranks)) 1006 (dolist (candidate (cdr ranks))
1007 (when (and (not (equal candidate choice)) 1007 (when (and (not (equal candidate choice))
1008 (gethash candidate (car new-faces)) 1008 (gethash candidate (car new-faces))
1009 (gethash choice normals)) 1009 (gethash candidate normals))
1010 (throw 'face candidate))) 1010 (throw 'face candidate)))
1011 ;; Otherwise, go with any "normal" face other than 1011 ;; Otherwise, go with any "normal" face other than
1012 ;; `choice' in the region. 1012 ;; `choice' in the region.
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 572b73188e3..6facb7966b0 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1693,11 +1693,18 @@ time `erc-mode-hook' runs for any connection."
1693 (declare (indent 1)) 1693 (declare (indent 1))
1694 (cl-assert (stringp (car args))) 1694 (cl-assert (stringp (car args)))
1695 (if (derived-mode-p 'erc-mode) 1695 (if (derived-mode-p 'erc-mode)
1696 (unless (or (erc-with-server-buffer ; needs `erc-server-process' 1696 (unless
1697 (apply #'erc-button--display-error-notice-with-keys 1697 (or (erc-with-server-buffer ; needs `erc-server-process'
1698 (current-buffer) args) 1698 (let ((fn
1699 t) 1699 (lambda (buffer)
1700 erc--target) ; unlikely 1700 (erc-with-buffer (buffer)
1701 (apply #'erc-button--display-error-notice-with-keys
1702 buffer args)))))
1703 (if erc--msg-props
1704 (run-at-time nil nil fn (current-buffer))
1705 (funcall fn (current-buffer))))
1706 t)
1707 erc--target) ; unlikely
1701 (let (hook) 1708 (let (hook)
1702 (setq hook 1709 (setq hook
1703 (lambda (_) 1710 (lambda (_)
diff --git a/lisp/files.el b/lisp/files.el
index f9af75187cb..e05a4b99497 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1790,7 +1790,10 @@ If DIR-FLAG is non-nil, create a new empty directory instead of a file.
1790If SUFFIX is non-nil, add that at the end of the file name. 1790If SUFFIX is non-nil, add that at the end of the file name.
1791 1791
1792If TEXT is a string, insert it into the new file; DIR-FLAG should be nil. 1792If TEXT is a string, insert it into the new file; DIR-FLAG should be nil.
1793Otherwise the file will be empty." 1793Otherwise the file will be empty.
1794
1795On Posix systems, the file/directory is created with access mode bits
1796that limit access to the current user."
1794 (let ((absolute-prefix 1797 (let ((absolute-prefix
1795 (if (or (zerop (length prefix)) (member prefix '("." ".."))) 1798 (if (or (zerop (length prefix)) (member prefix '("." "..")))
1796 (concat (file-name-as-directory temporary-file-directory) prefix) 1799 (concat (file-name-as-directory temporary-file-directory) prefix)
@@ -8320,41 +8323,24 @@ Valid wildcards are `*', `?', `[abc]' and `[a-z]'."
8320 (forward-line -1)) 8323 (forward-line -1))
8321 (if (let ((case-fold-search nil)) (looking-at "//DIRED//")) 8324 (if (let ((case-fold-search nil)) (looking-at "//DIRED//"))
8322 (let ((end (line-end-position)) 8325 (let ((end (line-end-position))
8323 (linebeg (point)) 8326 (linebeg (point)))
8324 error-lines) 8327 ;; Read the numeric positions of file names.
8325 ;; Find all the lines that are error messages,
8326 ;; and record the bounds of each one.
8327 (goto-char beg)
8328 (while (< (point) linebeg)
8329 (or (eql (following-char) ?\s)
8330 (push (list (point) (line-end-position)) error-lines))
8331 (forward-line 1))
8332 (setq error-lines (nreverse error-lines))
8333 ;; Now read the numeric positions of file names.
8334 (goto-char linebeg) 8328 (goto-char linebeg)
8335 (forward-word-strictly 1) 8329 (forward-word-strictly 1)
8336 (forward-char 3) 8330 (forward-char 3)
8337 (while (< (point) end) 8331 (while (< (point) end)
8338 (let ((start (insert-directory-adj-pos 8332 (let ((start (+ beg (read (current-buffer))))
8339 (+ beg (read (current-buffer))) 8333 (end (+ beg (read (current-buffer)))))
8340 error-lines)) 8334 (when (memq (char-after end) '(?\n ?\s ?/ ?* ?@ ?% ?= ?|))
8341 (end (insert-directory-adj-pos 8335 ;; End is followed by \n or by output of -F.
8342 (+ beg (read (current-buffer))) 8336 (put-text-property start end 'dired-filename t))))
8343 error-lines)))
8344 (if (memq (char-after end) '(?\n ?\s ?/ ?* ?@ ?% ?= ?|))
8345 ;; End is followed by \n or by output of -F.
8346 (put-text-property start end 'dired-filename t)
8347 ;; It seems that we can't trust ls's output as to
8348 ;; byte positions of filenames.
8349 (put-text-property beg (point) 'dired-filename nil)
8350 (end-of-line))))
8351 (goto-char end) 8337 (goto-char end)
8352 (beginning-of-line) 8338 (beginning-of-line)
8353 (delete-region (point) (progn (forward-line 1) (point)))) 8339 (delete-region (point) (progn (forward-line 1) (point))))
8354 ;; Take care of the case where the ls output contains a 8340 ;; Take care of the case where the ls output contains a
8355 ;; "//DIRED-OPTIONS//"-line, but no "//DIRED//"-line 8341 ;; "//DIRED-OPTIONS//"-line, but no "//DIRED//"-line
8356 ;; and we went one line too far back (see above). 8342 ;; and we went one line too far back (see above).
8357 (forward-line 1)) 8343 (unless (bobp) (forward-line 1)))
8358 (if (let ((case-fold-search nil)) (looking-at "//DIRED-OPTIONS//")) 8344 (if (let ((case-fold-search nil)) (looking-at "//DIRED-OPTIONS//"))
8359 (delete-region (point) (progn (forward-line 1) (point)))))) 8345 (delete-region (point) (progn (forward-line 1) (point))))))
8360 8346
@@ -8363,12 +8349,12 @@ Valid wildcards are `*', `?', `[abc]' and `[a-z]'."
8363;; FULL-DIRECTORY-P is nil. 8349;; FULL-DIRECTORY-P is nil.
8364;; The single line of output must display FILE's name as it was 8350;; The single line of output must display FILE's name as it was
8365;; given, namely, an absolute path name. 8351;; given, namely, an absolute path name.
8366;; - must insert exactly one line for each file if WILDCARD or 8352;; - must insert exactly one entry for each file if WILDCARD or
8367;; FULL-DIRECTORY-P is t, plus one optional "total" line 8353;; FULL-DIRECTORY-P is t, plus one optional "total" line
8368;; before the file lines, plus optional text after the file lines. 8354;; before the file lines, plus optional text after the file lines.
8369;; Lines are delimited by "\n", so filenames containing "\n" are not 8355;; Entries are delimited by "\n", but file names containing "\n" are
8370;; allowed. 8356;; allowed and by default the "\n" is displayed as a literal newline.
8371;; File lines should display the basename. 8357;; File entries should display the basename.
8372;; - must be consistent with 8358;; - must be consistent with
8373;; - functions dired-move-to-filename, (these two define what a file line is) 8359;; - functions dired-move-to-filename, (these two define what a file line is)
8374;; dired-move-to-end-of-filename, 8360;; dired-move-to-end-of-filename,
@@ -8410,10 +8396,10 @@ normally equivalent short `-D' option is just passed on to
8410 (declare-function ls-lisp--insert-directory "ls-lisp") 8396 (declare-function ls-lisp--insert-directory "ls-lisp")
8411 (ls-lisp--insert-directory file switches wildcard full-directory-p)) 8397 (ls-lisp--insert-directory file switches wildcard full-directory-p))
8412 (t 8398 (t
8413 (let (result (beg (point))) 8399 (let ((beg (point))
8400 (errfile (make-temp-file "lserr")))
8414 8401
8415 ;; Read the actual directory using `insert-directory-program'. 8402 ;; Read the actual directory using `insert-directory-program'.
8416 ;; RESULT gets the status code.
8417 (let* (;; We at first read by no-conversion, then after 8403 (let* (;; We at first read by no-conversion, then after
8418 ;; putting text property `dired-filename, decode one 8404 ;; putting text property `dired-filename, decode one
8419 ;; bunch by one to preserve that property. 8405 ;; bunch by one to preserve that property.
@@ -8423,143 +8409,88 @@ normally equivalent short `-D' option is just passed on to
8423 (and enable-multibyte-characters 8409 (and enable-multibyte-characters
8424 (or file-name-coding-system 8410 (or file-name-coding-system
8425 default-file-name-coding-system)))) 8411 default-file-name-coding-system))))
8426 (setq result 8412 (if wildcard
8427 (if wildcard 8413 ;; If the wildcard is just in the file part, then run ls in
8428 ;; If the wildcard is just in the file part, then run ls in 8414 ;; the directory part of the file pattern using the last
8429 ;; the directory part of the file pattern using the last 8415 ;; component as argument. Otherwise, run ls in the longest
8430 ;; component as argument. Otherwise, run ls in the longest 8416 ;; subdirectory of the directory part free of wildcards; use
8431 ;; subdirectory of the directory part free of wildcards; use 8417 ;; the remaining of the file pattern as argument.
8432 ;; the remaining of the file pattern as argument. 8418 (let* ((dir-wildcard
8433 (let* ((dir-wildcard (insert-directory-wildcard-in-dir-p file)) 8419 (insert-directory-wildcard-in-dir-p file))
8434 (default-directory 8420 (default-directory
8435 (cond (dir-wildcard (car dir-wildcard)) 8421 (cond (dir-wildcard (car dir-wildcard))
8436 (t 8422 (t
8437 (if (file-name-absolute-p file) 8423 (if (file-name-absolute-p file)
8438 (file-name-directory file) 8424 (file-name-directory file)
8439 (file-name-directory (expand-file-name file)))))) 8425 (file-name-directory
8440 (pattern (if dir-wildcard (cdr dir-wildcard) (file-name-nondirectory file)))) 8426 (expand-file-name file))))))
8441 ;; NB since switches is passed to the shell, be 8427 (pattern (if dir-wildcard
8442 ;; careful of malicious values, eg "-l;reboot". 8428 (cdr dir-wildcard)
8443 ;; See eg dired-safe-switches-p. 8429 (file-name-nondirectory file))))
8444 (call-process 8430 ;; NB since switches is passed to the shell, be
8445 shell-file-name nil t nil 8431 ;; careful of malicious values, eg "-l;reboot".
8446 shell-command-switch 8432 ;; See eg dired-safe-switches-p.
8447 (concat (if (memq system-type '(ms-dos windows-nt)) 8433 (call-process
8448 "" 8434 shell-file-name nil (list t errfile) nil
8449 "\\") ; Disregard Unix shell aliases! 8435 shell-command-switch
8450 insert-directory-program 8436 (concat (if (memq system-type '(ms-dos windows-nt))
8451 " -d " 8437 ""
8452 ;; Quote switches that require quoting 8438 "\\") ; Disregard Unix shell aliases!
8453 ;; such as "--block-size='1". But don't 8439 insert-directory-program
8454 ;; quote switches that use patterns 8440 " -d "
8455 ;; such as "--ignore=PATTERN" (bug#71935). 8441 ;; Quote switches that require quoting
8456 (mapconcat #'shell-quote-wildcard-pattern 8442 ;; such as "--block-size='1". But don't
8457 (if (stringp switches) 8443 ;; quote switches that use patterns
8458 (split-string-and-unquote switches) 8444 ;; such as "--ignore=PATTERN" (bug#71935).
8459 switches) 8445 (mapconcat #'shell-quote-wildcard-pattern
8460 " ") 8446 (if (stringp switches)
8461 " -- " 8447 (split-string-and-unquote switches)
8462 ;; Quote some characters that have 8448 switches)
8463 ;; special meanings in shells; but 8449 " ")
8464 ;; don't quote the wildcards--we want 8450 " -- "
8465 ;; them to be special. We also 8451 ;; Quote some characters that have
8466 ;; currently don't quote the quoting 8452 ;; special meanings in shells; but
8467 ;; characters in case people want to 8453 ;; don't quote the wildcards--we want
8468 ;; use them explicitly to quote 8454 ;; them to be special. We also
8469 ;; wildcard characters. 8455 ;; currently don't quote the quoting
8470 (shell-quote-wildcard-pattern pattern)))) 8456 ;; characters in case people want to
8471 ;; SunOS 4.1.3, SVr4 and others need the "." to list the 8457 ;; use them explicitly to quote
8472 ;; directory if FILE is a symbolic link. 8458 ;; wildcard characters.
8473 (unless full-directory-p 8459 (shell-quote-wildcard-pattern pattern))))
8474 (setq switches 8460 ;; SunOS 4.1.3, SVr4 and others need the "." to list the
8475 (cond 8461 ;; directory if FILE is a symbolic link.
8476 ((stringp switches) (concat switches " -d")) 8462 (unless full-directory-p
8477 ((member "-d" switches) switches) 8463 (setq switches
8478 (t (append switches '("-d")))))) 8464 (cond
8479 (if (string-match "\\`~" file) 8465 ((stringp switches) (concat switches " -d"))
8480 (setq file (expand-file-name file))) 8466 ((member "-d" switches) switches)
8481 (apply #'call-process 8467 (t (append switches '("-d"))))))
8482 insert-directory-program nil t nil 8468 (if (string-match "\\`~" file)
8483 (append 8469 (setq file (expand-file-name file)))
8484 (if (listp switches) switches 8470 (apply #'call-process
8485 (unless (equal switches "") 8471 insert-directory-program nil (list t errfile) nil
8486 ;; Split the switches at any spaces so we can 8472 (append
8487 ;; pass separate options as separate args. 8473 (if (listp switches) switches
8488 (split-string-and-unquote switches))) 8474 (unless (equal switches "")
8489 ;; Avoid lossage if FILE starts with `-'. 8475 ;; Split the switches at any spaces so we can
8490 '("--") 8476 ;; pass separate options as separate args.
8491 (list file)))))) 8477 (split-string-and-unquote switches)))
8492 8478 ;; Avoid lossage if FILE starts with `-'.
8493 ;; If we got "//DIRED//" in the output, it means we got a real 8479 '("--")
8494 ;; directory listing, even if `ls' returned nonzero. 8480 (list file)))))
8495 ;; So ignore any errors. 8481
8496 (when (if (stringp switches) 8482 ;; If `ls' emits an error message, copy it to a buffer that will
8497 (string-match "--dired\\>" switches) 8483 ;; be displayed when a Dired invocation results in the `ls'
8498 (member "--dired" switches)) 8484 ;; error.
8499 (save-excursion 8485 (when (> (file-attribute-size (file-attributes errfile)) 0)
8500 (let ((case-fold-search nil)) 8486 (defvar dired--ls-error-buffer) ; Pacify byte-compiler.
8501 (forward-line -2) 8487 (let ((errbuf (get-buffer-create "*ls error*")))
8502 (when (looking-at "//SUBDIRED//") 8488 (with-current-buffer errbuf
8503 (forward-line -1)) 8489 (erase-buffer)
8504 (if (looking-at "//DIRED//") 8490 (insert-file-contents errfile))
8505 (setq result 0))))) 8491 (setq dired--ls-error-buffer errbuf)))
8506 8492 (delete-file errfile)
8507 (when (and (not (eq 0 result)) 8493
8508 (eq insert-directory-ls-version 'unknown))
8509 ;; The first time ls returns an error,
8510 ;; find the version numbers of ls,
8511 ;; and set insert-directory-ls-version
8512 ;; to > if it is more than 5.2.1, < if it is less, nil if it
8513 ;; is equal or if the info cannot be obtained.
8514 ;; (That can mean it isn't GNU ls.)
8515 (let ((version-out
8516 (with-temp-buffer
8517 (call-process "ls" nil t nil "--version")
8518 (buffer-string))))
8519 (setq insert-directory-ls-version
8520 (if (string-match "ls (.*utils) \\([0-9.]*\\)$" version-out)
8521 (let* ((version (match-string 1 version-out))
8522 (split (split-string version "[.]"))
8523 (numbers (mapcar #'string-to-number split))
8524 (min '(5 2 1))
8525 comparison)
8526 (while (and (not comparison) (or numbers min))
8527 (cond ((null min)
8528 (setq comparison #'>))
8529 ((null numbers)
8530 (setq comparison #'<))
8531 ((> (car numbers) (car min))
8532 (setq comparison #'>))
8533 ((< (car numbers) (car min))
8534 (setq comparison #'<))
8535 (t
8536 (setq numbers (cdr numbers)
8537 min (cdr min)))))
8538 (or comparison #'=))
8539 nil))))
8540
8541 ;; For GNU ls versions 5.2.2 and up, ignore minor errors.
8542 (when (and (eq 1 result) (eq insert-directory-ls-version #'>))
8543 (setq result 0))
8544
8545 ;; If `insert-directory-program' failed, signal an error.
8546 (unless (eq 0 result)
8547 ;; Delete the error message it may have output.
8548 (delete-region beg (point))
8549 ;; On non-Posix systems, we cannot open a directory, so
8550 ;; don't even try, because that will always result in
8551 ;; the ubiquitous "Access denied". Instead, show the
8552 ;; command line so the user can try to guess what went wrong.
8553 (if (and (file-directory-p file)
8554 (memq system-type '(ms-dos windows-nt)))
8555 (error
8556 "Reading directory: \"%s %s -- %s\" exited with status %s"
8557 insert-directory-program
8558 (if (listp switches) (concat switches) switches)
8559 file result)
8560 ;; Unix. Access the file to get a suitable error.
8561 (access-file file "Reading directory")
8562 (error "Listing directory failed but `access-file' worked")))
8563 (insert-directory-clean beg switches) 8494 (insert-directory-clean beg switches)
8564 ;; Now decode what read if necessary. 8495 ;; Now decode what read if necessary.
8565 (let ((coding (or coding-system-for-read 8496 (let ((coding (or coding-system-for-read
@@ -8594,18 +8525,6 @@ normally equivalent short `-D' option is just passed on to
8594 (put-text-property pos (point) 8525 (put-text-property pos (point)
8595 'dired-filename t)))))))))))) 8526 'dired-filename t))))))))))))
8596 8527
8597(defun insert-directory-adj-pos (pos error-lines)
8598 "Convert `ls --dired' file name position value POS to a buffer position.
8599File name position values returned in ls --dired output
8600count only stdout; they don't count the error messages sent to stderr.
8601So this function converts to them to real buffer positions.
8602ERROR-LINES is a list of buffer positions of error message lines,
8603of the form (START END)."
8604 (while (and error-lines (< (caar error-lines) pos))
8605 (setq pos (+ pos (- (nth 1 (car error-lines)) (nth 0 (car error-lines)))))
8606 (pop error-lines))
8607 pos)
8608
8609(defun insert-directory-safely (file switches 8528(defun insert-directory-safely (file switches
8610 &optional wildcard full-directory-p) 8529 &optional wildcard full-directory-p)
8611 "Insert directory listing for FILE, formatted according to SWITCHES. 8530 "Insert directory listing for FILE, formatted according to SWITCHES.
diff --git a/lisp/frame.el b/lisp/frame.el
index da48e695297..85b58cee070 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -493,6 +493,7 @@ there (in decreasing order of priority)."
493 (setq parms (append initial-frame-alist window-system-frame-alist 493 (setq parms (append initial-frame-alist window-system-frame-alist
494 default-frame-alist parms nil)) 494 default-frame-alist parms nil))
495 ;; Don't enable tab-bar in daemon's initial frame. 495 ;; Don't enable tab-bar in daemon's initial frame.
496 ;; Use `frame-initial-p'?
496 (when (and (daemonp) (eq (selected-frame) terminal-frame)) 497 (when (and (daemonp) (eq (selected-frame) terminal-frame))
497 (setq parms (delq (assq 'tab-bar-lines parms) parms))) 498 (setq parms (delq (assq 'tab-bar-lines parms) parms)))
498 parms)) 499 parms))
diff --git a/lisp/frameset.el b/lisp/frameset.el
index e11a1da7e9b..0dde10869fd 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -1370,12 +1370,10 @@ All keyword parameters default to nil."
1370 ;; frame, as that would only trigger 1370 ;; frame, as that would only trigger
1371 ;; warnings. 1371 ;; warnings.
1372 (not 1372 (not
1373 (and (daemonp) 1373 (and (daemonp) ;; FIXME: Remove `daemonp'?
1374 (equal (terminal-name (frame-terminal 1374 (frame-initial-p frame))))
1375 frame)) 1375 (delete-frame frame)))
1376 "initial_terminal")))) 1376 cleanup-frames)))
1377 (delete-frame frame)))
1378 cleanup-frames)))
1379 (maphash (lambda (frame _action) (push frame map)) frameset--action-map) 1377 (maphash (lambda (frame _action) (push frame map)) frameset--action-map)
1380 (dolist (frame (sort map 1378 (dolist (frame (sort map
1381 ;; Minibufferless frames must go first to avoid 1379 ;; Minibufferless frames must go first to avoid
diff --git a/lisp/gnus/gnus-delay.el b/lisp/gnus/gnus-delay.el
index b8fefabacbb..d3088b4001f 100644
--- a/lisp/gnus/gnus-delay.el
+++ b/lisp/gnus/gnus-delay.el
@@ -70,6 +70,9 @@ DELAY is a string, giving the length of the time. Possible values are:
70* YYYY-MM-DD for a specific date. The time of day is given by the 70* YYYY-MM-DD for a specific date. The time of day is given by the
71 variable `gnus-delay-default-hour', minute and second are zero. 71 variable `gnus-delay-default-hour', minute and second are zero.
72 72
73* YYYY-MM-DD hh:mm(:ss) for a specific date and time. If seconds are left
74 out, they will be zero.
75
73* hh:mm for a specific time. Use 24h format. If it is later than this 76* hh:mm for a specific time. Use 24h format. If it is later than this
74 time, then the deadline is tomorrow, else today. 77 time, then the deadline is tomorrow, else today.
75 78
@@ -82,8 +85,21 @@ generated when the article is sent."
82 message-mode) 85 message-mode)
83 ;; Allow spell checking etc. 86 ;; Allow spell checking etc.
84 (run-hooks 'message-send-hook) 87 (run-hooks 'message-send-hook)
85 (let (num unit year month day hour minute deadline) ;; days 88 (let (num unit year month day hour minute deadline second) ;; days
86 (cond ((string-match 89 (cond ((string-match
90 "\\([0-9][0-9][0-9]?[0-9]?\\)-\\([0-9]+\\)-\\([0-9]+\\) \\([0-9]\\{1,2\\}\\):\\([0-9]\\{2\\}\\):?\\([0-9]\\{2\\}\\)?"
91 delay)
92 (setq year (string-to-number (match-string 1 delay))
93 month (string-to-number (match-string 2 delay))
94 day (string-to-number (match-string 3 delay))
95 hour (string-to-number (match-string 4 delay))
96 minute (string-to-number (match-string 5 delay))
97 second (if (match-string 6 delay) (string-to-number (match-string 6 delay)) 0))
98 (setq deadline
99 (message-make-date
100 (encode-time second minute hour
101 day month year))))
102 ((string-match
87 "\\([0-9][0-9][0-9]?[0-9]?\\)-\\([0-9]+\\)-\\([0-9]+\\)" 103 "\\([0-9][0-9][0-9]?[0-9]?\\)-\\([0-9]+\\)-\\([0-9]+\\)"
88 delay) 104 delay)
89 (setq year (string-to-number (match-string 1 delay)) 105 (setq year (string-to-number (match-string 1 delay))
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index ad1c4c2731a..0097f590b43 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -36,6 +36,10 @@
36;;; Code: 36;;; Code:
37 37
38(require 'icalendar) 38(require 'icalendar)
39(require 'icalendar-parser)
40(eval-when-compile (require 'icalendar-macs))
41(require 'icalendar-ast)
42(require 'icalendar-utils)
39(require 'eieio) 43(require 'eieio)
40(require 'gmm-utils) 44(require 'gmm-utils)
41(require 'mm-decode) 45(require 'mm-decode)
@@ -82,8 +86,8 @@
82 :type (or null t)) 86 :type (or null t))
83 (recur :initarg :recur 87 (recur :initarg :recur
84 :accessor gnus-icalendar-event:recur 88 :accessor gnus-icalendar-event:recur
85 :initform "" 89 :initform nil
86 :type (or null string)) 90 :type (or null list))
87 (uid :initarg :uid 91 (uid :initarg :uid
88 :accessor gnus-icalendar-event:uid 92 :accessor gnus-icalendar-event:uid
89 :type string) 93 :type string)
@@ -127,295 +131,212 @@
127 131
128(cl-defmethod gnus-icalendar-event:recurring-freq ((event gnus-icalendar-event)) 132(cl-defmethod gnus-icalendar-event:recurring-freq ((event gnus-icalendar-event))
129 "Return recurring frequency of EVENT." 133 "Return recurring frequency of EVENT."
130 (let ((rrule (gnus-icalendar-event:recur event))) 134 (ical:recur-freq (gnus-icalendar-event:recur event)))
131 (string-match "FREQ=\\([[:alpha:]]+\\)" rrule)
132 (match-string 1 rrule)))
133 135
134(cl-defmethod gnus-icalendar-event:recurring-interval ((event gnus-icalendar-event)) 136(cl-defmethod gnus-icalendar-event:recurring-interval ((event gnus-icalendar-event))
135 "Return recurring interval of EVENT." 137 "Return recurring interval of EVENT."
136 (let ((rrule (gnus-icalendar-event:recur event)) 138 (ical:recur-interval-size (gnus-icalendar-event:recur event)))
137 (default-interval "1"))
138
139 (if (string-match "INTERVAL=\\([[:digit:]]+\\)" rrule)
140 (match-string 1 rrule)
141 default-interval)))
142 139
143(cl-defmethod gnus-icalendar-event:recurring-days ((event gnus-icalendar-event)) 140(cl-defmethod gnus-icalendar-event:recurring-days ((event gnus-icalendar-event))
144 "Return, when available, the week day numbers on which the EVENT recurs." 141 "Return, when available, the week day numbers on which the EVENT recurs."
145 (let ((rrule (gnus-icalendar-event:recur event)) 142 (let ((rrule (gnus-icalendar-event:recur event)))
146 (weekday-map '(("SU" . 0) 143 (when rrule
147 ("MO" . 1) 144 (mapcar (lambda (el) (if (consp el) (car el) el))
148 ("TU" . 2) 145 (ical:recur-by* 'BYDAY rrule)))))
149 ("WE" . 3)
150 ("TH" . 4)
151 ("FR" . 5)
152 ("SA" . 6))))
153 (when (and rrule (string-match "BYDAY=\\([^;]+\\)" rrule))
154 (let ((bydays (split-string (match-string 1 rrule) ",")))
155 (seq-map
156 (lambda (x) (cdr (assoc x weekday-map)))
157 (seq-filter (lambda (x) (string-match "^[A-Z]\\{2\\}$" x)) bydays))))))
158 146
159(cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event)) 147(cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
160 (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event))) 148 (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event)))
161 149
162(defun gnus-icalendar-event--decode-datefield (event field zone-map) 150(defun gnus-icalendar-event--find-attendee (attendees ids)
163 (let* ((dtdate (icalendar--get-event-property event field)) 151 "Return the first `icalendar-attendee' in ATTENDEES matching IDS.
164 (dtdate-zone (icalendar--find-time-zone 152IDS should be a list of strings. The first attendee is returned whose
165 (icalendar--get-event-property-attributes 153name (as `icalendar-cnparam') or email address (without \"mailto:\")
166 event field) zone-map)) 154is a member of IDS."
167 (dtdate-dec (icalendar--decode-isodatetime dtdate nil dtdate-zone))) 155 (catch 'found
168 (when dtdate-dec (encode-time dtdate-dec)))) 156 (dolist (attendee attendees)
169 157 (ical:with-property attendee ((ical:cnparam :value name))
170(defun gnus-icalendar-event--find-attendee (ical name-or-email) 158 (let ((email (ical:strip-mailto value)))
171 (let* ((event (car (icalendar--all-events ical))) 159 (when (or (member name ids)
172 (event-props (caddr event))) 160 (member email ids))
173 (cl-labels ((attendee-name (att) (plist-get (cadr att) 'CN)) 161 (throw 'found attendee)))))))
174 (attendee-email 162
175 (att) 163(defun gnus-icalendar-event--attendees-by-type (attendees)
176 (replace-regexp-in-string "^.*MAILTO:" "" (caddr att))) 164 "Return lists of required and optional participants in ATTENDEES.
177 (attendee-prop-matches-p 165ATTENDEES must be a list of `icalendar-attendee' nodes. The returned
178 (prop) 166list has the form (REQUIRED OPTIONAL), where each is a list of
179 (and (eq (car prop) 'ATTENDEE) 167`icalendar-attendee' nodes."
180 (or (member (attendee-name prop) name-or-email) 168 (let (required optional)
181 (let ((att-email (attendee-email prop))) 169 (dolist (attendee attendees)
182 (gnus-icalendar-find-if 170 (ical:with-property attendee ((ical:roleparam :value role))
183 (lambda (str-or-fun) 171 (when (or (null role) ; "REQ-PARTICIPANT" is the default
184 (if (functionp str-or-fun) 172 (equal role "REQ-PARTICIPANT"))
185 (funcall str-or-fun att-email) 173 (push attendee required))
186 (string-match str-or-fun att-email))) 174 (when (equal role "OPT-PARTICIPANT")
187 name-or-email)))))) 175 (push attendee optional))))
188 (gnus-icalendar-find-if #'attendee-prop-matches-p event-props)))) 176 (list (nreverse required)
189 177 (nreverse optional))))
190(defun gnus-icalendar-event--get-attendee-names (ical) 178
191 (let* ((event (car (icalendar--all-events ical))) 179(defun gnus-icalendar-event-from-ical (vcalendar &optional ids)
192 (attendee-props (seq-filter 180 "Initialize an event instance with the first `icalendar-vevent' in VCALENDAR.
193 (lambda (p) (eq (car p) 'ATTENDEE)) 181IDS should be a list of strings representing names and email addresses
194 (caddr event)))) 182by which to identify an `icalendar-attendee' in the event as the
195 183recipient."
196 (cl-labels 184 (ical:with-component vcalendar
197 ((attendee-role (prop) 185 ((ical:vevent vevent)
198 ;; RFC5546: default ROLE is REQ-PARTICIPANT 186 (ical:method :value method))
199 (and prop 187 (ical:with-component vevent
200 (or (plist-get (cadr prop) 'ROLE) 188 ((ical:organizer :value organizer)
201 "REQ-PARTICIPANT"))) 189 (ical:attendee :all attendees)
202 (attendee-name 190 (ical:summary :value summary)
203 (prop) 191 (ical:description :value description)
204 (or (plist-get (cadr prop) 'CN) 192 (ical:dtstart :value dtstart)
205 (replace-regexp-in-string "^.*MAILTO:" "" (caddr prop)))) 193 (ical:dtend :value dtend)
206 (attendees-by-type (type) 194 (ical:location :value location)
207 (seq-filter 195 (ical:rrule :value rrule)
208 (lambda (p) (string= (attendee-role p) type)) 196 (ical:uid :value uid))
209 attendee-props)) 197
210 (attendee-names-by-type 198 (let* ((attendee (when ids (gnus-icalendar-event--find-attendee attendees ids)))
211 (type) 199 (rsvp-p (ical:with-param-of attendee 'ical:rsvpparam))
212 (mapcar #'attendee-name (attendees-by-type type))))
213 (list
214 (attendee-names-by-type "REQ-PARTICIPANT")
215 (attendee-names-by-type "OPT-PARTICIPANT")))))
216
217(defun gnus-icalendar-event-from-ical (ical &optional attendee-name-or-email)
218 (let* ((event (car (icalendar--all-events ical)))
219 (organizer (replace-regexp-in-string
220 "^.*MAILTO:" ""
221 (or (icalendar--get-event-property event 'ORGANIZER) "")))
222 (prop-map '((summary . SUMMARY)
223 (description . DESCRIPTION)
224 (location . LOCATION)
225 (recur . RRULE)
226 (uid . UID)))
227 (method (caddr (assoc 'METHOD (caddr (car (nreverse ical))))))
228 (attendee (when attendee-name-or-email
229 (gnus-icalendar-event--find-attendee
230 ical attendee-name-or-email)))
231 (attendee-names (gnus-icalendar-event--get-attendee-names ical))
232 ;; RFC5546: default ROLE is REQ-PARTICIPANT 200 ;; RFC5546: default ROLE is REQ-PARTICIPANT
233 (role (and attendee 201 (role (when attendee
234 (or (plist-get (cadr attendee) 'ROLE) 202 (or (ical:with-param-of attendee 'ical:roleparam)
235 "REQ-PARTICIPANT"))) 203 "REQ-PARTICIPANT")))
236 (participation-type (pcase role 204 (participation-type (pcase role
237 ("REQ-PARTICIPANT" 'required) 205 ("REQ-PARTICIPANT" 'required)
238 ("OPT-PARTICIPANT" 'optional) 206 ("OPT-PARTICIPANT" 'optional)
239 (_ 'non-participant))) 207 (_ 'non-participant)))
240 (zone-map (icalendar--convert-all-timezones ical)) 208 (req/opt (gnus-icalendar-event--attendees-by-type attendees))
241 (args 209 (args
242 (list :method method 210 (list :method method
243 :organizer organizer 211 :organizer (when organizer (ical:strip-mailto organizer))
244 :start-time (gnus-icalendar-event--decode-datefield 212 :summary summary
245 event 'DTSTART zone-map) 213 :description description
246 :end-time (gnus-icalendar-event--decode-datefield 214 :location location
247 event 'DTEND zone-map) 215 :recur rrule
248 :rsvp (string= (plist-get (cadr attendee) 'RSVP) "TRUE") 216 :start-time (encode-time dtstart)
217 :end-time (encode-time dtend)
218 :rsvp rsvp-p
249 :participation-type participation-type 219 :participation-type participation-type
250 :req-participants (car attendee-names) 220 :req-participants (car req/opt)
251 :opt-participants (cadr attendee-names))) 221 :opt-participants (cadr req/opt)
252 (event-class 222 :uid (or uid ""))) ; UID must be a string
253 (cond 223 (event-class (pcase method
254 ((string= method "REQUEST") 'gnus-icalendar-event-request) 224 ("REQUEST" 'gnus-icalendar-event-request)
255 ((string= method "CANCEL") 'gnus-icalendar-event-cancel) 225 ("CANCEL" 'gnus-icalendar-event-cancel)
256 ((string= method "REPLY") 'gnus-icalendar-event-reply) 226 ("REPLY" 'gnus-icalendar-event-reply)
257 (t 'gnus-icalendar-event)))) 227 (_ 'gnus-icalendar-event))))
258 (cl-labels 228 ;; Initialize and return the instance:
259 ((map-property 229 (apply
260 (prop) 230 #'make-instance
261 (let ((value (icalendar--get-event-property event prop))) 231 event-class
262 (when value 232 (cl-loop for slot in (eieio-class-slots event-class)
263 ;; ugly, but cannot get 233 for keyword = (intern
264 ;;replace-regexp-in-string work with "\\" as 234 (format ":%s" (eieio-slot-descriptor-name slot)))
265 ;;REP, plus we should also handle "\\;" 235 when (plist-member args keyword)
266 (string-replace 236 append (list keyword (plist-get args keyword))))))))
267 "\\," "," 237
268 (string-replace 238(defun gnus-icalendar-event-from-buffer (buf &optional ids)
269 "\\n" "\n" (substring-no-properties value))))))
270 (accumulate-args
271 (mapping)
272 (cl-destructuring-bind (slot . ical-property) mapping
273 (setq args (append (list
274 (intern (concat ":" (symbol-name slot)))
275 (map-property ical-property))
276 args)))))
277 (mapc #'accumulate-args prop-map)
278 (apply
279 #'make-instance
280 event-class
281 (cl-loop for slot in (eieio-class-slots event-class)
282 for keyword = (intern
283 (format ":%s" (eieio-slot-descriptor-name slot)))
284 when (plist-member args keyword)
285 append (list keyword
286 (if (eq keyword :uid)
287 ;; The UID has to be a string.
288 (or (plist-get args keyword) "")
289 (plist-get args keyword))))))))
290
291(defun gnus-icalendar-event-from-buffer (buf &optional attendee-name-or-email)
292 "Parse RFC5545 iCalendar in buffer BUF and return an event object. 239 "Parse RFC5545 iCalendar in buffer BUF and return an event object.
293 240
294Return a gnus-icalendar-event object representing the first event 241Return a gnus-icalendar-event object representing the first event
295contained in the invitation. Return nil for calendars without an 242contained in the invitation. Return nil for calendars without an
296event entry. 243event entry.
297 244
298ATTENDEE-NAME-OR-EMAIL is a list of strings that will be matched 245IDS is a list of strings that identify the recipient
299against the event's attendee names and emails. Invitation rsvp 246`icalendar-attendee' by name or email address. Invitation rsvp status
300status will be retrieved from the first matching attendee record." 247will be retrieved from the first matching attendee record."
301 (let ((ical (with-current-buffer (icalendar--get-unfolded-buffer (get-buffer buf)) 248 (let ((vcalendar (ical:parse buf)))
302 (goto-char (point-min)) 249 (when vcalendar
303 (icalendar--read-element nil nil)))) 250 (gnus-icalendar-event-from-ical vcalendar ids))))
304
305 (when ical
306 (gnus-icalendar-event-from-ical ical attendee-name-or-email))))
307 251
308;;; 252;;;
309;;; gnus-icalendar-event-reply 253;;; gnus-icalendar-event-reply
310;;; 254;;;
311 255
312(defun gnus-icalendar-event--build-reply-event-body (ical-request status identities &optional comment) 256(defun gnus-icalendar-event--build-reply (vcalendar status ids &optional comment)
257 "Return an `icalendar-vcalendar' based on VCALENDAR with updated STATUS.
258STATUS should one of \\='accepted, \\='declined, or \\='tentative. The
259recipient whose participation status is updated to STATUS is identified
260in EVENT by finding an `icalendar-attendee' whose name or email address
261matches one of the strings in IDS. If no such attendee is found, a new
262`icalendar-attendee' is added from the values of `user-mail-address' and
263`user-full-name'. COMMENT, if provided, will be added as an
264`icalendar-comment' to the returned event."
313 (let ((summary-status (capitalize (symbol-name status))) 265 (let ((summary-status (capitalize (symbol-name status)))
314 (attendee-status (upcase (symbol-name status))) 266 (attendee-status (upcase (symbol-name status)))
315 reply-event-lines) 267 recipient)
316 (cl-labels 268 (ical:with-component vcalendar
317 ((update-summary 269 ((ical:vtimezone :all tz-nodes)
318 (line) 270 (ical:vevent :first vevent))
319 (if (string-match "^[^:]+:" line) 271 (ical:with-component vevent
320 (replace-match (format "\\&%s: " summary-status) t nil line) 272 ((ical:summary :value summary)
321 line)) 273 (ical:attendee :all attendees)
322 (update-comment 274 (ical:uid :value uid)
323 (line) 275 (ical:comment :value old-comment)
324 (if comment (format "COMMENT:%s" comment) 276 ;; The nodes below are copied unchanged to the reply. Not all
325 line)) 277 ;; of them are mandatory, but they are often present in other
326 (update-dtstamp () 278 ;; clients' replies. Can be helpful for debugging, too.
327 (format-time-string "DTSTAMP:%Y%m%dT%H%M%SZ" nil t)) 279 (ical:organizer :first organizer-node)
328 (attendee-matches-identity 280 (ical:dtstart :first dtstart-node)
329 (line) 281 (ical:dtend :first dtend-node)
330 (gnus-icalendar-find-if (lambda (name) (string-match-p name line)) 282 (ical:duration :first duration-node)
331 identities)) 283 (ical:location :first location-node)
332 (update-attendee-status 284 (ical:sequence :first sequence-node)
333 (line) 285 (ical:recurrence-id :first recid-node))
334 (when (and (attendee-matches-identity line) 286
335 (string-match "\\(PARTSTAT=\\)[^;]+" line)) 287 (setq recipient (gnus-icalendar-event--find-attendee attendees ids))
336 (replace-match (format "\\1%s" attendee-status) t nil line))) 288 (if recipient
337 (process-event-line 289 (ical:with-property recipient
338 (line) 290 ((ical:partstatparam :first partstat-node))
339 (when (string-match "^\\([^;:]+\\)" line) 291 (ical:ast-node-set-value partstat-node attendee-status))
340 (let* ((key (match-string 0 line)) 292 ;; RFC5546 refers to uninvited attendees as "party crashers".
341 ;; NOTE: not all of the below fields are mandatory, 293 ;; This situation is common if the invitation is sent to a group
342 ;; but they are often present in other clients' 294 ;; of people via a mailing list.
343 ;; replies. Can be helpful for debugging, too. 295 (lwarn 'gnus-icalendar :warning
344 (new-line 296 "Could not find a matching event attendee; creating new.")
345 (cond 297 (setq recipient
346 ((string= key "ATTENDEE") (update-attendee-status line)) 298 (ical:make-property ical:attendee
347 ((string= key "SUMMARY") (update-summary line)) 299 (concat "mailto:" user-mail-address)
348 ((string= key "COMMENT") (update-comment line)) 300 (ical:partstatparam attendee-status)
349 ((string= key "DTSTAMP") (update-dtstamp)) 301 (ical:cnparam user-full-name)))
350 ((member key '("ORGANIZER" "DTSTART" "DTEND" 302 (push recipient attendees))
351 "LOCATION" "DURATION" "SEQUENCE" 303
352 "RECURRENCE-ID" "UID")) 304 ;; Build the reply:
353 line) 305 (ical:make-vcalendar
354 (t nil)))) 306 (ical:method "REPLY")
355 (when new-line 307 (@ tz-nodes)
356 (push new-line reply-event-lines)))))) 308 (ical:vevent
357 309 (ical:uid uid)
358 (mapc #'process-event-line (split-string ical-request "\n")) 310 recid-node
359 311 sequence-node
360 ;; RFC5546 refers to uninvited attendees as "party crashers". 312 organizer-node
361 ;; This situation is common if the invitation is sent to a group 313 dtstart-node
362 ;; of people via a mailing list. 314 dtend-node
363 (unless (gnus-icalendar-find-if (lambda (x) (string-match "^ATTENDEE" x)) 315 duration-node
364 reply-event-lines) 316 location-node
365 (lwarn 'gnus-icalendar :warning 317 (ical:summary
366 "Could not find an event attendee matching given identity") 318 (if (string-match "^[^:]+:" summary)
367 (push (format "ATTENDEE;RSVP=TRUE;PARTSTAT=%s;CN=%s:MAILTO:%s" 319 (replace-match (format "\\&%s: " summary-status) t nil summary)
368 attendee-status user-full-name user-mail-address) 320 summary))
369 reply-event-lines)) 321 (ical:comment (or comment old-comment))
370 322 (@ attendees)))))))
371 ;; add comment line if not existing 323
372 (when (and comment 324(defun gnus-icalendar-event-reply-from-buffer (buf status ids
373 (not (gnus-icalendar-find-if 325 &optional comment)
374 (lambda (x)
375 (string-match "^COMMENT" x))
376 reply-event-lines)))
377 (push (format "COMMENT:%s" comment) reply-event-lines))
378
379 (mapconcat #'identity `("BEGIN:VEVENT"
380 ,@(nreverse reply-event-lines)
381 "END:VEVENT")
382 "\n"))))
383
384(defun gnus-icalendar-event-reply-from-buffer (buf status identities &optional comment)
385 "Build a calendar event reply for request contained in BUF. 326 "Build a calendar event reply for request contained in BUF.
386The reply will have STATUS (`accepted', `tentative' or `declined'). 327The reply will have STATUS (`accepted', `tentative' or `declined'). The
387The reply will be composed for attendees matching any entry 328reply will be composed for attendees matching any entry in the
388on the IDENTITIES list. 329IDS list. Optional argument COMMENT will be placed in the
389Optional argument COMMENT will be placed in the comment field of the 330comment field of the reply."
390reply. 331 (let (vcalendar reply)
391" 332 (with-current-buffer (ical:unfolded-buffer-from-buffer (get-buffer buf))
392 (cl-labels 333 (setq vcalendar (ical:parse))
393 ((extract-block 334 (unless vcalendar
394 (blockname) 335 (error "Could not parse invitation; see buffer %s"
395 (save-excursion 336 (buffer-name (ical:error-buffer))))
396 (let ((block-start-re (format "^BEGIN:%s" blockname)) 337 (setq reply
397 (block-end-re (format "^END:%s" blockname)) 338 (gnus-icalendar-event--build-reply vcalendar status ids comment))
398 start) 339 (ical:print-calendar-node reply))))
399 (when (re-search-forward block-start-re nil t)
400 (setq start (line-beginning-position))
401 (re-search-forward block-end-re)
402 (buffer-substring-no-properties start (line-end-position)))))))
403 (let (zone event)
404 (with-current-buffer (icalendar--get-unfolded-buffer (get-buffer buf))
405 (goto-char (point-min))
406 (setq zone (extract-block "VTIMEZONE")
407 event (extract-block "VEVENT")))
408
409 (when event
410 (let ((contents (list "BEGIN:VCALENDAR"
411 "METHOD:REPLY"
412 "PRODID:Gnus"
413 "VERSION:2.0"
414 zone
415 (gnus-icalendar-event--build-reply-event-body event status identities comment)
416 "END:VCALENDAR")))
417
418 (mapconcat #'identity (delq nil contents) "\n"))))))
419 340
420;;; 341;;;
421;;; gnus-icalendar-org 342;;; gnus-icalendar-org
@@ -455,15 +376,17 @@ reply.
455 "Return `org-mode' timestamp repeater string for recurring EVENT. 376 "Return `org-mode' timestamp repeater string for recurring EVENT.
456Return nil for non-recurring EVENT." 377Return nil for non-recurring EVENT."
457 (when (gnus-icalendar-event:recurring-p event) 378 (when (gnus-icalendar-event:recurring-p event)
458 (let* ((freq-map '(("HOURLY" . "h") 379 (let* ((freq-map '((HOURLY . "h")
459 ("DAILY" . "d") 380 (DAILY . "d")
460 ("WEEKLY" . "w") 381 (WEEKLY . "w")
461 ("MONTHLY" . "m") 382 (MONTHLY . "m")
462 ("YEARLY" . "y"))) 383 (YEARLY . "y")))
463 (org-freq (cdr (assoc (gnus-icalendar-event:recurring-freq event) freq-map)))) 384 (org-freq
385 (alist-get (gnus-icalendar-event:recurring-freq event) freq-map))
386 (interval-size (gnus-icalendar-event:recurring-interval event)))
464 387
465 (when org-freq 388 (when org-freq
466 (format "+%s%s" (gnus-icalendar-event:recurring-interval event) org-freq))))) 389 (format "+%d%s" interval-size org-freq)))))
467 390
468(defun gnus-icalendar--find-day (start-date end-date day) 391(defun gnus-icalendar--find-day (start-date end-date day)
469 (let ((time-1-day 86400)) 392 (let ((time-1-day 86400))
@@ -550,7 +473,18 @@ Return nil for non-recurring EVENT."
550 473
551 474
552(defun gnus-icalendar--format-participant-list (participants) 475(defun gnus-icalendar--format-participant-list (participants)
553 (mapconcat #'identity participants ", ")) 476 "Format PARTICIPANTS as a comma-separated list.
477
478Each `icalendar-attendee' in PARTICIPANTS will be represented like
479 A. Person <a.person@example.domain>
480or simply: <a.person@example.domain>, if no `icalendar-cnparam' is present."
481 (mapconcat
482 (lambda (attendee)
483 (ical:with-property attendee ((ical:cnparam :value cn))
484 (if cn
485 (format "%s <%s>" cn value)
486 (format "<%s>" value))))
487 participants ", "))
554 488
555;; TODO: make the template customizable 489;; TODO: make the template customizable
556(cl-defmethod gnus-icalendar-event->org-entry ((event gnus-icalendar-event) reply-status) 490(cl-defmethod gnus-icalendar-event->org-entry ((event gnus-icalendar-event) reply-status)
@@ -1110,3 +1044,7 @@ means prompt for a comment to include in the reply."
1110(provide 'gnus-icalendar) 1044(provide 'gnus-icalendar)
1111 1045
1112;;; gnus-icalendar.el ends here 1046;;; gnus-icalendar.el ends here
1047
1048;; Local Variables:
1049;; read-symbol-shorthands: (("ical:" . "icalendar-"))
1050;; End:
diff --git a/lisp/help.el b/lisp/help.el
index 49d4659ab02..1576fb61dc8 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -2356,11 +2356,13 @@ ARGLIST can also be t or a string of the form \"(FUN ARG1 ARG2 ...)\"."
2356 "Return a formal argument list for the function DEF. 2356 "Return a formal argument list for the function DEF.
2357If PRESERVE-NAMES is non-nil, return a formal arglist that uses 2357If PRESERVE-NAMES is non-nil, return a formal arglist that uses
2358the same names as used in the original source code, when possible." 2358the same names as used in the original source code, when possible."
2359 (let ((orig-def def) 2359 (let ((orig-def def))
2360 ;; Advice wrappers have "catch all" args, so fetch the actual underlying 2360 (let ((seen nil))
2361 ;; function to find the real arguments. 2361 ;; Advice wrappers have "catch all" args, so fetch the actual underlying
2362 (def (advice--cd*r 2362 ;; function to find the real arguments. Also follow aliases.
2363 (indirect-function def)))) ;; Follow aliases to other symbols. 2363 (while (not (memq def seen))
2364 (push def seen)
2365 (setq def (advice--cd*r (indirect-function def)))))
2364 ;; If definition is a macro, find the function inside it. 2366 ;; If definition is a macro, find the function inside it.
2365 (if (eq (car-safe def) 'macro) (setq def (cdr def))) 2367 (if (eq (car-safe def) 'macro) (setq def (cdr def)))
2366 (cond 2368 (cond
diff --git a/lisp/info.el b/lisp/info.el
index 368255092a1..320ac7de65c 100644
--- a/lisp/info.el
+++ b/lisp/info.el
@@ -1897,8 +1897,10 @@ of NODENAME; if none is found it then tries a case-insensitive match
1897 (if (equal nodename "") "Top" nodename) nil strict-case))) 1897 (if (equal nodename "") "Top" nodename) nil strict-case)))
1898 1898
1899(defun Info-goto-node-web (node) 1899(defun Info-goto-node-web (node)
1900 "Use `browse-url' to go to the gnu.org web server's version of NODE. 1900 "Use `browse-url' to go to the gnu.org Web server's version of NODE.
1901By default, go to the current Info node." 1901By default, go to the URL corresponding to the current Info node.
1902
1903This uses `Info-url-for-node' to determine the URL that corresponds to NODE."
1902 (interactive (list (Info-read-node-name 1904 (interactive (list (Info-read-node-name
1903 "Go to node (default current page): " Info-current-node)) 1905 "Go to node (default current page): " Info-current-node))
1904 Info-mode) 1906 Info-mode)
@@ -1924,7 +1926,10 @@ By default, go to the current Info node."
1924(defun Info-url-for-node (node) 1926(defun Info-url-for-node (node)
1925 "Return the URL corresponding to NODE. 1927 "Return the URL corresponding to NODE.
1926 1928
1927NODE should be a string of the form \"(manual)Node\"." 1929NODE should be a string of the form \"(manual)Node\".
1930
1931The correspondence between Info manuals and their Web URLs is
1932established by `Info-url-alist', which see."
1928 ;; GNU Texinfo skips whitespaces and newlines between the closing 1933 ;; GNU Texinfo skips whitespaces and newlines between the closing
1929 ;; parenthesis and the node-name, i.e. space, tab, line feed and 1934 ;; parenthesis and the node-name, i.e. space, tab, line feed and
1930 ;; carriage return. 1935 ;; carriage return.
diff --git a/lisp/international/characters.el b/lisp/international/characters.el
index ba994daa852..d19802c46fd 100644
--- a/lisp/international/characters.el
+++ b/lisp/international/characters.el
@@ -1782,15 +1782,15 @@ Setup `char-width-table' appropriate for non-CJK language environment."
1782(let ((c0-acronyms '("NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL" 1782(let ((c0-acronyms '("NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL"
1783 "BS" nil nil "VT" "FF" "CR" "SO" "SI" 1783 "BS" nil nil "VT" "FF" "CR" "SO" "SI"
1784 "DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB" 1784 "DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB"
1785 "CAN" "EM" "SUB" "ESC" "FC" "GS" "RS" "US"))) 1785 "CAN" "EM" "SUB" "ESC" "FS" "GS" "RS" "US")))
1786 (dotimes (i 32) 1786 (dotimes (i 32)
1787 (aset char-acronym-table i (car c0-acronyms)) 1787 (aset char-acronym-table i (car c0-acronyms))
1788 (setq c0-acronyms (cdr c0-acronyms)))) 1788 (setq c0-acronyms (cdr c0-acronyms))))
1789 1789
1790(let ((c1-acronyms '("PAD" "HOP" "BPH" "NBH" "IND" "NEL" "SSA" "ESA" 1790(let ((c1-acronyms '("PAD" "HOP" "BPH" "NBH" "IND" "NEL" "SSA" "ESA"
1791 "HTS" "HTJ" "VTS" "PLD" "PLU" "R1" "SS2" "SS1" 1791 "HTS" "HTJ" "VTS" "PLD" "PLU" "RI" "SS2" "SS3"
1792 "DCS" "PU1" "PU2" "STS" "CCH" "MW" "SPA" "EPA" 1792 "DCS" "PU1" "PU2" "STS" "CCH" "MW" "SPA" "EPA"
1793 "SOS" "SGCI" "SC1" "CSI" "ST" "OSC" "PM" "APC"))) 1793 "SOS" "SGCI" "SCI" "CSI" "ST" "OSC" "PM" "APC")))
1794 (dotimes (i 32) 1794 (dotimes (i 32)
1795 (aset char-acronym-table (+ #x0080 i) (car c1-acronyms)) 1795 (aset char-acronym-table (+ #x0080 i) (car c1-acronyms))
1796 (setq c1-acronyms (cdr c1-acronyms)))) 1796 (setq c1-acronyms (cdr c1-acronyms))))
diff --git a/lisp/international/emoji.el b/lisp/international/emoji.el
index d8e779f7d8d..56a8134be81 100644
--- a/lisp/international/emoji.el
+++ b/lisp/international/emoji.el
@@ -155,9 +155,13 @@ and also consults the `emoji-alternate-names' alist."
155 155
156;;;###autoload 156;;;###autoload
157(defun emoji-list () 157(defun emoji-list ()
158 "List emojis and allow selecting and inserting one of them. 158 "List Emoji and allow selecting and inserting one of them.
159If you are displaying Emoji on a text-only terminal, and some
160of them look incorrect, or there are display artifacts when
161scrolling the display, turn off `auto-composition-mode'.
162
159Select the emoji by typing \\<emoji-list-mode-map>\\[emoji-list-select] on its picture. 163Select the emoji by typing \\<emoji-list-mode-map>\\[emoji-list-select] on its picture.
160The glyph will be inserted into the buffer that was current 164The selected glyph will be inserted into the buffer that was current
161when the command was invoked." 165when the command was invoked."
162 (interactive) 166 (interactive)
163 (let ((buf (current-buffer))) 167 (let ((buf (current-buffer)))
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index fca00dd2fc7..e8930fd2d4e 100644
--- a/lisp/jsonrpc.el
+++ b/lisp/jsonrpc.el
@@ -4,7 +4,7 @@
4 4
5;; Author: João Távora <joaotavora@gmail.com> 5;; Author: João Távora <joaotavora@gmail.com>
6;; Keywords: processes, languages, extensions 6;; Keywords: processes, languages, extensions
7;; Version: 1.0.27 7;; Version: 1.0.28
8;; Package-Requires: ((emacs "25.2")) 8;; Package-Requires: ((emacs "25.2"))
9 9
10;; This is a GNU ELPA :core package. Avoid functionality that is not 10;; This is a GNU ELPA :core package. Avoid functionality that is not
diff --git a/lisp/kmacro.el b/lisp/kmacro.el
index 982ae38f47d..b88c716f0b3 100644
--- a/lisp/kmacro.el
+++ b/lisp/kmacro.el
@@ -219,7 +219,7 @@ macro to be executed before appending to it."
219;;;###autoload (autoload 'kmacro-keymap "kmacro" "Keymap for keyboard macro commands." t 'keymap) 219;;;###autoload (autoload 'kmacro-keymap "kmacro" "Keymap for keyboard macro commands." t 'keymap)
220 220
221(if kmacro-call-mouse-event 221(if kmacro-call-mouse-event
222 (global-set-key (vector kmacro-call-mouse-event) #'kmacro-end-call-mouse)) 222 (global-set-key (vector kmacro-call-mouse-event) #'kmacro-end-and-call-macro))
223 223
224 224
225;;; Called from keyboard-quit 225;;; Called from keyboard-quit
@@ -742,8 +742,8 @@ With numeric ARG, repeat the macro that many times,
742counting the definition just completed as the first repetition. 742counting the definition just completed as the first repetition.
743An argument of zero means repeat until error." 743An argument of zero means repeat until error."
744 (interactive "p") 744 (interactive "p")
745 ;; Isearch may push the kmacro-end-macro key sequence onto the macro. 745 ;; Isearch may push the kmacro-end-macro key sequence onto the macro.
746 ;; Just ignore it when executing the macro. 746 ;; Just ignore it when executing the macro. FIXME: When?Why?
747 (unless executing-kbd-macro 747 (unless executing-kbd-macro
748 (end-kbd-macro arg #'kmacro-loop-setup-function) 748 (end-kbd-macro arg #'kmacro-loop-setup-function)
749 (when (and last-kbd-macro (= (length last-kbd-macro) 0)) 749 (when (and last-kbd-macro (= (length last-kbd-macro) 0))
@@ -880,35 +880,25 @@ With \\[universal-argument], call second macro in macro ring."
880 880
881 881
882;;;###autoload 882;;;###autoload
883(defun kmacro-end-and-call-macro (arg &optional no-repeat) 883(defun kmacro-end-and-call-macro (arg &optional no-repeat event)
884 "Call last keyboard macro, ending it first if currently being defined. 884 "Call last keyboard macro, ending it first if currently being defined.
885With numeric prefix ARG, repeat macro that many times. 885With numeric prefix ARG, repeat macro that many times.
886Zero argument means repeat until there is an error. 886Zero argument means repeat until there is an error.
887If triggered via a mouse EVENT, moves point to the position clicked
888with the mouse before calling the macro.
887 889
888To give a macro a name, so you can call it even after defining other 890To give a macro a name, so you can call it even after defining other
889macros, use \\[kmacro-name-last-macro]." 891macros, use \\[kmacro-name-last-macro]."
890 (interactive "p") 892 (interactive (list current-prefix-arg nil
893 (if (consp last-input-event) last-input-event)))
891 (if defining-kbd-macro 894 (if defining-kbd-macro
892 (kmacro-end-macro nil)) 895 (kmacro-end-macro nil))
896 (if event (mouse-set-point event))
893 (kmacro-call-macro arg no-repeat)) 897 (kmacro-call-macro arg no-repeat))
894 898
895
896;;;###autoload 899;;;###autoload
897(defun kmacro-end-call-mouse (event) 900(define-obsolete-function-alias 'kmacro-end-call-mouse
898 "Move point to the position clicked with the mouse and call last kbd macro. 901 #'kmacro-end-and-call-macro "31.1")
899If kbd macro currently being defined end it before activating it."
900 (interactive "e")
901 (when defining-kbd-macro
902 (end-kbd-macro)
903 (when (and last-kbd-macro (= (length last-kbd-macro) 0))
904 (setq last-kbd-macro nil)
905 (message "Ignore empty macro")
906 ;; Don't call `kmacro-ring-empty-p' to avoid its messages.
907 (while (and (null last-kbd-macro) kmacro-ring)
908 (kmacro-pop-ring1))))
909 (mouse-set-point event)
910 (kmacro-call-macro nil t))
911
912 902
913;;; Misc. commands 903;;; Misc. commands
914 904
diff --git a/lisp/language/korea-util.el b/lisp/language/korea-util.el
index da91e692719..cca702f71b0 100644
--- a/lisp/language/korea-util.el
+++ b/lisp/language/korea-util.el
@@ -27,13 +27,22 @@
27 27
28;;; Code: 28;;; Code:
29 29
30(defgroup korean nil
31 "Options for writing Korean."
32 :version "31.1"
33 :group 'languages)
34
30;;;###autoload 35;;;###autoload
31(defvar default-korean-keyboard 36(defcustom default-korean-keyboard
32 (if (string-search "3" (or (getenv "HANGUL_KEYBOARD_TYPE") "")) 37 (if (string-search "3" (or (getenv "HANGUL_KEYBOARD_TYPE") ""))
33 "3" 38 "3"
34 "") 39 "")
35 "The kind of Korean keyboard for Korean (Hangul) input method. 40 "The kind of Korean keyboard for Korean (Hangul) input method.
36\"\" for 2, \"3\" for 3, and \"3f\" for 3f.") 41\"\" for 2, \"3\" for 3, and \"3f\" for 3f."
42 :initialize #'custom-initialize-delay
43 :group 'korean
44 :version "31.1"
45 :type 'string)
37 46
38;; functions useful for Korean text input 47;; functions useful for Korean text input
39 48
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index 44e8665eebd..f96cd43eca6 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -231,8 +231,8 @@ in the tool bar will close the current window where possible."
231 '(menu-item "Open Project Directory" project-dired 231 '(menu-item "Open Project Directory" project-dired
232 :enable (menu-bar-non-minibuffer-window-p) 232 :enable (menu-bar-non-minibuffer-window-p)
233 :help "Read the root directory of the current project, to operate on its files")) 233 :help "Read the root directory of the current project, to operate on its files"))
234 (define-key menu [dired] 234 (define-key menu [open-directory]
235 '(menu-item "Open Directory..." dired 235 '(menu-item "Open Directory..." dired-from-menubar
236 :enable (menu-bar-non-minibuffer-window-p) 236 :enable (menu-bar-non-minibuffer-window-p)
237 :help "Read a directory, to operate on its files")) 237 :help "Read a directory, to operate on its files"))
238 (define-key menu [project-open-file] 238 (define-key menu [project-open-file]
@@ -2287,7 +2287,7 @@ this frame."
2287 (and menu-bar-close-window 2287 (and menu-bar-close-window
2288 (window-parent (selected-window))))) 2288 (window-parent (selected-window)))))
2289 2289
2290(put 'dired 'menu-enable '(menu-bar-non-minibuffer-window-p)) 2290(put 'dired-from-menubar 'menu-enable '(menu-bar-non-minibuffer-window-p))
2291 2291
2292;; Permit deleting frame if it would leave a visible or iconified frame. 2292;; Permit deleting frame if it would leave a visible or iconified frame.
2293(defun delete-frame-enabled-p () 2293(defun delete-frame-enabled-p ()
@@ -2496,8 +2496,7 @@ It must accept a buffer as its only required argument.")
2496 ;; Ignore the initial frame if present. It can happen if 2496 ;; Ignore the initial frame if present. It can happen if
2497 ;; Emacs was started as a daemon. (bug#53740) 2497 ;; Emacs was started as a daemon. (bug#53740)
2498 (dolist (frame (frame-list)) 2498 (dolist (frame (frame-list))
2499 (unless (equal (terminal-name (frame-terminal frame)) 2499 (unless (frame-initial-p frame)
2500 "initial_terminal")
2501 (push frame frames))) 2500 (push frame frames)))
2502 ;; Make the menu of buffers proper. 2501 ;; Make the menu of buffers proper.
2503 (setq buffers-menu 2502 (setq buffers-menu
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 13d0e712821..94fc63440b4 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -2807,7 +2807,7 @@ has been requested by the completion table."
2807 "Update displayed *Completions* buffer after change in buffer contents." 2807 "Update displayed *Completions* buffer after change in buffer contents."
2808 (if (not (or (minibufferp nil t) completion-in-region-mode)) 2808 (if (not (or (minibufferp nil t) completion-in-region-mode))
2809 (remove-hook 'after-change-functions #'completions--after-change t) 2809 (remove-hook 'after-change-functions #'completions--after-change t)
2810 (when-let* ((window (get-buffer-window "*Completions*" 0))) 2810 (when-let* ((window (get-buffer-window "*Completions*" 'visible)))
2811 (when completion-auto-deselect 2811 (when completion-auto-deselect
2812 (with-selected-window window 2812 (with-selected-window window
2813 (completions--deselect)))) 2813 (completions--deselect))))
@@ -3480,7 +3480,7 @@ in the minibuffer window."
3480 3480
3481(defun minibuffer--completions-visible () 3481(defun minibuffer--completions-visible ()
3482 "Return the window where the current *Completions* buffer is visible, if any." 3482 "Return the window where the current *Completions* buffer is visible, if any."
3483 (when-let* ((window (get-buffer-window "*Completions*" 0))) 3483 (when-let* ((window (get-buffer-window "*Completions*" 'visible)))
3484 (let ((reference-buffer 3484 (let ((reference-buffer
3485 (buffer-local-value 'completion-reference-buffer 3485 (buffer-local-value 'completion-reference-buffer
3486 (window-buffer window)))) 3486 (window-buffer window))))
diff --git a/lisp/net/imap.el b/lisp/net/imap.el
index bb298d11d3c..a09cd730c0f 100644
--- a/lisp/net/imap.el
+++ b/lisp/net/imap.el
@@ -870,7 +870,8 @@ t if it successfully authenticates, nil otherwise."
870 (base64-encode-string 870 (base64-encode-string
871 (format "\000%s\000%s" 871 (format "\000%s\000%s"
872 (imap-quote-specials user) 872 (imap-quote-specials user)
873 (imap-quote-specials passwd))))))))) 873 (imap-quote-specials passwd))
874 t)))))))
874 875
875(defun imap-anonymous-p (_buffer) 876(defun imap-anonymous-p (_buffer)
876 t) 877 t)
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index c20b5df9b59..f6bfd9ebbea 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -451,21 +451,13 @@ Emacs dired can't find files."
451(defun tramp-adb-handle-file-name-all-completions (filename directory) 451(defun tramp-adb-handle-file-name-all-completions (filename directory)
452 "Like `file-name-all-completions' for Tramp files." 452 "Like `file-name-all-completions' for Tramp files."
453 (tramp-skeleton-file-name-all-completions filename directory 453 (tramp-skeleton-file-name-all-completions filename directory
454 (all-completions 454 (with-parsed-tramp-file-name (expand-file-name directory) nil
455 filename 455 (when (tramp-adb-do-ls v "-a" localname)
456 (with-parsed-tramp-file-name (expand-file-name directory) nil 456 (with-current-buffer (tramp-get-buffer v)
457 (with-tramp-file-property v localname "file-name-all-completions" 457 (mapcar
458 (when (tramp-adb-do-ls v "-a" localname) 458 (lambda (l)
459 (mapcar 459 (and (not (string-match-p (rx bol (* blank) eol) l)) l))
460 (lambda (f) 460 (split-string (buffer-string) "\n" 'omit)))))))
461 (if (file-directory-p (expand-file-name f directory))
462 (file-name-as-directory f)
463 f))
464 (with-current-buffer (tramp-get-buffer v)
465 (mapcar
466 (lambda (l)
467 (and (not (string-match-p (rx bol (* blank) eol) l)) l))
468 (split-string (buffer-string) "\n" 'omit))))))))))
469 461
470(defun tramp-adb-handle-file-local-copy (filename) 462(defun tramp-adb-handle-file-local-copy (filename)
471 "Like `file-local-copy' for Tramp files." 463 "Like `file-local-copy' for Tramp files."
diff --git a/lisp/net/tramp-container.el b/lisp/net/tramp-container.el
index 91d9b239a70..fec2e16a624 100644
--- a/lisp/net/tramp-container.el
+++ b/lisp/net/tramp-container.el
@@ -266,7 +266,7 @@ BODY is the backend specific code."
266 tramp--last-hop-directory) 266 tramp--last-hop-directory)
267 tramp-compat-temporary-file-directory)) 267 tramp-compat-temporary-file-directory))
268 (program (let ((tramp-verbose 0)) 268 (program (let ((tramp-verbose 0))
269 (tramp-get-method-parameter 269 (tramp-expand-args
270 (make-tramp-file-name :method ,method) 270 (make-tramp-file-name :method ,method)
271 'tramp-login-program))) 271 'tramp-login-program)))
272 (vec (when (tramp-tramp-file-p default-directory) 272 (vec (when (tramp-tramp-file-p default-directory)
@@ -656,10 +656,9 @@ see its function help for a description of the format."
656 '((tramp-config-check . tramp-kubernetes--current-context-data) 656 '((tramp-config-check . tramp-kubernetes--current-context-data)
657 ;; This variable will be eval'ed in `tramp-expand-args'. 657 ;; This variable will be eval'ed in `tramp-expand-args'.
658 (tramp-extra-expand-args 658 (tramp-extra-expand-args
659 . (?a (tramp-kubernetes--container (car tramp-current-connection)) 659 ?a (tramp-kubernetes--container (car tramp-current-connection))
660 ?h (tramp-kubernetes--pod (car tramp-current-connection)) 660 ?h (tramp-kubernetes--pod (car tramp-current-connection))
661 ?x (tramp-kubernetes--context-namespace 661 ?x (tramp-kubernetes--context-namespace (car tramp-current-connection))))
662 (car tramp-current-connection)))))
663 "Default connection-local variables for remote kubernetes connections.") 662 "Default connection-local variables for remote kubernetes connections.")
664 663
665 (connection-local-set-profile-variables 664 (connection-local-set-profile-variables
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index 59e4cea2edb..4400f4fecd3 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -741,18 +741,16 @@ absolute file names."
741(defun tramp-crypt-handle-file-name-all-completions (filename directory) 741(defun tramp-crypt-handle-file-name-all-completions (filename directory)
742 "Like `file-name-all-completions' for Tramp files." 742 "Like `file-name-all-completions' for Tramp files."
743 (tramp-skeleton-file-name-all-completions filename directory 743 (tramp-skeleton-file-name-all-completions filename directory
744 (all-completions 744 (let* (completion-regexp-list
745 filename 745 tramp-crypt-enabled
746 (let* (completion-regexp-list 746 (directory (file-name-as-directory directory))
747 tramp-crypt-enabled 747 (enc-dir (tramp-crypt-encrypt-file-name directory)))
748 (directory (file-name-as-directory directory)) 748 (mapcar
749 (enc-dir (tramp-crypt-encrypt-file-name directory))) 749 (lambda (x)
750 (mapcar 750 (substring
751 (lambda (x) 751 (tramp-crypt-decrypt-file-name (concat enc-dir x))
752 (substring 752 (length directory)))
753 (tramp-crypt-decrypt-file-name (concat enc-dir x)) 753 (file-name-all-completions "" enc-dir)))))
754 (length directory)))
755 (file-name-all-completions "" enc-dir))))))
756 754
757(defun tramp-crypt-handle-file-readable-p (filename) 755(defun tramp-crypt-handle-file-readable-p (filename)
758 "Like `file-readable-p' for Tramp files." 756 "Like `file-readable-p' for Tramp files."
diff --git a/lisp/net/tramp-ftp.el b/lisp/net/tramp-ftp.el
index 7e140a0e372..601690befd6 100644
--- a/lisp/net/tramp-ftp.el
+++ b/lisp/net/tramp-ftp.el
@@ -49,7 +49,7 @@ present for backward compatibility."
49 (let ((a1 (rassq 'ange-ftp-hook-function file-name-handler-alist)) 49 (let ((a1 (rassq 'ange-ftp-hook-function file-name-handler-alist))
50 (a2 (rassq 'ange-ftp-completion-hook-function file-name-handler-alist))) 50 (a2 (rassq 'ange-ftp-completion-hook-function file-name-handler-alist)))
51 (setq file-name-handler-alist 51 (setq file-name-handler-alist
52 (delete a1 (delete a2 file-name-handler-alist))))) 52 (seq-difference file-name-handler-alist (list a1 a2)))))
53 53
54(with-eval-after-load 'ange-ftp 54(with-eval-after-load 'ange-ftp
55 (tramp-disable-ange-ftp)) 55 (tramp-disable-ange-ftp))
diff --git a/lisp/net/tramp-fuse.el b/lisp/net/tramp-fuse.el
index b3e59063cd8..f7abddab1a1 100644
--- a/lisp/net/tramp-fuse.el
+++ b/lisp/net/tramp-fuse.el
@@ -102,10 +102,7 @@
102 "Like `file-name-all-completions' for Tramp files." 102 "Like `file-name-all-completions' for Tramp files."
103 (tramp-skeleton-file-name-all-completions filename directory 103 (tramp-skeleton-file-name-all-completions filename directory
104 (tramp-fuse-remove-hidden-files 104 (tramp-fuse-remove-hidden-files
105 (all-completions 105 (file-name-all-completions "" (tramp-fuse-local-file-name directory)))))
106 filename
107 (file-name-all-completions
108 filename (tramp-fuse-local-file-name directory))))))
109 106
110;; This function isn't used. 107;; This function isn't used.
111(defun tramp-fuse-handle-insert-directory 108(defun tramp-fuse-handle-insert-directory
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index 0f68e4d768a..a5919e071c3 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -1479,19 +1479,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1479(defun tramp-gvfs-handle-file-name-all-completions (filename directory) 1479(defun tramp-gvfs-handle-file-name-all-completions (filename directory)
1480 "Like `file-name-all-completions' for Tramp files." 1480 "Like `file-name-all-completions' for Tramp files."
1481 (tramp-skeleton-file-name-all-completions filename directory 1481 (tramp-skeleton-file-name-all-completions filename directory
1482 (unless (string-search "/" filename) 1482 (mapcar #'car (tramp-gvfs-get-directory-attributes directory))))
1483 (all-completions
1484 filename
1485 (with-parsed-tramp-file-name (expand-file-name directory) nil
1486 (with-tramp-file-property v localname "file-name-all-completions"
1487 (let (result)
1488 ;; Get a list of directories and files.
1489 (dolist (item
1490 (tramp-gvfs-get-directory-attributes directory)
1491 result)
1492 (if (string-equal (cdr (assoc "type" item)) "directory")
1493 (push (file-name-as-directory (car item)) result)
1494 (push (car item) result))))))))))
1495 1483
1496(defun tramp-gvfs-handle-file-notify-add-watch (file-name flags _callback) 1484(defun tramp-gvfs-handle-file-notify-add-watch (file-name flags _callback)
1497 "Like `file-notify-add-watch' for Tramp files." 1485 "Like `file-notify-add-watch' for Tramp files."
@@ -1545,11 +1533,13 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1545 (when rest-string 1533 (when rest-string
1546 (tramp-message proc 10 "Previous string:\n%s" rest-string)) 1534 (tramp-message proc 10 "Previous string:\n%s" rest-string))
1547 (tramp-message proc 6 "%S\n%s" proc string) 1535 (tramp-message proc 6 "%S\n%s" proc string)
1548 (setq string (concat rest-string string) 1536 (setq string
1549 ;; Fix action names. 1537 (thread-last
1550 string (string-replace "attributes changed" "attribute-changed" string) 1538 (concat rest-string string)
1551 string (string-replace "changes done" "changes-done-hint" string) 1539 ;; Fix action names.
1552 string (string-replace "renamed to" "moved" string)) 1540 (string-replace "attributes changed" "attribute-changed")
1541 (string-replace "changes done" "changes-done-hint")
1542 (string-replace "renamed to" "moved")))
1553 ;; https://bugs.launchpad.net/bugs/1742946 1543 ;; https://bugs.launchpad.net/bugs/1742946
1554 (when 1544 (when
1555 (string-match-p 1545 (string-match-p
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index c83a7a9978d..9aec9e38f65 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -1993,48 +1993,39 @@ ID-FORMAT valid values are `string' and `integer'."
1993 "Like `file-name-all-completions' for Tramp files." 1993 "Like `file-name-all-completions' for Tramp files."
1994 (tramp-skeleton-file-name-all-completions filename directory 1994 (tramp-skeleton-file-name-all-completions filename directory
1995 (with-parsed-tramp-file-name (expand-file-name directory) nil 1995 (with-parsed-tramp-file-name (expand-file-name directory) nil
1996 (when (and (not (string-search "/" filename)) 1996 (let (result)
1997 (tramp-connectable-p v)) 1997 ;; Get a list of directories and files, including reliably
1998 (unless (string-search "/" filename) 1998 ;; tagging the directories with a trailing "/".
1999 (all-completions 1999 ;; Because I rock. --daniel@danann.net
2000 filename 2000 (if (tramp-get-remote-perl v)
2001 (with-tramp-file-property v localname "file-name-all-completions" 2001 (tramp-maybe-send-script
2002 (let (result) 2002 v tramp-perl-file-name-all-completions
2003 ;; Get a list of directories and files, including 2003 "tramp_perl_file_name_all_completions")
2004 ;; reliably tagging the directories with a trailing "/". 2004 (tramp-maybe-send-script
2005 ;; Because I rock. --daniel@danann.net 2005 v tramp-shell-file-name-all-completions
2006 (if (tramp-get-remote-perl v) 2006 "tramp_shell_file_name_all_completions"))
2007 (tramp-maybe-send-script 2007
2008 v tramp-perl-file-name-all-completions 2008 (dolist
2009 "tramp_perl_file_name_all_completions") 2009 (elt
2010 (tramp-maybe-send-script 2010 (tramp-send-command-and-read
2011 v tramp-shell-file-name-all-completions 2011 v (format
2012 "tramp_shell_file_name_all_completions")) 2012 "%s %s"
2013 2013 (if (tramp-get-remote-perl v)
2014 (dolist 2014 "tramp_perl_file_name_all_completions"
2015 (elt 2015 "tramp_shell_file_name_all_completions")
2016 (tramp-send-command-and-read 2016 (tramp-shell-quote-argument localname))
2017 v (format 2017 'noerror)
2018 "%s %s" 2018 result)
2019 (if (tramp-get-remote-perl v) 2019 ;; Don't cache "." and "..".
2020 "tramp_perl_file_name_all_completions" 2020 (when (string-match-p
2021 "tramp_shell_file_name_all_completions") 2021 directory-files-no-dot-files-regexp
2022 (tramp-shell-quote-argument localname)) 2022 (file-name-nondirectory (car elt)))
2023 'noerror) 2023 (tramp-set-file-property v (car elt) "file-exists-p" (nth 1 elt))
2024 result) 2024 (tramp-set-file-property v (car elt) "file-readable-p" (nth 2 elt))
2025 ;; Don't cache "." and "..". 2025 (tramp-set-file-property v (car elt) "file-directory-p" (nth 3 elt))
2026 (when (string-match-p 2026 (tramp-set-file-property v (car elt) "file-executable-p" (nth 4 elt)))
2027 directory-files-no-dot-files-regexp 2027
2028 (file-name-nondirectory (car elt))) 2028 (push (file-name-nondirectory (car elt)) result))))))
2029 (tramp-set-file-property v (car elt) "file-exists-p" (nth 1 elt))
2030 (tramp-set-file-property v (car elt) "file-readable-p" (nth 2 elt))
2031 (tramp-set-file-property v (car elt) "file-directory-p" (nth 3 elt))
2032 (tramp-set-file-property v (car elt) "file-executable-p" (nth 4 elt)))
2033
2034 (push
2035 (concat
2036 (file-name-nondirectory (car elt)) (and (nth 3 elt) "/"))
2037 result))))))))))
2038 2029
2039;; cp, mv and ln 2030;; cp, mv and ln
2040 2031
@@ -2803,7 +2794,7 @@ The method used must be an out-of-band method."
2803 (append switches (split-string (tramp-sh--quoting-style-options v)) 2794 (append switches (split-string (tramp-sh--quoting-style-options v))
2804 (when dired `(,dired)))) 2795 (when dired `(,dired))))
2805 (unless dired 2796 (unless dired
2806 (setq switches (delete "-N" (delete "--dired" switches))))) 2797 (setq switches (seq-difference switches '("-N" "--dired")))))
2807 (when wildcard 2798 (when wildcard
2808 (setq wildcard (tramp-run-real-handler 2799 (setq wildcard (tramp-run-real-handler
2809 #'file-name-nondirectory (list localname))) 2800 #'file-name-nondirectory (list localname)))
@@ -3917,11 +3908,13 @@ Fall back to normal file name handler if no Tramp handler exists."
3917 (when rest-string 3908 (when rest-string
3918 (tramp-message proc 10 "Previous string:\n%s" rest-string)) 3909 (tramp-message proc 10 "Previous string:\n%s" rest-string))
3919 (tramp-message proc 6 "%S\n%s" proc string) 3910 (tramp-message proc 6 "%S\n%s" proc string)
3920 (setq string (concat rest-string string) 3911 (setq string
3921 ;; Fix action names. 3912 (thread-last
3922 string (string-replace "attributes changed" "attribute-changed" string) 3913 (concat rest-string string)
3923 string (string-replace "changes done" "changes-done-hint" string) 3914 ;; Fix action names.
3924 string (string-replace "renamed to" "moved" string)) 3915 (string-replace "attributes changed" "attribute-changed")
3916 (string-replace "changes done" "changes-done-hint")
3917 (string-replace "renamed to" "moved")))
3925 3918
3926 (catch 'doesnt-work 3919 (catch 'doesnt-work
3927 ;; https://bugs.launchpad.net/bugs/1742946 3920 ;; https://bugs.launchpad.net/bugs/1742946
@@ -5044,7 +5037,7 @@ Goes through the list `tramp-inline-compress-commands'."
5044 ;; Use plink options. 5037 ;; Use plink options.
5045 ((string-match-p 5038 ((string-match-p
5046 (rx "plink" (? ".exe") eol) 5039 (rx "plink" (? ".exe") eol)
5047 (tramp-get-method-parameter vec 'tramp-login-program)) 5040 (tramp-expand-args vec 'tramp-login-program))
5048 (concat 5041 (concat
5049 (if (eq tramp-use-connection-share 'suppress) 5042 (if (eq tramp-use-connection-share 'suppress)
5050 "-noshare" "-share") 5043 "-noshare" "-share")
@@ -5405,7 +5398,7 @@ connection if a previous connection has died for some reason."
5405 hop 'tramp-connection-timeout 5398 hop 'tramp-connection-timeout
5406 tramp-connection-timeout)) 5399 tramp-connection-timeout))
5407 (command 5400 (command
5408 (tramp-get-method-parameter 5401 (tramp-expand-args
5409 hop 'tramp-login-program)) 5402 hop 'tramp-login-program))
5410 ;; We don't create the temporary file. In 5403 ;; We don't create the temporary file. In
5411 ;; fact, it is just a prefix for the 5404 ;; fact, it is just a prefix for the
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index 554aa354c00..8eec0e1bd08 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -603,12 +603,9 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
603 (copy-directory filename newname keep-date 'parents 'copy-contents) 603 (copy-directory filename newname keep-date 'parents 'copy-contents)
604 604
605 (tramp-barf-if-file-missing v filename 605 (tramp-barf-if-file-missing v filename
606 ;; `file-local-copy' returns a file name also for a local 606 ;; Suppress `jka-compr-handler'.
607 ;; file with `jka-compr-handler', so we cannot trust its 607 (if-let* ((jka-compr-inhibit t)
608 ;; result as indication for a remote file name. 608 (tmpfile (file-local-copy filename)))
609 (if-let* ((tmpfile
610 (and (tramp-tramp-file-p filename)
611 (file-local-copy filename))))
612 ;; Remote filename. 609 ;; Remote filename.
613 (condition-case err 610 (condition-case err
614 (rename-file tmpfile newname ok-if-already-exists) 611 (rename-file tmpfile newname ok-if-already-exists)
@@ -1068,18 +1065,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
1068(defun tramp-smb-handle-file-name-all-completions (filename directory) 1065(defun tramp-smb-handle-file-name-all-completions (filename directory)
1069 "Like `file-name-all-completions' for Tramp files." 1066 "Like `file-name-all-completions' for Tramp files."
1070 (tramp-skeleton-file-name-all-completions filename directory 1067 (tramp-skeleton-file-name-all-completions filename directory
1071 (all-completions 1068 (mapcar #'car (tramp-smb-get-file-entries directory))))
1072 filename
1073 (when (file-directory-p directory)
1074 (with-parsed-tramp-file-name (expand-file-name directory) nil
1075 (with-tramp-file-property v localname "file-name-all-completions"
1076 (mapcar
1077 (lambda (x)
1078 (list
1079 (if (string-search "d" (nth 1 x))
1080 (file-name-as-directory (nth 0 x))
1081 (nth 0 x))))
1082 (tramp-smb-get-file-entries directory))))))))
1083 1069
1084(defun tramp-smb-handle-file-system-info (filename) 1070(defun tramp-smb-handle-file-system-info (filename)
1085 "Like `file-system-info' for Tramp files." 1071 "Like `file-system-info' for Tramp files."
@@ -1752,9 +1738,6 @@ Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME YEAR)."
1752 (unless share 1738 (unless share
1753 (tramp-set-connection-property v "share-cache" res))) 1739 (tramp-set-connection-property v "share-cache" res)))
1754 1740
1755 ;; Add directory itself.
1756 (push '("" "drwxrwxrwx" 0 (0 0)) res)
1757
1758 ;; Return entries. 1741 ;; Return entries.
1759 (delq nil res))))) 1742 (delq nil res)))))
1760 1743
@@ -2295,9 +2278,6 @@ SHARE will be passed to the call of `tramp-smb-get-localname'."
2295 2278
2296;; * Return more comprehensive file permission string. 2279;; * Return more comprehensive file permission string.
2297;; 2280;;
2298;; * Try to remove the inclusion of dummy "" directory. Seems to be at
2299;; several places, especially in `tramp-smb-handle-insert-directory'.
2300;;
2301;; * Keep a separate connection process per share. 2281;; * Keep a separate connection process per share.
2302;; 2282;;
2303;; * Keep a permanent connection process for `process-file'. 2283;; * Keep a permanent connection process for `process-file'.
diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el
index 2cb5b5b1ed1..f4073158683 100644
--- a/lisp/net/tramp-sshfs.el
+++ b/lisp/net/tramp-sshfs.el
@@ -269,7 +269,7 @@ arguments to pass to the OPERATION."
269 (setq ret 269 (setq ret
270 (apply 270 (apply
271 #'tramp-call-process 271 #'tramp-call-process
272 v (tramp-get-method-parameter v 'tramp-login-program) 272 v (tramp-expand-args v 'tramp-login-program)
273 nil outbuf display 273 nil outbuf display
274 (tramp-expand-args 274 (tramp-expand-args
275 v 'tramp-login-args nil 275 v 'tramp-login-args nil
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index 9511c899b2b..8bf6a9f50b0 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -498,24 +498,16 @@ the result will be a local, non-Tramp, file name."
498(defun tramp-sudoedit-handle-file-name-all-completions (filename directory) 498(defun tramp-sudoedit-handle-file-name-all-completions (filename directory)
499 "Like `file-name-all-completions' for Tramp files." 499 "Like `file-name-all-completions' for Tramp files."
500 (tramp-skeleton-file-name-all-completions filename directory 500 (tramp-skeleton-file-name-all-completions filename directory
501 (all-completions 501 (with-parsed-tramp-file-name (expand-file-name directory) nil
502 filename 502 (tramp-sudoedit-send-command
503 (with-parsed-tramp-file-name (expand-file-name directory) nil 503 v "ls" "-a1" "--quoting-style=literal" "--show-control-chars"
504 (with-tramp-file-property v localname "file-name-all-completions" 504 (if (tramp-string-empty-or-nil-p localname)
505 (tramp-sudoedit-send-command 505 "" (file-name-unquote localname)))
506 v "ls" "-a1" "--quoting-style=literal" "--show-control-chars" 506 (mapcar
507 (if (tramp-string-empty-or-nil-p localname) 507 (lambda (l) (and (not (string-match-p (rx bol (* blank) eol) l)) l))
508 "" (file-name-unquote localname))) 508 (split-string
509 (mapcar 509 (tramp-get-buffer-string (tramp-get-connection-buffer v))
510 (lambda (f) 510 "\n" 'omit)))))
511 (if (ignore-errors (file-directory-p (expand-file-name f directory)))
512 (file-name-as-directory f)
513 f))
514 (mapcar
515 (lambda (l) (and (not (string-match-p (rx bol (* blank) eol) l)) l))
516 (split-string
517 (tramp-get-buffer-string (tramp-get-connection-buffer v))
518 "\n" 'omit))))))))
519 511
520(defun tramp-sudoedit-handle-file-readable-p (filename) 512(defun tramp-sudoedit-handle-file-readable-p (filename)
521 "Like `file-readable-p' for Tramp files." 513 "Like `file-readable-p' for Tramp files."
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 5441a26d7a0..03089dffb55 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -2002,12 +2002,11 @@ expected to be a string, which will be used."
2002 "Construct a Tramp hop name from VEC." 2002 "Construct a Tramp hop name from VEC."
2003 (concat 2003 (concat
2004 (tramp-file-name-hop vec) 2004 (tramp-file-name-hop vec)
2005 (replace-regexp-in-string 2005 (thread-last
2006 tramp-prefix-regexp "" 2006 (replace-regexp-in-string
2007 (replace-regexp-in-string 2007 (rx (regexp tramp-postfix-host-regexp) eos) tramp-postfix-hop-format
2008 (rx (regexp tramp-postfix-host-regexp) eos) 2008 (tramp-make-tramp-file-name (tramp-file-name-unify vec)))
2009 tramp-postfix-hop-format 2009 (replace-regexp-in-string tramp-prefix-regexp ""))))
2010 (tramp-make-tramp-file-name (tramp-file-name-unify vec))))))
2011 2010
2012(defun tramp-completion-make-tramp-file-name (method user host localname) 2011(defun tramp-completion-make-tramp-file-name (method user host localname)
2013 "Construct a Tramp file name from METHOD, USER, HOST and LOCALNAME. 2012 "Construct a Tramp file name from METHOD, USER, HOST and LOCALNAME.
@@ -2957,7 +2956,7 @@ not in completion mode."
2957 (or (and (cond 2956 (or (and (cond
2958 ;; Completion styles like `flex' and `substring' check for 2957 ;; Completion styles like `flex' and `substring' check for
2959 ;; the file name "/". This does exist. 2958 ;; the file name "/". This does exist.
2960 ((string-equal filename "/")) 2959 ((string-equal filename tramp-prefix-format))
2961 ;; Is it a valid method? 2960 ;; Is it a valid method?
2962 ((and (not (string-empty-p tramp-postfix-method-format)) 2961 ((and (not (string-empty-p tramp-postfix-method-format))
2963 (string-match 2962 (string-match
@@ -3001,30 +3000,59 @@ not in completion mode."
3001 3000
3002 (tramp-run-real-handler #'file-exists-p (list filename)))) 3001 (tramp-run-real-handler #'file-exists-p (list filename))))
3003 3002
3003(defvar tramp-fnac-add-trailing-slash t
3004 "Whether `file-name-all-completions' shall add a trailing slash.
3005This is not desired, if that function is used in `directory-files', or
3006in `tramp-completion-handle-file-name-all-completions'.")
3007
3004(defmacro tramp-skeleton-file-name-all-completions 3008(defmacro tramp-skeleton-file-name-all-completions
3005 (filename directory &rest body) 3009 (filename directory &rest body)
3006 "Skeleton for `tramp-*-handle-filename-all-completions'. 3010 "Skeleton for `tramp-*-handle-filename-all-completions'.
3007BODY is the backend specific code." 3011BODY is the backend specific code."
3008 (declare (indent 2) (debug t)) 3012 (declare (indent 2) (debug t))
3009 `(ignore-error file-missing 3013 `(ignore-error file-missing
3010 (seq-uniq (delq nil (delete "" 3014 (all-completions
3011 (let* ((case-fold-search read-file-name-completion-ignore-case) 3015 ,filename
3012 (result (progn ,@body))) 3016 (when (file-directory-p ,directory)
3013 ;; Some storage systems do not return "." and "..". 3017 (seq-uniq (delq nil
3014 (when (tramp-tramp-file-p ,directory) 3018 (let* ((case-fold-search read-file-name-completion-ignore-case)
3015 (dolist (elt '(".." ".")) 3019 (result
3016 (when (string-prefix-p ,filename elt) 3020 (if (tramp-tramp-file-p ,directory)
3017 (setq result (cons (concat elt "/") result))))) 3021 (with-parsed-tramp-file-name
3018 (if (consp completion-regexp-list) 3022 (expand-file-name ,directory) nil
3019 ;; Discriminate over `completion-regexp-list'. 3023 (when (and (not (string-search "/" ,filename))
3020 (mapcar 3024 (tramp-connectable-p v))
3021 (lambda (x) 3025 (with-tramp-file-property
3022 (when (stringp x) 3026 v localname
3023 (catch 'match 3027 (format
3024 (dolist (elt completion-regexp-list x) 3028 "file-name-all-completions-%s"
3025 (unless (string-match-p elt x) (throw 'match nil)))))) 3029 tramp-fnac-add-trailing-slash)
3026 result) 3030 ;; Mark symlinked directories. Other
3027 result))))))) 3031 ;; directories are already marked.
3032 (mapcar
3033 (lambda (x)
3034 (let ((f (file-name-concat ,directory x)))
3035 (if (and tramp-fnac-add-trailing-slash
3036 (not (string-suffix-p "/" x))
3037 (file-directory-p
3038 (if (file-symlink-p f)
3039 (file-truename f) f)))
3040 (concat x "/") x)))
3041 ;; Some storage systems do not return "." and "..".
3042 (seq-union
3043 (seq-difference (progn ,@body) '("." ".."))
3044 '("./" "../"))))))
3045 ,@body)))
3046 ;; Discriminate over `completion-regexp-list'.
3047 (if (consp completion-regexp-list)
3048 (mapcar
3049 (lambda (x)
3050 (when (stringp x)
3051 (catch 'match
3052 (dolist (elt completion-regexp-list x)
3053 (unless (string-match-p elt x) (throw 'match nil))))))
3054 result)
3055 result))))))))
3028 3056
3029(defvar tramp--last-hop-directory nil 3057(defvar tramp--last-hop-directory nil
3030 "Tracks the directory from which to run login programs.") 3058 "Tracks the directory from which to run login programs.")
@@ -3035,72 +3063,74 @@ BODY is the backend specific code."
3035;; completions. 3063;; completions.
3036(defun tramp-completion-handle-file-name-all-completions (filename directory) 3064(defun tramp-completion-handle-file-name-all-completions (filename directory)
3037 "Like `file-name-all-completions' for partial Tramp files." 3065 "Like `file-name-all-completions' for partial Tramp files."
3038 (tramp-skeleton-file-name-all-completions filename directory 3066 (let (tramp-fnac-add-trailing-slash)
3039 (let ((fullname 3067 (tramp-skeleton-file-name-all-completions filename directory
3040 (tramp-drop-volume-letter (expand-file-name filename directory))) 3068 (let ((fullname
3041 (directory (tramp-drop-volume-letter directory)) 3069 (tramp-drop-volume-letter (expand-file-name filename directory)))
3042 tramp--last-hop-directory hop result result1) 3070 (directory (tramp-drop-volume-letter directory))
3071 tramp--last-hop-directory hop result result1)
3072
3073 ;; Suppress hop from completion.
3074 (when (string-match
3075 (rx
3076 (regexp tramp-prefix-regexp)
3077 (group (+ (regexp tramp-remote-file-name-spec-regexp)
3078 (regexp tramp-postfix-hop-regexp))))
3079 fullname)
3080 (setq hop (match-string 1 fullname)
3081 fullname (replace-match "" nil nil fullname 1)
3082 tramp--last-hop-directory
3083 (tramp-make-tramp-file-name (tramp-dissect-hop-name hop))))
3084
3085 (let (tramp-default-user tramp-default-user-alist
3086 tramp-default-host tramp-default-host-alist)
3087
3088 ;; Possible completion structures.
3089 (dolist (elt (tramp-completion-dissect-file-name fullname))
3090 (let* ((method (tramp-file-name-method elt))
3091 (user (tramp-file-name-user elt))
3092 (host (tramp-file-name-host elt))
3093 (localname (tramp-file-name-localname elt))
3094 (m (tramp-find-method method user host))
3095 all-user-hosts)
3096
3097 (unless localname ;; Nothing to complete.
3098 (if (or user host)
3099 ;; Method dependent user / host combinations.
3100 (progn
3101 (mapc
3102 (lambda (x)
3103 (setq all-user-hosts
3104 (append all-user-hosts
3105 (funcall (nth 0 x) (nth 1 x)))))
3106 (tramp-get-completion-function m))
3043 3107
3044 ;; Suppress hop from completion. 3108 (setq result
3045 (when (string-match 3109 (append result
3046 (rx 3110 (mapcar
3047 (regexp tramp-prefix-regexp) 3111 (lambda (x)
3048 (group (+ (regexp tramp-remote-file-name-spec-regexp) 3112 (tramp-get-completion-user-host
3049 (regexp tramp-postfix-hop-regexp)))) 3113 method user host (nth 0 x) (nth 1 x)))
3050 fullname) 3114 all-user-hosts))))
3051 (setq hop (match-string 1 fullname) 3115
3052 fullname (replace-match "" nil nil fullname 1) 3116 ;; Possible methods.
3053 tramp--last-hop-directory 3117 (setq result
3054 (tramp-make-tramp-file-name (tramp-dissect-hop-name hop)))) 3118 (append result (tramp-get-completion-methods m hop)))))))
3055 3119
3056 (let (tramp-default-user tramp-default-user-alist 3120 ;; Add hop.
3057 tramp-default-host tramp-default-host-alist) 3121 (dolist (elt result)
3058 3122 (when elt
3059 ;; Possible completion structures. 3123 (setq elt (replace-regexp-in-string
3060 (dolist (elt (tramp-completion-dissect-file-name fullname)) 3124 tramp-prefix-regexp
3061 (let* ((method (tramp-file-name-method elt)) 3125 (concat tramp-prefix-format hop) elt))
3062 (user (tramp-file-name-user elt)) 3126 (push (substring elt (length directory)) result1)))
3063 (host (tramp-file-name-host elt)) 3127
3064 (localname (tramp-file-name-localname elt)) 3128 ;; Complete local parts.
3065 (m (tramp-find-method method user host)) 3129 (append
3066 all-user-hosts) 3130 result1
3067 3131 (ignore-errors
3068 (unless localname ;; Nothing to complete. 3132 (tramp-run-real-handler
3069 (if (or user host) 3133 #'file-name-all-completions (list filename directory)))))))))
3070 ;; Method dependent user / host combinations.
3071 (progn
3072 (mapc
3073 (lambda (x)
3074 (setq all-user-hosts
3075 (append all-user-hosts
3076 (funcall (nth 0 x) (nth 1 x)))))
3077 (tramp-get-completion-function m))
3078
3079 (setq result
3080 (append result
3081 (mapcar
3082 (lambda (x)
3083 (tramp-get-completion-user-host
3084 method user host (nth 0 x) (nth 1 x)))
3085 all-user-hosts))))
3086
3087 ;; Possible methods.
3088 (setq result
3089 (append result (tramp-get-completion-methods m hop)))))))
3090
3091 ;; Add hop.
3092 (dolist (elt result)
3093 (when elt
3094 (setq elt (replace-regexp-in-string
3095 tramp-prefix-regexp (concat tramp-prefix-format hop) elt))
3096 (push (substring elt (length directory)) result1)))
3097
3098 ;; Complete local parts.
3099 (append
3100 result1
3101 (ignore-errors
3102 (tramp-run-real-handler
3103 #'file-name-all-completions (list filename directory))))))))
3104 3134
3105;; Method, host name and user name completion for a file. 3135;; Method, host name and user name completion for a file.
3106(defun tramp-completion-handle-file-name-completion 3136(defun tramp-completion-handle-file-name-completion
@@ -3659,9 +3689,10 @@ BODY is the backend specific code."
3659 (signal 'error nil) 3689 (signal 'error nil)
3660 (setf ,directory 3690 (setf ,directory
3661 (file-name-as-directory (expand-file-name ,directory))) 3691 (file-name-as-directory (expand-file-name ,directory)))
3662 (let ((temp 3692 (let* (tramp-fnac-add-trailing-slash
3663 (with-tramp-file-property v localname "directory-files" ,@body)) 3693 (temp
3664 result item) 3694 (with-tramp-file-property v localname "directory-files" ,@body))
3695 result item)
3665 (while temp 3696 (while temp
3666 (setq item (directory-file-name (pop temp))) 3697 (setq item (directory-file-name (pop temp)))
3667 (when (or (null ,match) (string-match-p ,match item)) 3698 (when (or (null ,match) (string-match-p ,match item))
@@ -4496,8 +4527,8 @@ Let-bind it when necessary.")
4496 ;; "." and ".." are never interesting as completions, and are 4527 ;; "." and ".." are never interesting as completions, and are
4497 ;; actually in the way in a directory with only one file. See 4528 ;; actually in the way in a directory with only one file. See
4498 ;; file_name_completion() in dired.c. 4529 ;; file_name_completion() in dired.c.
4499 (when (and (consp fnac) (length= (delete "./" (delete "../" fnac)) 1)) 4530 (when (and (consp fnac) (length= (seq-difference fnac '("./" "../")) 1))
4500 (setq fnac (delete "./" (delete "../" fnac)))) 4531 (setq fnac (seq-difference fnac '("./" "../"))))
4501 (or 4532 (or
4502 (try-completion 4533 (try-completion
4503 filename fnac 4534 filename fnac
@@ -5294,7 +5325,7 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.")
5294(defvar tramp-extra-expand-args nil 5325(defvar tramp-extra-expand-args nil
5295 "Method specific arguments.") 5326 "Method specific arguments.")
5296 5327
5297(defun tramp-expand-args (vec parameter default &rest spec-list) 5328(defun tramp-expand-args (vec parameter &optional default &rest spec-list)
5298 "Expand login arguments as given by PARAMETER in `tramp-methods'. 5329 "Expand login arguments as given by PARAMETER in `tramp-methods'.
5299PARAMETER is a symbol like `tramp-login-args', denoting a list of 5330PARAMETER is a symbol like `tramp-login-args', denoting a list of
5300list of strings from `tramp-methods', containing %-sequences for 5331list of strings from `tramp-methods', containing %-sequences for
@@ -5317,12 +5348,15 @@ a connection-local variable."
5317 (setq spec-list (cddr spec-list))) 5348 (setq spec-list (cddr spec-list)))
5318 (setq spec (apply #'format-spec-make extra-spec-list)) 5349 (setq spec (apply #'format-spec-make extra-spec-list))
5319 ;; Expand format spec. 5350 ;; Expand format spec.
5320 (flatten-tree 5351 (cond
5321 (mapcar 5352 ((consp args)
5322 (lambda (x) 5353 (flatten-tree
5323 (setq x (mapcar (lambda (y) (tramp-format-spec y spec)) x)) 5354 (mapcar
5324 (unless (member "" x) x)) 5355 (lambda (x)
5325 args)))) 5356 (setq x (mapcar (lambda (y) (tramp-format-spec y spec)) x))
5357 (unless (member "" x) x))
5358 args)))
5359 (args (tramp-format-spec args spec)))))
5326 5360
5327(defun tramp-post-process-creation (proc vec) 5361(defun tramp-post-process-creation (proc vec)
5328 "Apply actions after creation of process PROC." 5362 "Apply actions after creation of process PROC."
@@ -5444,8 +5478,7 @@ processes."
5444 (tramp-get-method-parameter v 'tramp-direct-async) 5478 (tramp-get-method-parameter v 'tramp-direct-async)
5445 `(,(string-join command " "))) 5479 `(,(string-join command " ")))
5446 command)) 5480 command))
5447 (login-program 5481 (login-program (tramp-expand-args v 'tramp-login-program))
5448 (tramp-get-method-parameter v 'tramp-login-program))
5449 ;; We don't create the temporary file. In fact, it is just 5482 ;; We don't create the temporary file. In fact, it is just
5450 ;; a prefix for the ControlPath option of ssh; the real 5483 ;; a prefix for the ControlPath option of ssh; the real
5451 ;; temporary file has another name, and it is created and 5484 ;; temporary file has another name, and it is created and
@@ -5487,7 +5520,7 @@ processes."
5487 v 'tramp-login-args nil 5520 v 'tramp-login-args nil
5488 ?h (or host "") ?u (or user "") ?p (or port "") 5521 ?h (or host "") ?u (or user "") ?p (or port "")
5489 ?c (format-spec (or options "") (format-spec-make ?t tmpfile)) 5522 ?c (format-spec (or options "") (format-spec-make ?t tmpfile))
5490 ?d (or device "") ?a (or pta "") ?l "")))) 5523 ?w "" ?d (or device "") ?a (or pta "") ?l ""))))
5491 ;; Suppress `internal-default-process-sentinel', which is set 5524 ;; Suppress `internal-default-process-sentinel', which is set
5492 ;; when :sentinel is nil. (Bug#71049) 5525 ;; when :sentinel is nil. (Bug#71049)
5493 p (make-process 5526 p (make-process
diff --git a/lisp/obsolete/linum.el b/lisp/obsolete/linum.el
index 5a0a67ebff0..9b0efaf223a 100644
--- a/lisp/obsolete/linum.el
+++ b/lisp/obsolete/linum.el
@@ -129,6 +129,7 @@ Linum mode is a buffer-local minor mode."
129 ;; Note that nowadays, this actually doesn't show line 129 ;; Note that nowadays, this actually doesn't show line
130 ;; numbers in client frames at all, because we visit the 130 ;; numbers in client frames at all, because we visit the
131 ;; file before creating the client frame. See bug#35726. 131 ;; file before creating the client frame. See bug#35726.
132 ;; Use `frame-initial-p'?
132 (and (daemonp) (eq (selected-frame) terminal-frame))) 133 (and (daemonp) (eq (selected-frame) terminal-frame)))
133 (linum-mode 1))) 134 (linum-mode 1)))
134 135
diff --git a/lisp/outline.el b/lisp/outline.el
index 4fb953b0f7c..ea66ee5c8e9 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -326,10 +326,10 @@ non-nil and point is located on the heading line.")
326(defcustom outline-minor-mode-use-buttons nil 326(defcustom outline-minor-mode-use-buttons nil
327 "Whether to display clickable buttons on the headings. 327 "Whether to display clickable buttons on the headings.
328These buttons can be used to hide and show the body under the heading. 328These buttons can be used to hide and show the body under the heading.
329When the value is `insert', additional placeholders for buttons are 329When the value is \\+`insert', additional placeholders for buttons are
330inserted to the buffer, so buttons are not only clickable, 330inserted to the buffer, so buttons are not only clickable,
331but also typing `RET' on them can hide and show the body. 331but also typing `RET' on them can hide and show the body.
332Using the value `insert' is not recommended in editable 332Using the value \\+`insert' is not recommended in editable
333buffers because it modifies them. 333buffers because it modifies them.
334When the value is `in-margins', then clickable buttons are 334When the value is `in-margins', then clickable buttons are
335displayed in the margins before the headings. 335displayed in the margins before the headings.
@@ -513,7 +513,7 @@ font-lock faces defined by the major mode. Thus, a non-nil value will
513work well only when there's no such conflict. 513work well only when there's no such conflict.
514If the value is t, use outline faces only if there are no major mode's 514If the value is t, use outline faces only if there are no major mode's
515font-lock faces on headings. When `override', completely overwrite major 515font-lock faces on headings. When `override', completely overwrite major
516mode's font-lock faces with outline faces. When `append', try to append 516mode's font-lock faces with outline faces. When \\+`append', try to append
517outline font-lock faces to those of major mode." 517outline font-lock faces to those of major mode."
518 :type '(choice (const :tag "Do not use outline font-lock highlighting" nil) 518 :type '(choice (const :tag "Do not use outline font-lock highlighting" nil)
519 (const :tag "Overwrite major mode font-lock faces" override) 519 (const :tag "Overwrite major mode font-lock faces" override)
diff --git a/lisp/paren.el b/lisp/paren.el
index 1ab3f9a32cf..10c72dadc79 100644
--- a/lisp/paren.el
+++ b/lisp/paren.el
@@ -434,9 +434,10 @@ It is the default value of `show-paren-data-function'."
434 (overlay-put show-paren--context-overlay 'priority 434 (overlay-put show-paren--context-overlay 'priority
435 show-paren-priority) 435 show-paren-priority)
436 (overlay-put show-paren--context-overlay 436 (overlay-put show-paren--context-overlay
437 'face `(:box 437 'face `( :inherit default
438 ( :line-width (1 . -1) 438 :box
439 :color ,(face-attribute 'shadow :foreground)))) 439 ( :line-width (1 . -1)
440 :color ,(face-attribute 'shadow :foreground))))
440 (add-hook 'post-command-hook #'show-paren--delete-context-overlay 441 (add-hook 'post-command-hook #'show-paren--delete-context-overlay
441 nil 'local)) 442 nil 'local))
442 443
diff --git a/lisp/printing.el b/lisp/printing.el
index b6be982f5cb..3f31472d176 100644
--- a/lisp/printing.el
+++ b/lisp/printing.el
@@ -1431,7 +1431,7 @@ COMMAND Name of the program for printing a text file. On MS-DOS and
1431 specially, using NAME as the destination for output; any other 1431 specially, using NAME as the destination for output; any other
1432 program is treated like `lpr' except that an explicit filename 1432 program is treated like `lpr' except that an explicit filename
1433 is given as the last argument. 1433 is given as the last argument.
1434 If COMMAND is nil, it's used the default printing program: 1434 If COMMAND is nil, it stands for the default printing program:
1435 `print' for Windows system, `lp' for lp system and `lpr' for 1435 `print' for Windows system, `lp' for lp system and `lpr' for
1436 all other systems. See also `pr-path-alist'. 1436 all other systems. See also `pr-path-alist'.
1437 Examples: 1437 Examples:
@@ -1506,7 +1506,10 @@ Useful links:
1506 :type '(repeat 1506 :type '(repeat
1507 (list :tag "Text Printer" 1507 (list :tag "Text Printer"
1508 (symbol :tag "Printer Symbol Name") 1508 (symbol :tag "Printer Symbol Name")
1509 (string :tag "Printer Command") 1509 (choice :menu-tag "Printer Command"
1510 :tag "Printer Command"
1511 (const :tag "Default print command" nil)
1512 (string :tag "Explicit print command"))
1510 (repeat :tag "Printer Switches" 1513 (repeat :tag "Printer Switches"
1511 (sexp :tag "Switch" :value "")) 1514 (sexp :tag "Switch" :value ""))
1512 (choice :menu-tag "Printer Name" 1515 (choice :menu-tag "Printer Name"
@@ -1577,7 +1580,7 @@ COMMAND Name of the program for printing a PostScript file. On MS-DOS
1577 specially, using NAME as the destination for output; any other 1580 specially, using NAME as the destination for output; any other
1578 program is treated like `lpr' except that an explicit filename 1581 program is treated like `lpr' except that an explicit filename
1579 is given as the last argument. 1582 is given as the last argument.
1580 If COMMAND is nil, it's used the default printing program: 1583 If COMMAND is nil, it stands for the default printing program:
1581 `print' for Windows system, `lp' for lp system and `lpr' for 1584 `print' for Windows system, `lp' for lp system and `lpr' for
1582 all other systems. See also `pr-path-alist'. 1585 all other systems. See also `pr-path-alist'.
1583 Examples: 1586 Examples:
@@ -1756,7 +1759,10 @@ Useful links:
1756 (list 1759 (list
1757 :tag "PostScript Printer" 1760 :tag "PostScript Printer"
1758 (symbol :tag "Printer Symbol Name") 1761 (symbol :tag "Printer Symbol Name")
1759 (string :tag "Printer Command") 1762 (choice :menu-tag "Printer Command"
1763 :tag "Printer Command"
1764 (const :tag "Default print command" nil)
1765 (string :tag "Explicit print command"))
1760 (repeat :tag "Printer Switches" 1766 (repeat :tag "Printer Switches"
1761 (sexp :tag "Switch" :value "")) 1767 (sexp :tag "Switch" :value ""))
1762 (choice :menu-tag "Printer Name Switch" 1768 (choice :menu-tag "Printer Name Switch"
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 87273ec91c0..be67e8db78f 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -1567,6 +1567,7 @@ recommended to enable `electric-pair-mode' with this mode."
1567 (funcall c-ts-mode-indent-style) 1567 (funcall c-ts-mode-indent-style)
1568 (c-ts-mode--simple-indent-rules 1568 (c-ts-mode--simple-indent-rules
1569 'cpp c-ts-mode-indent-style))) 1569 'cpp c-ts-mode-indent-style)))
1570 (setq-local editorconfig-indent-size-vars '(c-ts-indent-offset))
1570 1571
1571 ;; Font-lock. 1572 ;; Font-lock.
1572 (setq-local treesit-font-lock-settings 1573 (setq-local treesit-font-lock-settings
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index 27b2e59409d..07974906a90 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -991,6 +991,8 @@ You might also use mode hooks to specify it in certain modes, like this:
991 (file-name-sans-extension buffer-file-name)))))))) 991 (file-name-sans-extension buffer-file-name))))))))
992 992
993It's often useful to leave a space at the end of the value." 993It's often useful to leave a space at the end of the value."
994 :group 'compilation
995 :initialize #'custom-initialize-delay
994 :type 'string) 996 :type 'string)
995;;;###autoload(put 'compile-command 'safe-local-variable (lambda (a) (and (stringp a) (if (boundp 'compilation-read-command) compilation-read-command t)))) 997;;;###autoload(put 'compile-command 'safe-local-variable (lambda (a) (and (stringp a) (if (boundp 'compilation-read-command) compilation-read-command t))))
996 998
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index a4f076a6197..0e1ed519b43 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -2,12 +2,12 @@
2 2
3;; Copyright (C) 2018-2026 Free Software Foundation, Inc. 3;; Copyright (C) 2018-2026 Free Software Foundation, Inc.
4 4
5;; Version: 1.21 5;; Version: 1.23
6;; Author: João Távora <joaotavora@gmail.com> 6;; Author: João Távora <joaotavora@gmail.com>
7;; Maintainer: João Távora <joaotavora@gmail.com> 7;; Maintainer: João Távora <joaotavora@gmail.com>
8;; URL: https://github.com/joaotavora/eglot 8;; URL: https://github.com/joaotavora/eglot
9;; Keywords: convenience, languages 9;; Keywords: convenience, languages
10;; Package-Requires: ((emacs "26.3") (eldoc "1.14.0") (external-completion "0.1") (flymake "1.4.2") (jsonrpc "1.0.26") (project "0.11.2") (seq "2.23") (xref "1.6.2")) 10;; 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"))
11 11
12;; This is a GNU ELPA :core package. Avoid adding functionality 12;; This is a GNU ELPA :core package. Avoid adding functionality
13;; that is not available in the version of Emacs recorded above or any 13;; that is not available in the version of Emacs recorded above or any
@@ -2710,10 +2710,11 @@ still unanswered LSP requests to the server\n"))))
2710 2710
2711(defconst eglot-mode-line-progress 2711(defconst eglot-mode-line-progress
2712 '(:eval 2712 '(:eval
2713 (when-let ((server (eglot-current-server))) 2713 (when-let ((s (eglot-current-server)))
2714 (cl-loop 2714 (cl-loop
2715 for pr hash-values of (eglot--progress-reporters server) 2715 for pr in (cl-delete 'eglot--mode-line-reporter
2716 when (eq (car pr) 'eglot--mode-line-reporter) 2716 (hash-table-values (eglot--progress-reporters s))
2717 :key #'car :test-not #'eq)
2717 for v = (nth 4 pr) 2718 for v = (nth 4 pr)
2718 when v sum 1 into n and sum v into acc 2719 when v sum 1 into n and sum v into acc
2719 collect (format "(%s) %s %s" (nth 1 pr) (nth 2 pr) (nth 3 pr)) 2720 collect (format "(%s) %s %s" (nth 1 pr) (nth 2 pr) (nth 3 pr))
@@ -4092,7 +4093,7 @@ for which LSP on-type-formatting should be requested."
4092 parameter 4093 parameter
4093 ;; ...perhaps highlight it in the formals list 4094 ;; ...perhaps highlight it in the formals list
4094 (when (eq i active-param) 4095 (when (eq i active-param)
4095 (save-excursion ;; FIXME: Sink into the `if' or hoist out of loop? 4096 (save-excursion
4096 (goto-char (point-min)) 4097 (goto-char (point-min))
4097 (pcase-let 4098 (pcase-let
4098 ((`(,beg ,end) 4099 ((`(,beg ,end)
@@ -4100,8 +4101,7 @@ for which LSP on-type-formatting should be requested."
4100 (let ((case-fold-search nil)) 4101 (let ((case-fold-search nil))
4101 (and (search-forward parlabel (line-end-position) t) 4102 (and (search-forward parlabel (line-end-position) t)
4102 (list (match-beginning 0) (match-end 0)))) 4103 (list (match-beginning 0) (match-end 0))))
4103 (list (+ (point-min) (aref parlabel 0)) 4104 (list (1+ (aref parlabel 0)) (1+ (aref parlabel 1))))))
4104 (+ (point-min) (aref parlabel 1))))))
4105 (if (and beg end) 4105 (if (and beg end)
4106 (add-face-text-property 4106 (add-face-text-property
4107 beg end 4107 beg end
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 4e828eba8a0..f62f9f5ce3c 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -1330,6 +1330,8 @@ Interactively, with a prefix arg, FORCE is t."
1330 (buffer (current-buffer))) 1330 (buffer (current-buffer)))
1331 (cl-labels 1331 (cl-labels
1332 ((visible-buffer-window () 1332 ((visible-buffer-window ()
1333 ;; This can use `frame-initial-p' once
1334 ;; we can assume Emacs 31 or later.
1333 (and (or (not (daemonp)) 1335 (and (or (not (daemonp))
1334 (not (eq (selected-frame) terminal-frame))) 1336 (not (eq (selected-frame) terminal-frame)))
1335 (get-buffer-window (current-buffer)))) 1337 (get-buffer-window (current-buffer))))
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 128952a2dd4..72a05a082bb 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -1089,11 +1089,15 @@ list is empty)."
1089 match) 1089 match)
1090 (while (setq match (text-property-search-forward 'compilation-annotation)) 1090 (while (setq match (text-property-search-forward 'compilation-annotation))
1091 (add-text-properties (prop-match-beginning match) (prop-match-end match) 1091 (add-text-properties (prop-match-beginning match) (prop-match-end match)
1092 '(read-only t))) 1092 '(read-only t front-sticky t)))
1093 (goto-char (point-min)) 1093 (goto-char (point-min))
1094 (while (setq match (text-property-search-forward 'compilation-message)) 1094 (while (setq match (text-property-search-forward 'compilation-message))
1095 (add-text-properties (prop-match-beginning match) (prop-match-end match) 1095 (add-text-properties (prop-match-beginning match) (prop-match-end match)
1096 '(read-only t occur-prefix t)) 1096 '( read-only t occur-prefix t
1097 ;; Allow insertion of text right
1098 ;; after prefix, but not before.
1099 front-sticky t
1100 rear-nonsticky t))
1097 (let ((loc (compilation--message->loc (prop-match-value match))) 1101 (let ((loc (compilation--message->loc (prop-match-value match)))
1098 m) 1102 m)
1099 ;; Update the markers if necessary. 1103 ;; Update the markers if necessary.
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index ebf8df9f795..2c21d08d448 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -73,6 +73,7 @@
73(require 'cl-lib) 73(require 'cl-lib)
74(require 'ring) 74(require 'ring)
75(require 'project) 75(require 'project)
76(require 'text-property-search)
76 77
77(eval-and-compile 78(eval-and-compile
78 (when (version< emacs-version "28.0.60") 79 (when (version< emacs-version "28.0.60")
@@ -628,7 +629,7 @@ If SELECT is non-nil, select the target window."
628 (run-hooks 'xref-after-jump-hook))) 629 (run-hooks 'xref-after-jump-hook)))
629 630
630 631
631;;; XREF buffer (part of the UI) 632;;; Xref buffer (part of the UI)
632 633
633;; The xref buffer is used to display a set of xrefs. 634;; The xref buffer is used to display a set of xrefs.
634(defconst xref-buffer-name "*xref*" 635(defconst xref-buffer-name "*xref*"
@@ -1004,12 +1005,13 @@ point."
1004 (define-key map (kbd ".") #'xref-next-line) 1005 (define-key map (kbd ".") #'xref-next-line)
1005 (define-key map (kbd ",") #'xref-prev-line) 1006 (define-key map (kbd ",") #'xref-prev-line)
1006 (define-key map (kbd "M-,") #'xref-quit-and-pop-marker-stack) 1007 (define-key map (kbd "M-,") #'xref-quit-and-pop-marker-stack)
1008 (define-key map (kbd "e") #'xref-change-to-xref-edit-mode)
1007 map)) 1009 map))
1008 1010
1009(declare-function outline-search-text-property "outline" 1011(declare-function outline-search-text-property "outline"
1010 (property &optional value bound move backward looking-at)) 1012 (property &optional value bound move backward looking-at))
1011 1013
1012(define-derived-mode xref--xref-buffer-mode special-mode "XREF" 1014(define-derived-mode xref--xref-buffer-mode special-mode "Xref"
1013 "Mode for displaying cross-references." 1015 "Mode for displaying cross-references."
1014 (setq buffer-read-only t) 1016 (setq buffer-read-only t)
1015 (setq next-error-function #'xref--next-error-function) 1017 (setq next-error-function #'xref--next-error-function)
@@ -1039,7 +1041,7 @@ point."
1039 1041
1040(define-derived-mode xref--transient-buffer-mode 1042(define-derived-mode xref--transient-buffer-mode
1041 xref--xref-buffer-mode 1043 xref--xref-buffer-mode
1042 "XREF Transient.") 1044 "Xref Transient")
1043 1045
1044(defun xref--imenu-prev-index-position () 1046(defun xref--imenu-prev-index-position ()
1045 "Move point to previous line in `xref' buffer. 1047 "Move point to previous line in `xref' buffer.
@@ -1471,6 +1473,106 @@ between them by typing in the minibuffer with completion."
1471 'xref--show-defs-minibuffer #'xref-show-definitions-completing-read "28.1") 1473 'xref--show-defs-minibuffer #'xref-show-definitions-completing-read "28.1")
1472 1474
1473 1475
1476(defun xref-edit--prepare-buffer ()
1477 "Mark relevant regions read-only, and add relevant occur text-properties."
1478 (save-excursion
1479 (goto-char (point-min))
1480 (let ((inhibit-read-only t)
1481 match)
1482 (while (setq match (text-property-search-forward 'xref-group))
1483 (add-text-properties (prop-match-beginning match) (prop-match-end match)
1484 '( read-only t
1485 front-sticky t)))
1486 (goto-char (point-min))
1487 (while (setq match (text-property-search-forward 'xref-item))
1488 (let ((line-number-end (save-excursion
1489 (forward-line 0)
1490 (and (looking-at " *[0-9]+:")
1491 (match-end 0)))))
1492 (when line-number-end
1493 (add-text-properties (prop-match-beginning match) line-number-end
1494 '( read-only t
1495 occur-prefix t
1496 ;; Allow insertion of text right
1497 ;; after prefix, but not before.
1498 front-sticky t
1499 rear-nonsticky t))))))))
1500
1501(defvar xref-edit-mode-map
1502 (let ((map (make-sparse-keymap)))
1503 (define-key map (kbd "C-c C-c") #'xref-edit-save-changes)
1504 (define-key map (kbd "RET") #'xref-goto-xref)
1505 (define-key map (kbd "M-,") #'xref-quit-and-pop-marker-stack)
1506 (define-key map (kbd "C-o") #'xref-show-location-at-point)
1507 map)
1508 "Keymap for `xref-edit-mode'.")
1509
1510(defvar xref-edit-mode-hook nil
1511 "Hooks run when changing to Xref-Edit mode.")
1512
1513(defun xref-edit-mode ()
1514 "Major mode for editing *xref* buffers.
1515In this mode, changes to the *xref* buffer are applied to the
1516originating files.
1517\\<xref-edit-mode-map>
1518Type \\[xref-edit-save-changes] to exit Xref-Edit mode, return to Xref
1519mode.
1520
1521The only editable texts in an Xref-Edit buffer are the match results."
1522 (interactive)
1523 (error "This mode can be enabled only by `xref-change-to-xref-edit-mode'"))
1524(put 'xref-edit-mode 'mode-class 'special)
1525
1526(defun xref-change-to-xref-edit-mode ()
1527 "Switch to `xref-edit-mode' to edit *xref* buffer."
1528 (interactive)
1529 (unless (derived-mode-p 'xref--xref-buffer-mode)
1530 (error "Not an Xref buffer"))
1531 (use-local-map xref-edit-mode-map)
1532 (xref-edit--prepare-buffer)
1533 (setq buffer-read-only nil)
1534 (setq major-mode 'xref-edit-mode)
1535 (setq mode-name "Xref-Edit")
1536 (buffer-enable-undo)
1537 (set-buffer-modified-p nil)
1538 (setq buffer-undo-list nil)
1539 (add-hook 'before-change-functions #'xref-edit--before-change-function nil t)
1540 (add-hook 'after-change-functions #'occur-after-change-function nil t)
1541 (run-mode-hooks 'xref-edit-mode-hook)
1542 (message (substitute-command-keys
1543 "Editing: Type \\[xref-edit-save-changes] to return to Xref mode")))
1544
1545(defun xref-edit-save-changes ()
1546 "Switch back to Xref mode."
1547 (interactive)
1548 (unless (derived-mode-p 'xref-edit-mode)
1549 (error "Not a Xref-Edit buffer"))
1550 (remove-hook 'before-change-functions #'xref-edit--before-change-function t)
1551 (remove-hook 'after-change-functions #'occur-after-change-function t)
1552 (use-local-map xref--xref-buffer-mode-map)
1553 (setq buffer-read-only t)
1554 (setq major-mode 'xref--xref-buffer-mode)
1555 (setq mode-name "Xref")
1556 (force-mode-line-update)
1557 (buffer-disable-undo)
1558 (setq buffer-undo-list t)
1559 (let ((inhibit-read-only t))
1560 (remove-text-properties (point-min) (point-max)
1561 '(occur-target nil occur-prefix nil)))
1562 (message "Switching to Xref mode"))
1563
1564(defun xref-edit--before-change-function (_beg _end)
1565 (when (and (not (get-text-property (pos-bol) 'occur-target))
1566 (get-text-property (pos-bol) 'occur-prefix))
1567 (let ((m (xref-location-marker (xref-item-location
1568 (get-text-property (pos-bol) 'xref-item))))
1569 (inhibit-read-only t)
1570 (inhibit-modification-hooks t)
1571 (buffer-undo-list t))
1572 (add-text-properties (pos-bol) (pos-eol)
1573 `(occur-target ((,m . ,m)))))))
1574
1575
1474(defcustom xref-show-xrefs-function 'xref--show-xref-buffer 1576(defcustom xref-show-xrefs-function 'xref--show-xref-buffer
1475 "Function to display a list of search results. 1577 "Function to display a list of search results.
1476 1578
diff --git a/lisp/server.el b/lisp/server.el
index fcfc6c01972..f5dea9c590f 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -706,6 +706,7 @@ the `server-process' variable."
706 ;; when we can't get user input, which may happen when 706 ;; when we can't get user input, which may happen when
707 ;; doing emacsclient --eval "(kill-emacs)" in daemon mode. 707 ;; doing emacsclient --eval "(kill-emacs)" in daemon mode.
708 (cond 708 (cond
709 ;; Use `frame-initial-p'?
709 ((and (daemonp) 710 ((and (daemonp)
710 (null (cdr (frame-list))) 711 (null (cdr (frame-list)))
711 (eq (selected-frame) terminal-frame)) 712 (eq (selected-frame) terminal-frame))
@@ -1429,6 +1430,7 @@ The following commands are accepted by the client:
1429 (or (eq use-current-frame 'always) 1430 (or (eq use-current-frame 'always)
1430 ;; We can't use the Emacs daemon's 1431 ;; We can't use the Emacs daemon's
1431 ;; terminal frame. 1432 ;; terminal frame.
1433 ;; Use `frame-initial-p'?
1432 (not (and (daemonp) 1434 (not (and (daemonp)
1433 (null (cdr (frame-list))) 1435 (null (cdr (frame-list)))
1434 (eq (selected-frame) 1436 (eq (selected-frame)
@@ -1453,6 +1455,7 @@ The following commands are accepted by the client:
1453 ;; If there won't be a current frame to use, fall 1455 ;; If there won't be a current frame to use, fall
1454 ;; back to trying to create a new one. 1456 ;; back to trying to create a new one.
1455 ((and use-current-frame 1457 ((and use-current-frame
1458 ;; Use `frame-initial-p'?
1456 (daemonp) 1459 (daemonp)
1457 (null (cdr (frame-list))) 1460 (null (cdr (frame-list)))
1458 (eq (selected-frame) terminal-frame) 1461 (eq (selected-frame) terminal-frame)
diff --git a/lisp/subr.el b/lisp/subr.el
index a1d718ca5b7..b0e04bc5f99 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -160,6 +160,10 @@ of previous VARs.
160 (push `(set-default ',(pop args) ,(pop args)) exps)) 160 (push `(set-default ',(pop args) ,(pop args)) exps))
161 `(progn . ,(nreverse exps)))) 161 `(progn . ,(nreverse exps))))
162 162
163(defun set-local (variable value)
164 "Make VARIABLE buffer local and set it to VALUE."
165 (set (make-local-variable variable) value))
166
163(defmacro setq-local (&rest pairs) 167(defmacro setq-local (&rest pairs)
164 "Make each VARIABLE local to current buffer and set it to corresponding VALUE. 168 "Make each VARIABLE local to current buffer and set it to corresponding VALUE.
165 169
@@ -181,7 +185,7 @@ In some corner cases you may need to resort to
181\(fn [VARIABLE VALUE]...)" 185\(fn [VARIABLE VALUE]...)"
182 (declare (debug setq)) 186 (declare (debug setq))
183 (unless (evenp (length pairs)) 187 (unless (evenp (length pairs))
184 (error "PAIRS must have an even number of variable/value members")) 188 (signal 'wrong-number-of-arguments (list 'setq-local (length pairs))))
185 (let ((expr nil)) 189 (let ((expr nil))
186 (while pairs 190 (while pairs
187 (unless (symbolp (car pairs)) 191 (unless (symbolp (car pairs))
@@ -229,7 +233,7 @@ in order to restore the state of the local variables set via this macro.
229\(fn [VARIABLE VALUE]...)" 233\(fn [VARIABLE VALUE]...)"
230 (declare (debug setq)) 234 (declare (debug setq))
231 (unless (evenp (length pairs)) 235 (unless (evenp (length pairs))
232 (error "PAIRS must have an even number of variable/value members")) 236 (signal 'wrong-number-of-arguments (list 'buffer-local-set-state (length pairs))))
233 (let ((vars nil) 237 (let ((vars nil)
234 (tmp pairs)) 238 (tmp pairs))
235 (while tmp (push (car tmp) vars) (setq tmp (cddr tmp))) 239 (while tmp (push (car tmp) vars) (setq tmp (cddr tmp)))
@@ -1226,8 +1230,13 @@ with
1226 (member-if (lambda (x) (foo (bar x))) items)" 1230 (member-if (lambda (x) (foo (bar x))) items)"
1227 (declare (compiler-macro 1231 (declare (compiler-macro
1228 (lambda (_) 1232 (lambda (_)
1229 (let ((x (make-symbol "x"))) 1233 (let* ((x (make-symbol "x"))
1230 `(drop-while (lambda (,x) (not (funcall ,pred ,x))) ,list))))) 1234 (f (and (not (internal--effect-free-fun-arg-p pred))
1235 (make-symbol "f")))
1236 (form `(drop-while (lambda (,x)
1237 (not (funcall ,(or f pred) ,x)))
1238 ,list)))
1239 (if f `(let ((,f ,pred)) ,form) form)))))
1231 (drop-while (lambda (x) (not (funcall pred x))) list)) 1240 (drop-while (lambda (x) (not (funcall pred x))) list))
1232 1241
1233;; This is good to have for improved readability in certain uses, but 1242;; This is good to have for improved readability in certain uses, but
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index ad749557987..3399e5ef93e 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -292,6 +292,7 @@ a list of frames to update."
292 (and (eq auto-resize-tab-bars 'grow-only) 292 (and (eq auto-resize-tab-bars 'grow-only)
293 (> (frame-parameter frame 'tab-bar-lines) 1)) 293 (> (frame-parameter frame 'tab-bar-lines) 1))
294 ;; Don't enable tab-bar in daemon's initial frame. 294 ;; Don't enable tab-bar in daemon's initial frame.
295 ;; Use `frame-initial-p'?
295 (and (daemonp) (eq frame terminal-frame))) 296 (and (daemonp) (eq frame terminal-frame)))
296 (set-frame-parameter frame 'tab-bar-lines 297 (set-frame-parameter frame 'tab-bar-lines
297 (tab-bar--tab-bar-lines-for-frame frame))))) 298 (tab-bar--tab-bar-lines-for-frame frame)))))
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index a56fc018e18..355555df090 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -3,7 +3,7 @@
3;; Copyright (C) 2006-2026 Free Software Foundation, Inc. 3;; Copyright (C) 2006-2026 Free Software Foundation, Inc.
4 4
5;; Author: Stefan Monnier <monnier@iro.umontreal.ca> 5;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
6;; Maintainer: Simen Heggestøyl <simenheg@gmail.com> 6;; Maintainer: Simen Heggestøyl <simenheg@runbox.com>
7;; Keywords: hypermedia 7;; Keywords: hypermedia
8 8
9;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
@@ -66,7 +66,7 @@
66 66
67(defconst css-pseudo-class-ids 67(defconst css-pseudo-class-ids
68 '("active" "checked" "default" "disabled" "empty" "enabled" "first" 68 '("active" "checked" "default" "disabled" "empty" "enabled" "first"
69 "first-child" "first-of-type" "focus" "focus-within" "hover" 69 "first-child" "first-of-type" "focus" "focus-within" "has" "hover"
70 "in-range" "indeterminate" "invalid" "lang" "last-child" 70 "in-range" "indeterminate" "invalid" "lang" "last-child"
71 "last-of-type" "left" "link" "not" "nth-child" "nth-last-child" 71 "last-of-type" "left" "link" "not" "nth-child" "nth-last-child"
72 "nth-last-of-type" "nth-of-type" "only-child" "only-of-type" 72 "nth-last-of-type" "nth-of-type" "only-child" "only-of-type"
diff --git a/lisp/textmodes/enriched.el b/lisp/textmodes/enriched.el
index a269cae0c9b..c5ae2a15557 100644
--- a/lisp/textmodes/enriched.el
+++ b/lisp/textmodes/enriched.el
@@ -390,6 +390,16 @@ which can be the value of the `face' text property."
390 (list (list "x-color" (cadr face)))) 390 (list (list "x-color" (cadr face))))
391 ((and (listp face) (eq (car face) :background)) 391 ((and (listp face) (eq (car face) :background))
392 (list (list "x-bg-color" (cadr face)))) 392 (list (list "x-bg-color" (cadr face))))
393 ((and (listp face) (eq (car face) :underline))
394 (list (list "underline")))
395 ((and (listp face)
396 (eq (car face) :weight)
397 (eq (cadr face) 'bold))
398 (list (list "bold")))
399 ((and (listp face)
400 (eq (car face) :slant)
401 (memq (cadr face) '(italic oblique)))
402 (list (list "italic")))
393 ((listp face) 403 ((listp face)
394 (apply #'append (mapcar #'enriched-face-ans face))) 404 (apply #'append (mapcar #'enriched-face-ans face)))
395 ((let* ((fg (face-attribute face :foreground)) 405 ((let* ((fg (face-attribute face :foreground))
diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el
index 9445b4a6b9a..c1ccdf2ec5f 100644
--- a/lisp/textmodes/fill.el
+++ b/lisp/textmodes/fill.el
@@ -1700,7 +1700,7 @@ and URL `https://rhodesmill.org/brandon/2012/one-sentence-per-line/'."
1700 (to (copy-marker (max from to) t)) 1700 (to (copy-marker (max from to) t))
1701 pfx) 1701 pfx)
1702 (goto-char from) 1702 (goto-char from)
1703 (let ((fill-column (* 2 (point-max)))) ; Wide characters span up to two columns. 1703 (let ((fill-column most-positive-fixnum))
1704 (setq pfx (or (save-excursion 1704 (setq pfx (or (save-excursion
1705 (fill-region-as-paragraph-default (point) 1705 (fill-region-as-paragraph-default (point)
1706 to 1706 to
diff --git a/lisp/textmodes/markdown-ts-mode.el b/lisp/textmodes/markdown-ts-mode.el
index cc3eaf03e15..657d6bc466d 100644
--- a/lisp/textmodes/markdown-ts-mode.el
+++ b/lisp/textmodes/markdown-ts-mode.el
@@ -40,6 +40,7 @@
40(require 'treesit) 40(require 'treesit)
41(require 'subr-x) 41(require 'subr-x)
42(require 'outline) 42(require 'outline)
43(require 'seq)
43 44
44(treesit-declare-unavailable-functions) 45(treesit-declare-unavailable-functions)
45 46
@@ -296,7 +297,12 @@ the same features enabled in MODE."
296 (plist-get configs :simple-indent))) 297 (plist-get configs :simple-indent)))
297 (setq treesit-range-settings 298 (setq treesit-range-settings
298 (append treesit-range-settings 299 (append treesit-range-settings
299 (plist-get configs :range))) 300 ;; Filter out function queries, because they are
301 ;; usually some hack and might escape the code block.
302 ;; Case in point: c-ts-mode's range setting.
303 (seq-filter (lambda (setting)
304 (not (functionp (car setting))))
305 (plist-get configs :range))))
300 (setq-local indent-line-function #'treesit-indent) 306 (setq-local indent-line-function #'treesit-indent)
301 (setq-local indent-region-function #'treesit-indent-region))) 307 (setq-local indent-region-function #'treesit-indent-region)))
302 308
diff --git a/lisp/time-stamp.el b/lisp/time-stamp.el
index b7f72f2619c..671cf5a1547 100644
--- a/lisp/time-stamp.el
+++ b/lisp/time-stamp.el
@@ -53,7 +53,7 @@ with %, which are converted as follows:
53%H 24-hour clock hour %I 12-hour clock hour 53%H 24-hour clock hour %I 12-hour clock hour
54%m month number 54%m month number
55%M minute 55%M minute
56%p meridian indicator: `AM', `PM' 56%p meridiem indicator: `AM', `PM'
57%S seconds 57%S seconds
58%w day number of week, Sunday is 0 58%w day number of week, Sunday is 0
59%Y 4-digit year %y 2-digit year 59%Y 4-digit year %y 2-digit year
@@ -1039,39 +1039,45 @@ This is an internal function called by `time-stamp'."
1039 offset-secs) 1039 offset-secs)
1040 "Format a time offset according to a %z variation. 1040 "Format a time offset according to a %z variation.
1041 1041
1042With no flags, the output includes hours and minutes: +-HHMM 1042Format parts FLAG-MINIMIZE, FLAG-PAD-SPACES-ONLY,
1043unless there is a non-zero seconds part, in which case the seconds 1043FLAG-PAD-ZEROS-FIRST, COLON-COUNT, and FIELD-WIDTH
1044are included: +-HHMMSS 1044are used to format time zone offset OFFSET-SECS.
1045
1046FLAG-MINIMIZE is whether \"-\" was specified. If non-nil, the
1047output may be limited to hours if minutes and seconds are zero.
1048
1049FLAG-PAD-SPACES-ONLY is whether \"_\" was specified. If non-nil,
1050seconds must be output, so that any padding can be spaces only.
1051
1052FLAG-PAD-ZEROS-FIRST is whether \"0\" was specified. If non-nil,
1053padding to the requested FIELD-WIDTH (if any) is done by adding
105400 seconds before padding with spaces.
1055
1056COLON-COUNT is the number of colons preceding the \"z\" (0-3). One or
1057two colons put that many colons in the output (+-HH:MM or +-HH:MM:SS).
1058Three colons outputs only hours if minutes and seconds are zero and
1059includes colon separators if minutes and seconds are output.
1060
1061FIELD-WIDTH is a whole number giving the minimum number of characters
1062in the output; 0 specifies no minimum. Additional characters will be
1063added on the right if necessary. The added characters will be spaces
1064unless FLAG-PAD-ZEROS-FIRST is non-nil.
1065
1066OFFSET-SECS is the time zone offset (in seconds east of UTC) to be
1067formatted according to the preceding parameters.
1068 1045
1069This is an internal function used by `time-stamp'." 1046This is an internal function used by `time-stamp'."
1047
1070 ;; Callers of this function need to have already parsed the %z 1048 ;; Callers of this function need to have already parsed the %z
1071 ;; format string; this function accepts just the parts of the format. 1049 ;; format string; this function accepts just the parts of the format.
1072 ;; `time-stamp-string-preprocess' is the full-fledged parser normally 1050 ;; `time-stamp-string-preprocess' is the full-fledged parser normally
1073 ;; used. The unit test (in time-stamp-tests.el) defines the simpler 1051 ;; used. The unit test (in time-stamp-tests.el) defines the simpler
1074 ;; parser `format-time-offset'. 1052 ;; parser `format-time-offset'.
1053
1054 ;; OFFSET-SECS is the time zone offset (in seconds east of UTC) to be
1055 ;; formatted according to the following parameters.
1056
1057 ;; FLAG-MINIMIZE is whether \"-\" was specified. If non-nil, the
1058 ;; output may be limited to hours if minutes and seconds are zero.
1059
1060 ;; FLAG-PAD-SPACES-ONLY is whether \"_\" was specified. If non-nil,
1061 ;; seconds must be output, so that any padding can be spaces only.
1062
1063 ;; FLAG-PAD-ZEROS-FIRST is whether \"0\" was specified. If non-nil,
1064 ;; padding to the requested FIELD-WIDTH (if any) is done by adding
1065 ;; 00 seconds before padding with spaces.
1066
1067 ;; COLON-COUNT is the number of colons preceding the \"z\" (0-3). One or
1068 ;; two colons put that many colons in the output (+-HH:MM or +-HH:MM:SS).
1069 ;; Three colons outputs only hours if minutes and seconds are zero and
1070 ;; includes colon separators if minutes and seconds are output.
1071
1072 ;; FIELD-WIDTH is a whole number giving the minimum number of characters
1073 ;; in the output; 0 specifies no minimum. Additional characters will be
1074 ;; added on the right if necessary. The added characters will be spaces
1075 ;; unless FLAG-PAD-ZEROS-FIRST is non-nil.
1076
1077 ;; With no flags set, the output includes hours and minutes: +-HHMM
1078 ;; unless there is a non-zero seconds part, in which case the seconds
1079 ;; are included: +-HHMMSS
1080
1075 (let ((hrs (/ (abs offset-secs) 3600)) 1081 (let ((hrs (/ (abs offset-secs) 3600))
1076 (mins (/ (% (abs offset-secs) 3600) 60)) 1082 (mins (/ (% (abs offset-secs) 3600) 60))
1077 (secs (% (abs offset-secs) 60)) 1083 (secs (% (abs offset-secs) 60))
diff --git a/lisp/tool-bar.el b/lisp/tool-bar.el
index 73df2e0bca8..d9b1f50b40c 100644
--- a/lisp/tool-bar.el
+++ b/lisp/tool-bar.el
@@ -330,7 +330,7 @@ holds a keymap."
330 :vert-only t) 330 :vert-only t)
331 (tool-bar-add-item-from-menu 'menu-find-file-existing "open" nil 331 (tool-bar-add-item-from-menu 'menu-find-file-existing "open" nil
332 :label "Open" :vert-only t) 332 :label "Open" :vert-only t)
333 (tool-bar-add-item-from-menu 'dired "diropen" nil :vert-only t) 333 (tool-bar-add-item-from-menu 'dired-from-menubar "diropen" nil :vert-only t)
334 (tool-bar-add-item-from-menu 'kill-this-buffer "close" nil :vert-only t) 334 (tool-bar-add-item-from-menu 'kill-this-buffer "close" nil :vert-only t)
335 (tool-bar-add-item-from-menu 'save-buffer "save" nil 335 (tool-bar-add-item-from-menu 'save-buffer "save" nil
336 :label "Save") 336 :label "Save")
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 7d6113e3249..14c05b0dd16 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -753,10 +753,10 @@ that encompasses the region between START and END."
753 (numberp (cdr range-offset))) 753 (numberp (cdr range-offset)))
754 (signal 'treesit-error (list "Value of :offset option should be a pair of numbers" range-offset))) 754 (signal 'treesit-error (list "Value of :offset option should be a pair of numbers" range-offset)))
755 (setq offset range-offset))) 755 (setq offset range-offset)))
756 (:range-fn (let ((range-fn (pop query-specs))) 756 (:range-fn (let ((fn (pop query-specs)))
757 (unless (functionp range-fn) 757 (unless (functionp fn)
758 (signal 'treesit-error (list "Value of :range-fn option should be a function" range-fn))) 758 (signal 'treesit-error (list "Value of :range-fn option should be a function" fn)))
759 (setq range-fn range-fn))) 759 (setq range-fn fn)))
760 (query (if (functionp query) 760 (query (if (functionp query)
761 (push (list query nil nil) result) 761 (push (list query nil nil) result)
762 (when (null embed) 762 (when (null embed)
@@ -1423,22 +1423,31 @@ LANGUAGE is the language of QUERY.")
1423 (setf (nth 1 new-setting) t) 1423 (setf (nth 1 new-setting) t)
1424 new-setting)) 1424 new-setting))
1425 1425
1426(defun treesit--font-lock-level-setter (sym val) 1426(defun treesit--font-lock-level-setter (sym val &optional buffer-local)
1427 "Custom setter for `treesit-font-lock-level'. 1427 "Custom setter for `treesit-font-lock-level'.
1428Set the default value of SYM to VAL, recompute fontification 1428Set the default value of SYM to VAL, recompute fontification
1429features and refontify for every buffer where tree-sitter-based 1429features and refontify for every buffer where tree-sitter-based
1430fontification is enabled." 1430fontification is enabled.
1431 (set-default sym val) 1431
1432 (when (treesit-available-p) 1432If optional BUFFER-LOCAL is non-nil, only affect the current buffer.
1433 (dolist (buffer (buffer-list)) 1433Set SYM buffer locally and refontify."
1434 (with-current-buffer buffer 1434 ;; FIXME: This doesn't re-run major mode hooks, meaning any
1435 ;; FIXME: This doesn't re-run major mode hooks, meaning any 1435 ;; customization done in major mode hooks (e.g., with
1436 ;; customization done in major mode hooks (e.g., with 1436 ;; `treesit-font-lock-recompute-features') may be overridden.
1437 ;; `treesit-font-lock-recompute-features') is lost. 1437 (cond (buffer-local
1438 (when treesit-font-lock-settings 1438 (set-local sym val)
1439 (treesit-font-lock-recompute-features) 1439 (when (and (treesit-available-p)
1440 (treesit-font-lock-fontify-region 1440 treesit-font-lock-settings)
1441 (point-min) (point-max))))))) 1441 (treesit-font-lock-recompute-features)
1442 (font-lock-flush)))
1443 (t
1444 (set-default sym val)
1445 (when (treesit-available-p)
1446 (dolist (buffer (buffer-list))
1447 (with-current-buffer buffer
1448 (when treesit-font-lock-settings
1449 (treesit-font-lock-recompute-features)
1450 (font-lock-flush))))))))
1442 1451
1443(defcustom treesit-font-lock-level 3 1452(defcustom treesit-font-lock-level 3
1444 "Decoration level to be used by tree-sitter fontifications. 1453 "Decoration level to be used by tree-sitter fontifications.
@@ -2050,9 +2059,8 @@ If LOUDLY is non-nil, display some debugging information."
2050 (pcase-let ((`(,max-depth ,max-width) 2059 (pcase-let ((`(,max-depth ,max-width)
2051 (treesit-subtree-stat 2060 (treesit-subtree-stat
2052 (treesit-buffer-root-node language)))) 2061 (treesit-buffer-root-node language))))
2053 (if (or (> max-depth 100) (> max-width 4000)) 2062 (setq treesit--font-lock-fast-mode
2054 (setq treesit--font-lock-fast-mode t) 2063 (or (> max-depth 100) (> max-width 4000)))))
2055 (setq treesit--font-lock-fast-mode nil))))
2056 2064
2057 ;; Only activate if ENABLE flag is t. 2065 ;; Only activate if ENABLE flag is t.
2058 (when-let* 2066 (when-let*
@@ -5849,7 +5857,7 @@ language."
5849 "Pattern matching" 5857 "Pattern matching"
5850 (treesit-query-capture 5858 (treesit-query-capture
5851 :no-eval (treesit-query-capture node '((identifier) @id "return" @ret)) 5859 :no-eval (treesit-query-capture node '((identifier) @id "return" @ret))
5852 :eg-result-string "((id . #<treesit-node (identifier) in 195-196>) (ret . #<treesit-node "return" in 338-344>))") 5860 :eg-result-string "((id . #<treesit-node (identifier) in 195-196>) (ret . #<treesit-node \"return\" in 338-344>))")
5853 (treesit-query-compile 5861 (treesit-query-compile
5854 :no-eval (treesit-query-compile 'c '((identifier) @id "return" @ret)) 5862 :no-eval (treesit-query-compile 'c '((identifier) @id "return" @ret))
5855 :eg-result-string "#<treesit-compiled-query>") 5863 :eg-result-string "#<treesit-compiled-query>")
diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el
index 042733f4c61..2dcae7362b7 100644
--- a/lisp/vc/vc-hooks.el
+++ b/lisp/vc/vc-hooks.el
@@ -977,6 +977,7 @@ In the latter case, VC mode is deactivated for this buffer."
977 noninteractive 977 noninteractive
978 ;; Copied from server-start. Seems like there should 978 ;; Copied from server-start. Seems like there should
979 ;; be a better way to ask "can we get user input?"... 979 ;; be a better way to ask "can we get user input?"...
980 ;; Use `frame-initial-p'?
980 (and (daemonp) 981 (and (daemonp)
981 (null (cdr (frame-list))) 982 (null (cdr (frame-list)))
982 (eq (selected-frame) terminal-frame)) 983 (eq (selected-frame) terminal-frame))
diff --git a/lisp/whitespace.el b/lisp/whitespace.el
index 9eb88eb35d0..50a687fe16b 100644
--- a/lisp/whitespace.el
+++ b/lisp/whitespace.el
@@ -907,9 +907,9 @@ means that `whitespace-mode' is turned on for buffers in C and
907C++ modes only. 907C++ modes only.
908 908
909Global `whitespace-mode' will not automatically turn on in internal 909Global `whitespace-mode' will not automatically turn on in internal
910buffers (with name starting from space) and special buffers (with name 910buffers (whose names start with a space) and special buffers (whose
911starting from \"*\"), except \"*scratch*\" buffer. Use 911names start with \"*\"), with the exception of the \"*scratch*\" buffer.
912`whitespace-global-mode-buffers' to customize this behavior." 912Use `whitespace-global-mode-buffers' to customize this behavior."
913 :type '(choice :tag "Global Modes" 913 :type '(choice :tag "Global Modes"
914 (const :tag "None" nil) 914 (const :tag "None" nil)
915 (const :tag "All" t) 915 (const :tag "All" t)
@@ -919,11 +919,11 @@ starting from \"*\"), except \"*scratch*\" buffer. Use
919 (repeat :inline t 919 (repeat :inline t
920 (symbol :tag "Mode"))))) 920 (symbol :tag "Mode")))))
921 921
922(defcustom whitespace-global-mode-buffers (list (regexp-quote "*scratch*")) 922(defcustom whitespace-global-mode-buffers (list (rx bos "*scratch*" eos))
923 "Buffer name regexps where global `whitespace-mode' can be auto-enabled. 923 "Buffer name regexps where global `whitespace-mode' can be auto-enabled.
924The value is a list of regexps. Set this custom option when you need 924The value is a list of regexps. Set this custom option when you need
925`whitespace-mode' in special buffers like *Org Src*." 925`whitespace-mode' in special buffers like \"*Org Src*\"."
926 :type '(list (regexp :tag "Regexp matching buffer name")) 926 :type '(repeat (regexp :tag "Regexp matching buffer name"))
927 :version "31.1") 927 :version "31.1")
928 928
929(defcustom whitespace-action nil 929(defcustom whitespace-action nil
@@ -1049,14 +1049,13 @@ See also `whitespace-newline' and `whitespace-display-mappings'."
1049 ;; ...we have a display (not running a batch job) 1049 ;; ...we have a display (not running a batch job)
1050 (not noninteractive) 1050 (not noninteractive)
1051 ;; ...the buffer is not internal (name starts with a space) 1051 ;; ...the buffer is not internal (name starts with a space)
1052 (not (eq (aref (buffer-name) 0) ?\ )) 1052 (not (eq (aref (buffer-name) 0) ?\s))
1053 ;; ...the buffer is not special (name starts with *) 1053 ;; ...the buffer is not special (name starts with *)
1054 (or (not (eq (aref (buffer-name) 0) ?*)) 1054 (or (not (eq (aref (buffer-name) 0) ?*))
1055 ;; except the scratch buffer. 1055 ;; except, e.g., the scratch buffer.
1056 (seq-find 1056 (any (lambda (re)
1057 (lambda (re) 1057 (string-match-p re (buffer-name)))
1058 (string-match-p re (buffer-name))) 1058 whitespace-global-mode-buffers))))
1059 whitespace-global-mode-buffers))))
1060 "Predicate to decide which buffers obey `global-whitespace-mode'. 1059 "Predicate to decide which buffers obey `global-whitespace-mode'.
1061This function is called with no argument and should return non-nil 1060This function is called with no argument and should return non-nil
1062if the current buffer should obey `global-whitespace-mode'. 1061if the current buffer should obey `global-whitespace-mode'.
diff --git a/lisp/window.el b/lisp/window.el
index 1f7ae726f49..bd0653fe0d4 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -1010,6 +1010,14 @@ and may be called only if no window on SIDE exists yet."
1010 (cons `(dedicated . ,(or display-buffer-mark-dedicated 'side)) 1010 (cons `(dedicated . ,(or display-buffer-mark-dedicated 'side))
1011 alist)))) 1011 alist))))
1012 (when window 1012 (when window
1013 ;; Protect the sibling (the main-window group) from recombination.
1014 ;; Without this, deleting a side window can flatten the group into
1015 ;; the root, causing subsequent side windows on other sides to be
1016 ;; placed incorrectly (Bug#80665).
1017 (when-let* ((sibling (or (window-prev-sibling window)
1018 (window-next-sibling window)))
1019 ((window-child sibling)))
1020 (set-window-combination-limit sibling t))
1013 ;; Initialize `window-side' parameter of new window to SIDE and 1021 ;; Initialize `window-side' parameter of new window to SIDE and
1014 ;; make that parameter persistent. 1022 ;; make that parameter persistent.
1015 (set-window-parameter window 'window-side side) 1023 (set-window-parameter window 'window-side side)
diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 67c475d563a..b93d914380f 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -509,16 +509,14 @@ enable, ?l to disable)."
509 "Enable xterm mouse tracking on TERMINAL." 509 "Enable xterm mouse tracking on TERMINAL."
510 (when (and xterm-mouse-mode (eq t (terminal-live-p terminal)) 510 (when (and xterm-mouse-mode (eq t (terminal-live-p terminal))
511 ;; Avoid the initial terminal which is not a termcap device. 511 ;; Avoid the initial terminal which is not a termcap device.
512 ;; FIXME: is there more elegant way to detect the initial 512 (not (frame-initial-p terminal)))
513 ;; terminal?
514 (not (string= (terminal-name terminal) "initial_terminal")))
515 (unless (terminal-parameter terminal 'xterm-mouse-mode) 513 (unless (terminal-parameter terminal 'xterm-mouse-mode)
516 ;; Simulate selecting a terminal by selecting one of its frames 514 ;; Simulate selecting a terminal by selecting one of its frames
517 ;; so that we can set the terminal-local `input-decode-map'. 515 ;; so that we can set the terminal-local `input-decode-map'.
518 ;; Use the tty-top-frame to avoid accidentally making an invisible 516 ;; Use the tty-top-frame to avoid accidentally making an invisible
519 ;; child frame visible by selecting it (bug#79960). 517 ;; child frame visible by selecting it (bug#79960).
520 ;; The test for match mode is here because xt-mouse-tests run in 518 ;; The test for batch mode is here because xt-mouse-tests run in
521 ;; match mode, and there is no top-frame in that case. 519 ;; batch mode, and there is no top-frame in that case.
522 (with-selected-frame (if noninteractive 520 (with-selected-frame (if noninteractive
523 (car (frame-list)) 521 (car (frame-list))
524 (tty-top-frame terminal)) 522 (tty-top-frame terminal))