diff options
| author | Andrea Corallo | 2020-08-09 15:03:23 +0200 |
|---|---|---|
| committer | Andrea Corallo | 2020-08-09 15:03:23 +0200 |
| commit | 12a982d9789052d8e85efcacb4b311f4876c882a (patch) | |
| tree | a452a8e888c6ee9c85d6a487359b7a1c0c9fa15b /lisp | |
| parent | 80d7f710f2fab902e46aa3fddb8e1c1795420af3 (diff) | |
| parent | 8e82baf5a730ff542118ddba5b76afdc1db643f6 (diff) | |
| download | emacs-12a982d9789052d8e85efcacb4b311f4876c882a.tar.gz emacs-12a982d9789052d8e85efcacb4b311f4876c882a.zip | |
Merge remote-tracking branch 'savannah/master' into HEAD
Diffstat (limited to 'lisp')
81 files changed, 2566 insertions, 1012 deletions
diff --git a/lisp/Makefile.in b/lisp/Makefile.in index 035720b49b7..9bcceceb0ee 100644 --- a/lisp/Makefile.in +++ b/lisp/Makefile.in | |||
| @@ -205,7 +205,6 @@ $(lisp)/finder-inf.el: | |||
| 205 | 205 | ||
| 206 | autoloads .PHONY: $(lisp)/loaddefs.el | 206 | autoloads .PHONY: $(lisp)/loaddefs.el |
| 207 | $(lisp)/loaddefs.el: gen-lisp $(LOADDEFS) | 207 | $(lisp)/loaddefs.el: gen-lisp $(LOADDEFS) |
| 208 | @echo Directories for loaddefs: ${SUBDIRS_ALMOST} | ||
| 209 | $(AM_V_GEN)$(emacs) -l autoload \ | 208 | $(AM_V_GEN)$(emacs) -l autoload \ |
| 210 | --eval '(setq autoload-ensure-writable t)' \ | 209 | --eval '(setq autoload-ensure-writable t)' \ |
| 211 | --eval '(setq autoload-builtin-package-versions t)' \ | 210 | --eval '(setq autoload-builtin-package-versions t)' \ |
diff --git a/lisp/arc-mode.el b/lisp/arc-mode.el index 6781c292d82..ae85fc55add 100644 --- a/lisp/arc-mode.el +++ b/lisp/arc-mode.el | |||
| @@ -391,6 +391,7 @@ file. Archive and member name will be added." | |||
| 391 | (define-key map "e" 'archive-extract) | 391 | (define-key map "e" 'archive-extract) |
| 392 | (define-key map "f" 'archive-extract) | 392 | (define-key map "f" 'archive-extract) |
| 393 | (define-key map "\C-m" 'archive-extract) | 393 | (define-key map "\C-m" 'archive-extract) |
| 394 | (define-key map "C" 'archive-copy-file) | ||
| 394 | (define-key map "m" 'archive-mark) | 395 | (define-key map "m" 'archive-mark) |
| 395 | (define-key map "n" 'archive-next-line) | 396 | (define-key map "n" 'archive-next-line) |
| 396 | (define-key map "\C-n" 'archive-next-line) | 397 | (define-key map "\C-n" 'archive-next-line) |
| @@ -430,6 +431,9 @@ file. Archive and member name will be added." | |||
| 430 | (define-key map [menu-bar immediate view] | 431 | (define-key map [menu-bar immediate view] |
| 431 | '(menu-item "View This File" archive-view | 432 | '(menu-item "View This File" archive-view |
| 432 | :help "Display file at cursor in View Mode")) | 433 | :help "Display file at cursor in View Mode")) |
| 434 | (define-key map [menu-bar immediate view] | ||
| 435 | '(menu-item "Copy This File" archive-copy-file | ||
| 436 | :help "Copy file at cursor to another location")) | ||
| 433 | (define-key map [menu-bar immediate display] | 437 | (define-key map [menu-bar immediate display] |
| 434 | '(menu-item "Display in Other Window" archive-display-other-window | 438 | '(menu-item "Display in Other Window" archive-display-other-window |
| 435 | :help "Display file at cursor in another window")) | 439 | :help "Display file at cursor in another window")) |
| @@ -989,6 +993,75 @@ using `make-temp-file', and the generated name is returned." | |||
| 989 | (kill-local-variable 'buffer-file-coding-system) | 993 | (kill-local-variable 'buffer-file-coding-system) |
| 990 | (after-insert-file-set-coding (- (point-max) (point-min)))))) | 994 | (after-insert-file-set-coding (- (point-max) (point-min)))))) |
| 991 | 995 | ||
| 996 | (defun archive-goto-file (file) | ||
| 997 | "Go to FILE in the current buffer. | ||
| 998 | FILE should be a relative file name. If FILE can't be found, | ||
| 999 | return nil. Otherwise point is returned." | ||
| 1000 | (let ((start (point)) | ||
| 1001 | found) | ||
| 1002 | (goto-char (point-min)) | ||
| 1003 | (while (and (not found) | ||
| 1004 | (not (eobp))) | ||
| 1005 | (forward-line 1) | ||
| 1006 | (when-let ((descr (archive-get-descr t))) | ||
| 1007 | (when (equal (archive--file-desc-ext-file-name descr) file) | ||
| 1008 | (setq found t)))) | ||
| 1009 | (if (not found) | ||
| 1010 | (progn | ||
| 1011 | (goto-char start) | ||
| 1012 | nil) | ||
| 1013 | (point)))) | ||
| 1014 | |||
| 1015 | (defun archive-next-file-displayer (file regexp n) | ||
| 1016 | "Return a closure to display the next file after FILE that matches REGEXP." | ||
| 1017 | (let ((short (replace-regexp-in-string "\\`.*:" "" file)) | ||
| 1018 | next) | ||
| 1019 | (archive-goto-file short) | ||
| 1020 | (while (and (not next) | ||
| 1021 | ;; Stop if we reach the end/start of the buffer. | ||
| 1022 | (if (> n 0) | ||
| 1023 | (not (eobp)) | ||
| 1024 | (not (save-excursion | ||
| 1025 | (beginning-of-line) | ||
| 1026 | (bobp))))) | ||
| 1027 | (archive-next-line n) | ||
| 1028 | (when-let ((descr (archive-get-descr t))) | ||
| 1029 | (let ((candidate (archive--file-desc-ext-file-name descr)) | ||
| 1030 | (buffer (current-buffer))) | ||
| 1031 | (when (and candidate | ||
| 1032 | (string-match-p regexp candidate)) | ||
| 1033 | (setq next (lambda () | ||
| 1034 | (kill-buffer (current-buffer)) | ||
| 1035 | (switch-to-buffer buffer) | ||
| 1036 | (archive-extract))))))) | ||
| 1037 | (unless next | ||
| 1038 | ;; If we didn't find a next/prev file, then restore | ||
| 1039 | ;; point. | ||
| 1040 | (archive-goto-file short)) | ||
| 1041 | next)) | ||
| 1042 | |||
| 1043 | (defun archive-copy-file (file new-name) | ||
| 1044 | "Copy FILE to a location specified by NEW-NAME. | ||
| 1045 | Interactively, FILE is the file at point, and the function prompts | ||
| 1046 | for NEW-NAME." | ||
| 1047 | (interactive | ||
| 1048 | (let ((name (archive--file-desc-ext-file-name (archive-get-descr)))) | ||
| 1049 | (list name | ||
| 1050 | (read-file-name (format "Copy %s to: " name))))) | ||
| 1051 | (when (file-directory-p new-name) | ||
| 1052 | (setq new-name (expand-file-name file new-name))) | ||
| 1053 | (when (and (file-exists-p new-name) | ||
| 1054 | (not (yes-or-no-p (format "%s already exists; overwrite? " | ||
| 1055 | new-name)))) | ||
| 1056 | (user-error "Not overwriting %s" new-name)) | ||
| 1057 | (let* ((descr (archive-get-descr)) | ||
| 1058 | (archive (buffer-file-name)) | ||
| 1059 | (extractor (archive-name "extract")) | ||
| 1060 | (ename (archive--file-desc-ext-file-name descr))) | ||
| 1061 | (with-temp-buffer | ||
| 1062 | (archive--extract-file extractor archive ename) | ||
| 1063 | (write-region (point-min) (point-max) new-name)))) | ||
| 1064 | |||
| 992 | (defun archive-extract (&optional other-window-p event) | 1065 | (defun archive-extract (&optional other-window-p event) |
| 993 | "In archive mode, extract this entry of the archive into its own buffer." | 1066 | "In archive mode, extract this entry of the archive into its own buffer." |
| 994 | (interactive (list nil last-input-event)) | 1067 | (interactive (list nil last-input-event)) |
| @@ -1030,26 +1103,7 @@ using `make-temp-file', and the generated name is returned." | |||
| 1030 | (setq archive-subfile-mode descr) | 1103 | (setq archive-subfile-mode descr) |
| 1031 | (setq archive-file-name-coding-system file-name-coding) | 1104 | (setq archive-file-name-coding-system file-name-coding) |
| 1032 | (if (and | 1105 | (if (and |
| 1033 | (null | 1106 | (null (archive--extract-file extractor archive ename)) |
| 1034 | (let (;; We may have to encode the file name argument for | ||
| 1035 | ;; external programs. | ||
| 1036 | (coding-system-for-write | ||
| 1037 | (and enable-multibyte-characters | ||
| 1038 | archive-file-name-coding-system)) | ||
| 1039 | ;; We read an archive member by no-conversion at | ||
| 1040 | ;; first, then decode appropriately by calling | ||
| 1041 | ;; archive-set-buffer-as-visiting-file later. | ||
| 1042 | (coding-system-for-read 'no-conversion) | ||
| 1043 | ;; Avoid changing dir mtime by lock_file | ||
| 1044 | (create-lockfiles nil)) | ||
| 1045 | (condition-case err | ||
| 1046 | (if (fboundp extractor) | ||
| 1047 | (funcall extractor archive ename) | ||
| 1048 | (archive-*-extract archive ename | ||
| 1049 | (symbol-value extractor))) | ||
| 1050 | (error | ||
| 1051 | (ding (message "%s" (error-message-string err))) | ||
| 1052 | nil)))) | ||
| 1053 | just-created) | 1107 | just-created) |
| 1054 | (progn | 1108 | (progn |
| 1055 | (set-buffer-modified-p nil) | 1109 | (set-buffer-modified-p nil) |
| @@ -1082,6 +1136,27 @@ using `make-temp-file', and the generated name is returned." | |||
| 1082 | (other-window-p (switch-to-buffer-other-window buffer)) | 1136 | (other-window-p (switch-to-buffer-other-window buffer)) |
| 1083 | (t (switch-to-buffer buffer)))))) | 1137 | (t (switch-to-buffer buffer)))))) |
| 1084 | 1138 | ||
| 1139 | (defun archive--extract-file (extractor archive ename) | ||
| 1140 | (let (;; We may have to encode the file name argument for | ||
| 1141 | ;; external programs. | ||
| 1142 | (coding-system-for-write | ||
| 1143 | (and enable-multibyte-characters | ||
| 1144 | archive-file-name-coding-system)) | ||
| 1145 | ;; We read an archive member by no-conversion at | ||
| 1146 | ;; first, then decode appropriately by calling | ||
| 1147 | ;; archive-set-buffer-as-visiting-file later. | ||
| 1148 | (coding-system-for-read 'no-conversion) | ||
| 1149 | ;; Avoid changing dir mtime by lock_file | ||
| 1150 | (create-lockfiles nil)) | ||
| 1151 | (condition-case err | ||
| 1152 | (if (fboundp extractor) | ||
| 1153 | (funcall extractor archive ename) | ||
| 1154 | (archive-*-extract archive ename | ||
| 1155 | (symbol-value extractor))) | ||
| 1156 | (error | ||
| 1157 | (ding (message "%s" (error-message-string err))) | ||
| 1158 | nil)))) | ||
| 1159 | |||
| 1085 | (defun archive-*-extract (archive name command) | 1160 | (defun archive-*-extract (archive name command) |
| 1086 | (let* ((default-directory (file-name-as-directory archive-tmpdir)) | 1161 | (let* ((default-directory (file-name-as-directory archive-tmpdir)) |
| 1087 | (tmpfile (expand-file-name (file-name-nondirectory name) | 1162 | (tmpfile (expand-file-name (file-name-nondirectory name) |
diff --git a/lisp/bookmark.el b/lisp/bookmark.el index de7d60f97eb..fb293adb779 100644 --- a/lisp/bookmark.el +++ b/lisp/bookmark.el | |||
| @@ -1667,6 +1667,19 @@ Don't affect the buffer ring order." | |||
| 1667 | 1667 | ||
| 1668 | 1668 | ||
| 1669 | ;;;###autoload | 1669 | ;;;###autoload |
| 1670 | (defun bookmark-bmenu-get-buffer () | ||
| 1671 | "Return the Bookmark List, building it if it doesn't exists. | ||
| 1672 | Don't affect the buffer ring order." | ||
| 1673 | (or (get-buffer bookmark-bmenu-buffer) | ||
| 1674 | (save-excursion | ||
| 1675 | (save-window-excursion | ||
| 1676 | (bookmark-bmenu-list) | ||
| 1677 | (get-buffer bookmark-bmenu-buffer))))) | ||
| 1678 | |||
| 1679 | (custom-add-choice 'tab-bar-new-tab-choice | ||
| 1680 | '(const :tag "Bookmark List" bookmark-bmenu-get-buffer)) | ||
| 1681 | |||
| 1682 | ;;;###autoload | ||
| 1670 | (defun bookmark-bmenu-list () | 1683 | (defun bookmark-bmenu-list () |
| 1671 | "Display a list of existing bookmarks. | 1684 | "Display a list of existing bookmarks. |
| 1672 | The list is displayed in a buffer named `*Bookmark List*'. | 1685 | The list is displayed in a buffer named `*Bookmark List*'. |
diff --git a/lisp/buff-menu.el b/lisp/buff-menu.el index 655a76a713c..aa5c47ca7f4 100644 --- a/lisp/buff-menu.el +++ b/lisp/buff-menu.el | |||
| @@ -69,11 +69,26 @@ minus `Buffer-menu-size-width'. This use is deprecated." | |||
| 69 | "use `Buffer-menu-name-width' and `Buffer-menu-size-width' instead." | 69 | "use `Buffer-menu-name-width' and `Buffer-menu-size-width' instead." |
| 70 | "24.3") | 70 | "24.3") |
| 71 | 71 | ||
| 72 | (defcustom Buffer-menu-name-width 19 | 72 | (defun Buffer-menu--dynamic-name-width (buffers) |
| 73 | "Width of buffer name column in the Buffer Menu." | 73 | "Return a name column width based on the current window width. |
| 74 | :type 'number | 74 | The width will never exceed the actual width of the buffer names, |
| 75 | but will never be narrower than 19 characters." | ||
| 76 | (max 19 | ||
| 77 | ;; This gives 19 on an 80 column window, and take up | ||
| 78 | ;; proportionally more space as the window widens. | ||
| 79 | (min (truncate (/ (window-width) 4.2)) | ||
| 80 | (apply #'max 0 (mapcar (lambda (b) | ||
| 81 | (length (buffer-name b))) | ||
| 82 | buffers))))) | ||
| 83 | |||
| 84 | (defcustom Buffer-menu-name-width #'Buffer-menu--dynamic-name-width | ||
| 85 | "Width of buffer name column in the Buffer Menu. | ||
| 86 | This can either be a number (used directly) or a function that | ||
| 87 | will be called with the list of buffers and should return a | ||
| 88 | number." | ||
| 89 | :type '(choice function number) | ||
| 75 | :group 'Buffer-menu | 90 | :group 'Buffer-menu |
| 76 | :version "24.3") | 91 | :version "28.1") |
| 77 | 92 | ||
| 78 | (defcustom Buffer-menu-size-width 7 | 93 | (defcustom Buffer-menu-size-width 7 |
| 79 | "Width of buffer size column in the Buffer Menu." | 94 | "Width of buffer size column in the Buffer Menu." |
| @@ -488,8 +503,9 @@ Buffers marked with \\<Buffer-menu-mode-map>`\\[Buffer-menu-delete]' are deleted | |||
| 488 | (defun Buffer-menu-select () | 503 | (defun Buffer-menu-select () |
| 489 | "Select this line's buffer; also, display buffers marked with `>'. | 504 | "Select this line's buffer; also, display buffers marked with `>'. |
| 490 | You can mark buffers with the \\<Buffer-menu-mode-map>`\\[Buffer-menu-mark]' command. | 505 | You can mark buffers with the \\<Buffer-menu-mode-map>`\\[Buffer-menu-mark]' command. |
| 506 | |||
| 491 | This command deletes and replaces all the previously existing windows | 507 | This command deletes and replaces all the previously existing windows |
| 492 | in the selected frame." | 508 | in the selected frame, and will remove any marks." |
| 493 | (interactive) | 509 | (interactive) |
| 494 | (let* ((this-buffer (Buffer-menu-buffer t)) | 510 | (let* ((this-buffer (Buffer-menu-buffer t)) |
| 495 | (menu-buffer (current-buffer)) | 511 | (menu-buffer (current-buffer)) |
| @@ -645,25 +661,11 @@ means list those buffers and no others." | |||
| 645 | 661 | ||
| 646 | (defun list-buffers--refresh (&optional buffer-list old-buffer) | 662 | (defun list-buffers--refresh (&optional buffer-list old-buffer) |
| 647 | ;; Set up `tabulated-list-format'. | 663 | ;; Set up `tabulated-list-format'. |
| 648 | (let ((name-width Buffer-menu-name-width) | 664 | (let ((size-width Buffer-menu-size-width) |
| 649 | (size-width Buffer-menu-size-width) | ||
| 650 | (marked-buffers (Buffer-menu-marked-buffers)) | 665 | (marked-buffers (Buffer-menu-marked-buffers)) |
| 651 | (buffer-menu-buffer (current-buffer)) | 666 | (buffer-menu-buffer (current-buffer)) |
| 652 | (show-non-file (not Buffer-menu-files-only)) | 667 | (show-non-file (not Buffer-menu-files-only)) |
| 653 | entries) | 668 | entries name-width) |
| 654 | ;; Handle obsolete variable: | ||
| 655 | (if Buffer-menu-buffer+size-width | ||
| 656 | (setq name-width (- Buffer-menu-buffer+size-width size-width))) | ||
| 657 | (setq tabulated-list-format | ||
| 658 | (vector '("C" 1 t :pad-right 0) | ||
| 659 | '("R" 1 t :pad-right 0) | ||
| 660 | '("M" 1 t) | ||
| 661 | `("Buffer" ,name-width t) | ||
| 662 | `("Size" ,size-width tabulated-list-entry-size-> | ||
| 663 | :right-align t) | ||
| 664 | `("Mode" ,Buffer-menu-mode-width t) | ||
| 665 | '("File" 1 t))) | ||
| 666 | (setq tabulated-list-use-header-line Buffer-menu-use-header-line) | ||
| 667 | ;; Collect info for each buffer we're interested in. | 669 | ;; Collect info for each buffer we're interested in. |
| 668 | (dolist (buffer (or buffer-list | 670 | (dolist (buffer (or buffer-list |
| 669 | (buffer-list (if Buffer-menu-use-frame-buffer-list | 671 | (buffer-list (if Buffer-menu-use-frame-buffer-list |
| @@ -693,6 +695,22 @@ means list those buffers and no others." | |||
| 693 | nil nil buffer))) | 695 | nil nil buffer))) |
| 694 | (Buffer-menu--pretty-file-name file))) | 696 | (Buffer-menu--pretty-file-name file))) |
| 695 | entries))))) | 697 | entries))))) |
| 698 | (setq name-width (if (functionp Buffer-menu-name-width) | ||
| 699 | (funcall Buffer-menu-name-width (mapcar #'car entries)) | ||
| 700 | Buffer-menu-name-width)) | ||
| 701 | ;; Handle obsolete variable: | ||
| 702 | (if Buffer-menu-buffer+size-width | ||
| 703 | (setq name-width (- Buffer-menu-buffer+size-width size-width))) | ||
| 704 | (setq tabulated-list-format | ||
| 705 | (vector '("C" 1 t :pad-right 0) | ||
| 706 | '("R" 1 t :pad-right 0) | ||
| 707 | '("M" 1 t) | ||
| 708 | `("Buffer" ,name-width t) | ||
| 709 | `("Size" ,size-width tabulated-list-entry-size-> | ||
| 710 | :right-align t) | ||
| 711 | `("Mode" ,Buffer-menu-mode-width t) | ||
| 712 | '("File" 1 t))) | ||
| 713 | (setq tabulated-list-use-header-line Buffer-menu-use-header-line) | ||
| 696 | (setq tabulated-list-entries (nreverse entries))) | 714 | (setq tabulated-list-entries (nreverse entries))) |
| 697 | (tabulated-list-init-header)) | 715 | (tabulated-list-init-header)) |
| 698 | 716 | ||
diff --git a/lisp/button.el b/lisp/button.el index d9c36a0375c..03ab59b109c 100644 --- a/lisp/button.el +++ b/lisp/button.el | |||
| @@ -464,8 +464,12 @@ see). | |||
| 464 | POS defaults to point, except when `push-button' is invoked | 464 | POS defaults to point, except when `push-button' is invoked |
| 465 | interactively as the result of a mouse-event, in which case, the | 465 | interactively as the result of a mouse-event, in which case, the |
| 466 | mouse event is used. | 466 | mouse event is used. |
| 467 | |||
| 467 | If there's no button at POS, do nothing and return nil, otherwise | 468 | If there's no button at POS, do nothing and return nil, otherwise |
| 468 | return t." | 469 | return t. |
| 470 | |||
| 471 | To get a description of what function will called when pushing a | ||
| 472 | butting, use the `button-describe' command." | ||
| 469 | (interactive | 473 | (interactive |
| 470 | (list (if (integerp last-command-event) (point) last-command-event))) | 474 | (list (if (integerp last-command-event) (point) last-command-event))) |
| 471 | (if (and (not (integerp pos)) (eventp pos)) | 475 | (if (and (not (integerp pos)) (eventp pos)) |
| @@ -555,6 +559,51 @@ Returns the button found." | |||
| 555 | (interactive "p\nd\nd") | 559 | (interactive "p\nd\nd") |
| 556 | (forward-button (- n) wrap display-message no-error)) | 560 | (forward-button (- n) wrap display-message no-error)) |
| 557 | 561 | ||
| 562 | (defun button--describe (properties) | ||
| 563 | "Describe a button's PROPERTIES (an alist) in a *Help* buffer. | ||
| 564 | This is a helper function for `button-describe', in order to be possible to | ||
| 565 | use `help-setup-xref'. | ||
| 566 | |||
| 567 | Each element of PROPERTIES should be of the form (PROPERTY . VALUE)." | ||
| 568 | (help-setup-xref (list #'button--describe properties) | ||
| 569 | (called-interactively-p 'interactive)) | ||
| 570 | (with-help-window (help-buffer) | ||
| 571 | (with-current-buffer (help-buffer) | ||
| 572 | (insert (format-message "This button's type is `%s'." | ||
| 573 | (alist-get 'type properties))) | ||
| 574 | (dolist (prop '(action mouse-action)) | ||
| 575 | (let ((name (symbol-name prop)) | ||
| 576 | (val (alist-get prop properties))) | ||
| 577 | (when (functionp val) | ||
| 578 | (insert "\n\n" | ||
| 579 | (propertize (capitalize name) 'face 'bold) | ||
| 580 | "\nThe " name " of this button is") | ||
| 581 | (if (symbolp val) | ||
| 582 | (progn | ||
| 583 | (insert (format-message " `%s',\nwhich is " val)) | ||
| 584 | (describe-function-1 val)) | ||
| 585 | (insert "\n") | ||
| 586 | (princ val)))))))) | ||
| 587 | |||
| 588 | (defun button-describe (&optional button-or-pos) | ||
| 589 | "Display a buffer with information about the button at point. | ||
| 590 | |||
| 591 | When called from Lisp, pass BUTTON-OR-POS as the button to describe, or a | ||
| 592 | buffer position where a button is present. If BUTTON-OR-POS is nil, the | ||
| 593 | button at point is the button to describe." | ||
| 594 | (interactive "d") | ||
| 595 | (let* ((button (cond ((integer-or-marker-p button-or-pos) | ||
| 596 | (button-at button-or-pos)) | ||
| 597 | ((null button-or-pos) (button-at (point))) | ||
| 598 | ((overlayp button-or-pos) button-or-pos))) | ||
| 599 | (props (and button | ||
| 600 | (mapcar (lambda (prop) | ||
| 601 | (cons prop (button-get button prop))) | ||
| 602 | '(type action mouse-action))))) | ||
| 603 | (when props | ||
| 604 | (button--describe props) | ||
| 605 | t))) | ||
| 606 | |||
| 558 | (provide 'button) | 607 | (provide 'button) |
| 559 | 608 | ||
| 560 | ;;; button.el ends here | 609 | ;;; button.el ends here |
diff --git a/lisp/calendar/cal-dst.el b/lisp/calendar/cal-dst.el index 3db12e668ab..af6acaf09ad 100644 --- a/lisp/calendar/cal-dst.el +++ b/lisp/calendar/cal-dst.el | |||
| @@ -350,17 +350,29 @@ If the locale never uses daylight saving time, set this to 0." | |||
| 350 | :group 'calendar-dst) | 350 | :group 'calendar-dst) |
| 351 | 351 | ||
| 352 | (defcustom calendar-standard-time-zone-name | 352 | (defcustom calendar-standard-time-zone-name |
| 353 | (or (nth 2 calendar-current-time-zone-cache) "EST") | 353 | (if calendar-use-numeric-time-zones |
| 354 | (if calendar-current-time-zone-cache | ||
| 355 | (format-time-string | ||
| 356 | "%z" 0 (* 60 (car calendar-current-time-zone-cache))) | ||
| 357 | "+0000") | ||
| 358 | (or (nth 2 calendar-current-time-zone-cache) "EST")) | ||
| 354 | "Abbreviated name of standard time zone at `calendar-location-name'. | 359 | "Abbreviated name of standard time zone at `calendar-location-name'. |
| 355 | For example, \"EST\" in New York City, \"PST\" for Los Angeles." | 360 | For example, \"EST\" in New York City, \"PST\" for Los Angeles." |
| 356 | :type 'string | 361 | :type 'string |
| 362 | :version "28.1" | ||
| 357 | :group 'calendar-dst) | 363 | :group 'calendar-dst) |
| 358 | 364 | ||
| 359 | (defcustom calendar-daylight-time-zone-name | 365 | (defcustom calendar-daylight-time-zone-name |
| 360 | (or (nth 3 calendar-current-time-zone-cache) "EDT") | 366 | (if calendar-use-numeric-time-zones |
| 367 | (if calendar-current-time-zone-cache | ||
| 368 | (format-time-string | ||
| 369 | "%z" 0 (* 60 (cadr calendar-current-time-zone-cache))) | ||
| 370 | "+0000") | ||
| 371 | (or (nth 3 calendar-current-time-zone-cache) "EDT")) | ||
| 361 | "Abbreviated name of daylight saving time zone at `calendar-location-name'. | 372 | "Abbreviated name of daylight saving time zone at `calendar-location-name'. |
| 362 | For example, \"EDT\" in New York City, \"PDT\" for Los Angeles." | 373 | For example, \"EDT\" in New York City, \"PDT\" for Los Angeles." |
| 363 | :type 'string | 374 | :type 'string |
| 375 | :version "28.1" | ||
| 364 | :group 'calendar-dst) | 376 | :group 'calendar-dst) |
| 365 | 377 | ||
| 366 | (defcustom calendar-daylight-savings-starts-time | 378 | (defcustom calendar-daylight-savings-starts-time |
diff --git a/lisp/calendar/calendar.el b/lisp/calendar/calendar.el index 1d5b9479e2b..0efb2bc6607 100644 --- a/lisp/calendar/calendar.el +++ b/lisp/calendar/calendar.el | |||
| @@ -1061,6 +1061,13 @@ calendar." | |||
| 1061 | :type 'boolean | 1061 | :type 'boolean |
| 1062 | :group 'holidays) | 1062 | :group 'holidays) |
| 1063 | 1063 | ||
| 1064 | (defcustom calendar-use-numeric-time-zones nil | ||
| 1065 | "If nil, use symbolic time zones like \"CET\" when displaying dates. | ||
| 1066 | If non-nil, use numeric time zones like \"+0100\"." | ||
| 1067 | :type 'boolean | ||
| 1068 | :version "28.1" | ||
| 1069 | :group 'calendar) | ||
| 1070 | |||
| 1064 | ;;; End of user options. | 1071 | ;;; End of user options. |
| 1065 | 1072 | ||
| 1066 | (calendar-recompute-layout-variables) | 1073 | (calendar-recompute-layout-variables) |
diff --git a/lisp/calendar/solar.el b/lisp/calendar/solar.el index 6a813e9ee82..635bdd8f11c 100644 --- a/lisp/calendar/solar.el +++ b/lisp/calendar/solar.el | |||
| @@ -209,7 +209,6 @@ Returns nil if nothing was entered." | |||
| 209 | 209 | ||
| 210 | (defun solar-setup () | 210 | (defun solar-setup () |
| 211 | "Prompt for `calendar-longitude', `calendar-latitude', `calendar-time-zone'." | 211 | "Prompt for `calendar-longitude', `calendar-latitude', `calendar-time-zone'." |
| 212 | (beep) | ||
| 213 | (or calendar-longitude | 212 | (or calendar-longitude |
| 214 | (setq calendar-longitude | 213 | (setq calendar-longitude |
| 215 | (solar-get-number | 214 | (solar-get-number |
| @@ -840,7 +839,9 @@ This function is suitable for execution in an init file." | |||
| 840 | "E" "W")))))) | 839 | "E" "W")))))) |
| 841 | (calendar-standard-time-zone-name | 840 | (calendar-standard-time-zone-name |
| 842 | (if (< arg 16) calendar-standard-time-zone-name | 841 | (if (< arg 16) calendar-standard-time-zone-name |
| 843 | (cond ((zerop calendar-time-zone) "UTC") | 842 | (cond ((zerop calendar-time-zone) |
| 843 | (if calendar-use-numeric-time-zones | ||
| 844 | "+0100" "UTC")) | ||
| 844 | ((< calendar-time-zone 0) | 845 | ((< calendar-time-zone 0) |
| 845 | (format "UTC%dmin" calendar-time-zone)) | 846 | (format "UTC%dmin" calendar-time-zone)) |
| 846 | (t (format "UTC+%dmin" calendar-time-zone))))) | 847 | (t (format "UTC+%dmin" calendar-time-zone))))) |
| @@ -1013,7 +1014,10 @@ Requires floating point." | |||
| 1013 | (let* ((m displayed-month) | 1014 | (let* ((m displayed-month) |
| 1014 | (y displayed-year) | 1015 | (y displayed-year) |
| 1015 | (calendar-standard-time-zone-name | 1016 | (calendar-standard-time-zone-name |
| 1016 | (if calendar-time-zone calendar-standard-time-zone-name "UTC")) | 1017 | (cond |
| 1018 | (calendar-time-zone calendar-standard-time-zone-name) | ||
| 1019 | (calendar-use-numeric-time-zones "+0100") | ||
| 1020 | (t "UTC"))) | ||
| 1017 | (calendar-daylight-savings-starts | 1021 | (calendar-daylight-savings-starts |
| 1018 | (if calendar-time-zone calendar-daylight-savings-starts)) | 1022 | (if calendar-time-zone calendar-daylight-savings-starts)) |
| 1019 | (calendar-daylight-savings-ends | 1023 | (calendar-daylight-savings-ends |
diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el index eeb09926a6e..125f9acc705 100644 --- a/lisp/calendar/time-date.el +++ b/lisp/calendar/time-date.el | |||
| @@ -527,6 +527,21 @@ TIME is modified and returned." | |||
| 527 | 527 | ||
| 528 | time) | 528 | time) |
| 529 | 529 | ||
| 530 | (defun decoded-time-period (time) | ||
| 531 | "Interpret DECODED as a period and return its length in seconds. | ||
| 532 | For computational purposes, years are 365 days long and months | ||
| 533 | are 30 days long." | ||
| 534 | (+ (if (consp (decoded-time-second time)) | ||
| 535 | ;; Fractional second. | ||
| 536 | (/ (float (car (decoded-time-second time))) | ||
| 537 | (cdr (decoded-time-second time))) | ||
| 538 | (or (decoded-time-second time) 0)) | ||
| 539 | (* (or (decoded-time-minute time) 0) 60) | ||
| 540 | (* (or (decoded-time-hour time) 0) 60 60) | ||
| 541 | (* (or (decoded-time-day time) 0) 60 60 24) | ||
| 542 | (* (or (decoded-time-month time) 0) 60 60 24 30) | ||
| 543 | (* (or (decoded-time-year time) 0) 60 60 24 365))) | ||
| 544 | |||
| 530 | (provide 'time-date) | 545 | (provide 'time-date) |
| 531 | 546 | ||
| 532 | ;;; time-date.el ends here | 547 | ;;; time-date.el ends here |
diff --git a/lisp/cus-dep.el b/lisp/cus-dep.el index e2c2ebe5f42..7c60916ee01 100644 --- a/lisp/cus-dep.el +++ b/lisp/cus-dep.el | |||
| @@ -70,7 +70,7 @@ Usage: emacs -batch -l ./cus-dep.el -f custom-make-dependencies DIRS" | |||
| 70 | (directory-files subdir nil | 70 | (directory-files subdir nil |
| 71 | "\\`[^=.].*\\.el\\'")))) | 71 | "\\`[^=.].*\\.el\\'")))) |
| 72 | (progress (make-progress-reporter | 72 | (progress (make-progress-reporter |
| 73 | (byte-compile-info-string "Scanning files for custom") | 73 | (byte-compile-info "Scanning files for custom") |
| 74 | 0 (length files) nil 10))) | 74 | 0 (length files) nil 10))) |
| 75 | (with-temp-buffer | 75 | (with-temp-buffer |
| 76 | (dolist (elem files) | 76 | (dolist (elem files) |
| @@ -128,8 +128,8 @@ Usage: emacs -batch -l ./cus-dep.el -f custom-make-dependencies DIRS" | |||
| 128 | type))))))))))) | 128 | type))))))))))) |
| 129 | (error nil))))))) | 129 | (error nil))))))) |
| 130 | (progress-reporter-done progress)) | 130 | (progress-reporter-done progress)) |
| 131 | (byte-compile-info-message "Generating %s..." | 131 | (byte-compile-info |
| 132 | generated-custom-dependencies-file) | 132 | (format "Generating %s..." generated-custom-dependencies-file) t) |
| 133 | (set-buffer (find-file-noselect generated-custom-dependencies-file)) | 133 | (set-buffer (find-file-noselect generated-custom-dependencies-file)) |
| 134 | (setq buffer-undo-list t) | 134 | (setq buffer-undo-list t) |
| 135 | (erase-buffer) | 135 | (erase-buffer) |
| @@ -218,8 +218,8 @@ elements the files that have variables or faces that contain that | |||
| 218 | version. These files should be loaded before showing the customization | 218 | version. These files should be loaded before showing the customization |
| 219 | buffer that `customize-changed-options' generates.\")\n\n")) | 219 | buffer that `customize-changed-options' generates.\")\n\n")) |
| 220 | (save-buffer) | 220 | (save-buffer) |
| 221 | (byte-compile-info-message "Generating %s...done" | 221 | (byte-compile-info |
| 222 | generated-custom-dependencies-file)) | 222 | (format "Generating %s...done" generated-custom-dependencies-file) t)) |
| 223 | 223 | ||
| 224 | 224 | ||
| 225 | (provide 'cus-dep) | 225 | (provide 'cus-dep) |
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 1942f25e891..16695967dfa 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el | |||
| @@ -4841,7 +4841,10 @@ The format is suitable for use with `easy-menu-define'." | |||
| 4841 | (error "You can't edit this part of the Custom buffer")) | 4841 | (error "You can't edit this part of the Custom buffer")) |
| 4842 | 4842 | ||
| 4843 | (defun Custom-newline (pos &optional event) | 4843 | (defun Custom-newline (pos &optional event) |
| 4844 | "Invoke button at POS, or refuse to allow editing of Custom buffer." | 4844 | "Invoke button at POS, or refuse to allow editing of Custom buffer. |
| 4845 | |||
| 4846 | To see what function the widget will call, use the | ||
| 4847 | `widget-describe' command." | ||
| 4845 | (interactive "@d") | 4848 | (interactive "@d") |
| 4846 | (let ((button (get-char-property pos 'button))) | 4849 | (let ((button (get-char-property pos 'button))) |
| 4847 | ;; If there is no button at point, then use the one at the start | 4850 | ;; If there is no button at point, then use the one at the start |
diff --git a/lisp/custom.el b/lisp/custom.el index 885c486c5e4..db7f6a056d4 100644 --- a/lisp/custom.el +++ b/lisp/custom.el | |||
| @@ -1541,6 +1541,20 @@ Each of the arguments ARGS has this form: | |||
| 1541 | This means reset VARIABLE. (The argument IGNORED is ignored)." | 1541 | This means reset VARIABLE. (The argument IGNORED is ignored)." |
| 1542 | (apply #'custom-theme-reset-variables 'user args)) | 1542 | (apply #'custom-theme-reset-variables 'user args)) |
| 1543 | 1543 | ||
| 1544 | (defun custom-add-choice (variable choice) | ||
| 1545 | "Add CHOICE to the custom type of VARIABLE. | ||
| 1546 | If a choice with the same tag already exists, no action is taken." | ||
| 1547 | (let ((choices (get variable 'custom-type))) | ||
| 1548 | (unless (eq (car choices) 'choice) | ||
| 1549 | (error "Not a choice type: %s" choices)) | ||
| 1550 | (unless (seq-find (lambda (elem) | ||
| 1551 | (equal (caddr (member :tag elem)) | ||
| 1552 | (caddr (member :tag choice)))) | ||
| 1553 | (cdr choices)) | ||
| 1554 | ;; Put the new choice at the end. | ||
| 1555 | (put variable 'custom-type | ||
| 1556 | (append choices (list choice)))))) | ||
| 1557 | |||
| 1544 | ;;; The End. | 1558 | ;;; The End. |
| 1545 | 1559 | ||
| 1546 | (provide 'custom) | 1560 | (provide 'custom) |
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index efb214088d8..84d8c36f45f 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el | |||
| @@ -688,7 +688,7 @@ are executed in the background on each file sequentially waiting | |||
| 688 | for each command to terminate before running the next command. | 688 | for each command to terminate before running the next command. |
| 689 | In shell syntax this means separating the individual commands with `;'. | 689 | In shell syntax this means separating the individual commands with `;'. |
| 690 | 690 | ||
| 691 | The output appears in the buffer `*Async Shell Command*'." | 691 | The output appears in the buffer `shell-command-buffer-name-async'." |
| 692 | (interactive | 692 | (interactive |
| 693 | (let ((files (dired-get-marked-files t current-prefix-arg nil nil t))) | 693 | (let ((files (dired-get-marked-files t current-prefix-arg nil nil t))) |
| 694 | (list | 694 | (list |
| @@ -727,7 +727,7 @@ it, write `*\"\"' in place of just `*'. This is equivalent to just | |||
| 727 | 727 | ||
| 728 | If COMMAND ends in `&', `;', or `;&', it is executed in the | 728 | If COMMAND ends in `&', `;', or `;&', it is executed in the |
| 729 | background asynchronously, and the output appears in the buffer | 729 | background asynchronously, and the output appears in the buffer |
| 730 | `*Async Shell Command*'. When operating on multiple files and COMMAND | 730 | `shell-command-buffer-name-async'. When operating on multiple files and COMMAND |
| 731 | ends in `&', the shell command is executed on each file in parallel. | 731 | ends in `&', the shell command is executed on each file in parallel. |
| 732 | However, when COMMAND ends in `;' or `;&' then commands are executed | 732 | However, when COMMAND ends in `;' or `;&' then commands are executed |
| 733 | in the background on each file sequentially waiting for each command | 733 | in the background on each file sequentially waiting for each command |
| @@ -735,7 +735,7 @@ to terminate before running the next command. You can also use | |||
| 735 | `dired-do-async-shell-command' that automatically adds `&'. | 735 | `dired-do-async-shell-command' that automatically adds `&'. |
| 736 | 736 | ||
| 737 | Otherwise, COMMAND is executed synchronously, and the output | 737 | Otherwise, COMMAND is executed synchronously, and the output |
| 738 | appears in the buffer `*Shell Command Output*'. | 738 | appears in the buffer `shell-command-buffer-name'. |
| 739 | 739 | ||
| 740 | This feature does not try to redisplay Dired buffers afterward, as | 740 | This feature does not try to redisplay Dired buffers afterward, as |
| 741 | there's no telling what files COMMAND may have changed. | 741 | there's no telling what files COMMAND may have changed. |
| @@ -952,13 +952,17 @@ With a prefix argument, kill that many lines starting with the current line. | |||
| 952 | "Kill all marked lines (not the files). | 952 | "Kill all marked lines (not the files). |
| 953 | With a prefix argument, kill that many lines starting with the current line. | 953 | With a prefix argument, kill that many lines starting with the current line. |
| 954 | \(A negative argument kills backward.) | 954 | \(A negative argument kills backward.) |
| 955 | |||
| 955 | If you use this command with a prefix argument to kill the line | 956 | If you use this command with a prefix argument to kill the line |
| 956 | for a file that is a directory, which you have inserted in the | 957 | for a file that is a directory, which you have inserted in the |
| 957 | Dired buffer as a subdirectory, then it deletes that subdirectory | 958 | Dired buffer as a subdirectory, then it deletes that subdirectory |
| 958 | from the buffer as well. | 959 | from the buffer as well. |
| 960 | |||
| 959 | To kill an entire subdirectory \(without killing its line in the | 961 | To kill an entire subdirectory \(without killing its line in the |
| 960 | parent directory), go to its directory header line and use this | 962 | parent directory), go to its directory header line and use this |
| 961 | command with a prefix argument (the value does not matter)." | 963 | command with a prefix argument (the value does not matter). |
| 964 | |||
| 965 | To undo the killing, the undo command can be used as normally." | ||
| 962 | ;; Returns count of killed lines. FMT="" suppresses message. | 966 | ;; Returns count of killed lines. FMT="" suppresses message. |
| 963 | (interactive "P") | 967 | (interactive "P") |
| 964 | (if arg | 968 | (if arg |
| @@ -1010,8 +1014,8 @@ command with a prefix argument (the value does not matter)." | |||
| 1010 | (defvar dired-compress-file-suffixes | 1014 | (defvar dired-compress-file-suffixes |
| 1011 | '( | 1015 | '( |
| 1012 | ;; "tar -zxf" isn't used because it's not available on the | 1016 | ;; "tar -zxf" isn't used because it's not available on the |
| 1013 | ;; Solaris10 version of tar. Solaris10 becomes obsolete in 2021. | 1017 | ;; Solaris 10 version of tar (obsolete in 2024?). |
| 1014 | ;; Same thing on AIX 7.1. | 1018 | ;; Same thing on AIX 7.1 (obsolete 2023?) and 7.2 (obsolete 2022?). |
| 1015 | ("\\.tar\\.gz\\'" "" "gzip -dc %i | tar -xf -") | 1019 | ("\\.tar\\.gz\\'" "" "gzip -dc %i | tar -xf -") |
| 1016 | ("\\.tgz\\'" "" "gzip -dc %i | tar -xf -") | 1020 | ("\\.tgz\\'" "" "gzip -dc %i | tar -xf -") |
| 1017 | ("\\.gz\\'" "" "gunzip") | 1021 | ("\\.gz\\'" "" "gunzip") |
| @@ -1974,6 +1978,10 @@ Optional arg HOW-TO determines how to treat the target. | |||
| 1974 | (apply (car into-dir) operation rfn-list fn-list target (cdr into-dir)) | 1978 | (apply (car into-dir) operation rfn-list fn-list target (cdr into-dir)) |
| 1975 | (if (not (or dired-one-file into-dir)) | 1979 | (if (not (or dired-one-file into-dir)) |
| 1976 | (error "Marked %s: target must be a directory: %s" operation target)) | 1980 | (error "Marked %s: target must be a directory: %s" operation target)) |
| 1981 | (if (and (not (file-directory-p (car fn-list))) | ||
| 1982 | (not (file-directory-p target)) | ||
| 1983 | (directory-name-p target)) | ||
| 1984 | (error "%s: Target directory does not exist: %s" operation target)) | ||
| 1977 | ;; rename-file bombs when moving directories unless we do this: | 1985 | ;; rename-file bombs when moving directories unless we do this: |
| 1978 | (or into-dir (setq target (directory-file-name target))) | 1986 | (or into-dir (setq target (directory-file-name target))) |
| 1979 | (dired-create-files | 1987 | (dired-create-files |
diff --git a/lisp/dired.el b/lisp/dired.el index 1792250ac90..d19d6d1581d 100644 --- a/lisp/dired.el +++ b/lisp/dired.el | |||
| @@ -125,7 +125,7 @@ For more details, see Info node `(emacs)ls in Lisp'." | |||
| 125 | "Informs Dired about how `ls -lF' marks symbolic links. | 125 | "Informs Dired about how `ls -lF' marks symbolic links. |
| 126 | Set this to t if `ls' (or whatever program is specified by | 126 | Set this to t if `ls' (or whatever program is specified by |
| 127 | `insert-directory-program') with `-lF' marks the symbolic link | 127 | `insert-directory-program') with `-lF' marks the symbolic link |
| 128 | itself with a trailing @ (usually the case under Ultrix). | 128 | itself with a trailing @ (usually the case under Ultrix and macOS). |
| 129 | 129 | ||
| 130 | Example: if `ln -s foo bar; ls -F bar' gives `bar -> foo', set it to | 130 | Example: if `ln -s foo bar; ls -F bar' gives `bar -> foo', set it to |
| 131 | nil (the default), if it gives `bar@ -> foo', set it to t. | 131 | nil (the default), if it gives `bar@ -> foo', set it to t. |
diff --git a/lisp/emacs-lisp/autoload.el b/lisp/emacs-lisp/autoload.el index d9da36586ce..05eb0ac5693 100644 --- a/lisp/emacs-lisp/autoload.el +++ b/lisp/emacs-lisp/autoload.el | |||
| @@ -1126,7 +1126,7 @@ write its autoloads into the specified file instead." | |||
| 1126 | ;; Elements remaining in FILES have no existing autoload sections yet. | 1126 | ;; Elements remaining in FILES have no existing autoload sections yet. |
| 1127 | (let ((no-autoloads-time (or last-time '(0 0 0 0))) | 1127 | (let ((no-autoloads-time (or last-time '(0 0 0 0))) |
| 1128 | (progress (make-progress-reporter | 1128 | (progress (make-progress-reporter |
| 1129 | (byte-compile-info-string | 1129 | (byte-compile-info |
| 1130 | (concat "Scraping files for " | 1130 | (concat "Scraping files for " |
| 1131 | (file-relative-name | 1131 | (file-relative-name |
| 1132 | generated-autoload-file))) | 1132 | generated-autoload-file))) |
| @@ -1169,6 +1169,19 @@ write its autoloads into the specified file instead." | |||
| 1169 | ;; file-local autoload-generated-file settings. | 1169 | ;; file-local autoload-generated-file settings. |
| 1170 | (autoload-save-buffers)))) | 1170 | (autoload-save-buffers)))) |
| 1171 | 1171 | ||
| 1172 | (defun batch-update-autoloads--summary (strings) | ||
| 1173 | (let ((message "")) | ||
| 1174 | (while strings | ||
| 1175 | (when (> (length (concat message " " (car strings))) 64) | ||
| 1176 | (byte-compile-info (concat message " ...") t "SCRAPE") | ||
| 1177 | (setq message "")) | ||
| 1178 | (setq message (if (zerop (length message)) | ||
| 1179 | (car strings) | ||
| 1180 | (concat message " " (car strings)))) | ||
| 1181 | (setq strings (cdr strings))) | ||
| 1182 | (when (> (length message) 0) | ||
| 1183 | (byte-compile-info message t "SCRAPE")))) | ||
| 1184 | |||
| 1172 | ;;;###autoload | 1185 | ;;;###autoload |
| 1173 | (defun batch-update-autoloads () | 1186 | (defun batch-update-autoloads () |
| 1174 | "Update loaddefs.el autoloads in batch mode. | 1187 | "Update loaddefs.el autoloads in batch mode. |
| @@ -1192,6 +1205,7 @@ should be non-nil)." | |||
| 1192 | (or (string-match "\\`site-" file) | 1205 | (or (string-match "\\`site-" file) |
| 1193 | (push (expand-file-name file) autoload-excludes))))))) | 1206 | (push (expand-file-name file) autoload-excludes))))))) |
| 1194 | (let ((args command-line-args-left)) | 1207 | (let ((args command-line-args-left)) |
| 1208 | (batch-update-autoloads--summary args) | ||
| 1195 | (setq command-line-args-left nil) | 1209 | (setq command-line-args-left nil) |
| 1196 | (apply #'update-directory-autoloads args))) | 1210 | (apply #'update-directory-autoloads args))) |
| 1197 | 1211 | ||
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 0d9c449b3b4..4987596bf95 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -648,14 +648,23 @@ | |||
| 648 | (setq args (cons (car rest) args))) | 648 | (setq args (cons (car rest) args))) |
| 649 | (setq rest (cdr rest))) | 649 | (setq rest (cdr rest))) |
| 650 | (if (cdr constants) | 650 | (if (cdr constants) |
| 651 | (if args | 651 | (let ((const (apply (car form) (nreverse constants)))) |
| 652 | (list (car form) | 652 | (if args |
| 653 | (apply (car form) constants) | 653 | (append (list (car form) const) |
| 654 | (if (cdr args) | 654 | (nreverse args)) |
| 655 | (cons (car form) (nreverse args)) | 655 | const)) |
| 656 | (car args))) | 656 | form))) |
| 657 | (apply (car form) constants)) | 657 | |
| 658 | form))) | 658 | (defun byte-optimize-min-max (form) |
| 659 | "Optimize `min' and `max'." | ||
| 660 | (let ((opt (byte-optimize-associative-math form))) | ||
| 661 | (if (and (consp opt) (memq (car opt) '(min max)) | ||
| 662 | (= (length opt) 4)) | ||
| 663 | ;; (OP x y z) -> (OP (OP x y) z), in order to use binary byte ops. | ||
| 664 | (list (car opt) | ||
| 665 | (list (car opt) (nth 1 opt) (nth 2 opt)) | ||
| 666 | (nth 3 opt)) | ||
| 667 | opt))) | ||
| 659 | 668 | ||
| 660 | ;; Use OP to reduce any leading prefix of constant numbers in the list | 669 | ;; Use OP to reduce any leading prefix of constant numbers in the list |
| 661 | ;; (cons ACCUM ARGS) down to a single number, and return the | 670 | ;; (cons ACCUM ARGS) down to a single number, and return the |
| @@ -878,8 +887,8 @@ | |||
| 878 | (put '* 'byte-optimizer #'byte-optimize-multiply) | 887 | (put '* 'byte-optimizer #'byte-optimize-multiply) |
| 879 | (put '- 'byte-optimizer #'byte-optimize-minus) | 888 | (put '- 'byte-optimizer #'byte-optimize-minus) |
| 880 | (put '/ 'byte-optimizer #'byte-optimize-divide) | 889 | (put '/ 'byte-optimizer #'byte-optimize-divide) |
| 881 | (put 'max 'byte-optimizer #'byte-optimize-associative-math) | 890 | (put 'max 'byte-optimizer #'byte-optimize-min-max) |
| 882 | (put 'min 'byte-optimizer #'byte-optimize-associative-math) | 891 | (put 'min 'byte-optimizer #'byte-optimize-min-max) |
| 883 | 892 | ||
| 884 | (put '= 'byte-optimizer #'byte-optimize-binary-predicate) | 893 | (put '= 'byte-optimizer #'byte-optimize-binary-predicate) |
| 885 | (put 'eq 'byte-optimizer #'byte-optimize-binary-predicate) | 894 | (put 'eq 'byte-optimizer #'byte-optimize-binary-predicate) |
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el index 539846683f0..8c16c172bed 100644 --- a/lisp/emacs-lisp/byte-run.el +++ b/lisp/emacs-lisp/byte-run.el | |||
| @@ -587,13 +587,26 @@ Otherwise, return nil. For internal use only." | |||
| 587 | (mapconcat (lambda (char) (format "`?\\%c'" char)) | 587 | (mapconcat (lambda (char) (format "`?\\%c'" char)) |
| 588 | sorted ", "))))) | 588 | sorted ", "))))) |
| 589 | 589 | ||
| 590 | (defun byte-compile-info (string &optional message type) | ||
| 591 | "Format STRING in a way that looks pleasing in the compilation output. | ||
| 592 | If MESSAGE, output the message, too. | ||
| 593 | |||
| 594 | If TYPE, it should be a string that says what the information | ||
| 595 | type is. This defaults to \"INFO\"." | ||
| 596 | (let ((string (format " %-9s%s" (or type "INFO") string))) | ||
| 597 | (when message | ||
| 598 | (message "%s" string)) | ||
| 599 | string)) | ||
| 600 | |||
| 590 | (defun byte-compile-info-string (&rest args) | 601 | (defun byte-compile-info-string (&rest args) |
| 591 | "Format ARGS in a way that looks pleasing in the compilation output." | 602 | "Format ARGS in a way that looks pleasing in the compilation output." |
| 592 | (format " %-9s%s" "INFO" (apply #'format args))) | 603 | (declare (obsolete byte-compile-info "28.1")) |
| 604 | (byte-compile-info (apply #'format args))) | ||
| 593 | 605 | ||
| 594 | (defun byte-compile-info-message (&rest args) | 606 | (defun byte-compile-info-message (&rest args) |
| 595 | "Message format ARGS in a way that looks pleasing in the compilation output." | 607 | "Message format ARGS in a way that looks pleasing in the compilation output." |
| 596 | (message "%s" (apply #'byte-compile-info-string args))) | 608 | (declare (obsolete byte-compile-info "28.1")) |
| 609 | (byte-compile-info (apply #'format args) t)) | ||
| 597 | 610 | ||
| 598 | 611 | ||
| 599 | ;; I nuked this because it's not a good idea for users to think of using it. | 612 | ;; I nuked this because it's not a good idea for users to think of using it. |
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 7a56aa2df29..c5b086f91a0 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -3659,10 +3659,10 @@ If it is nil, then the handler is \"byte-compile-SYMBOL.\"" | |||
| 3659 | (byte-defop-compiler (% byte-rem) 2) | 3659 | (byte-defop-compiler (% byte-rem) 2) |
| 3660 | (byte-defop-compiler aset 3) | 3660 | (byte-defop-compiler aset 3) |
| 3661 | 3661 | ||
| 3662 | (byte-defop-compiler max byte-compile-associative) | 3662 | (byte-defop-compiler max byte-compile-min-max) |
| 3663 | (byte-defop-compiler min byte-compile-associative) | 3663 | (byte-defop-compiler min byte-compile-min-max) |
| 3664 | (byte-defop-compiler (+ byte-plus) byte-compile-associative) | 3664 | (byte-defop-compiler (+ byte-plus) byte-compile-variadic-numeric) |
| 3665 | (byte-defop-compiler (* byte-mult) byte-compile-associative) | 3665 | (byte-defop-compiler (* byte-mult) byte-compile-variadic-numeric) |
| 3666 | 3666 | ||
| 3667 | ;;####(byte-defop-compiler move-to-column 1) | 3667 | ;;####(byte-defop-compiler move-to-column 1) |
| 3668 | (byte-defop-compiler-1 interactive byte-compile-noop) | 3668 | (byte-defop-compiler-1 interactive byte-compile-noop) |
| @@ -3809,30 +3809,36 @@ discarding." | |||
| 3809 | (if byte-compile--for-effect (setq byte-compile--for-effect nil) | 3809 | (if byte-compile--for-effect (setq byte-compile--for-effect nil) |
| 3810 | (byte-compile-out 'byte-constant (nth 1 form)))) | 3810 | (byte-compile-out 'byte-constant (nth 1 form)))) |
| 3811 | 3811 | ||
| 3812 | ;; Compile a function that accepts one or more args and is right-associative. | 3812 | ;; Compile a pure function that accepts zero or more numeric arguments |
| 3813 | ;; We do it by left-associativity so that the operations | 3813 | ;; and has an opcode for the binary case. |
| 3814 | ;; are done in the same order as in interpreted code. | 3814 | ;; Single-argument calls are assumed to be numeric identity and are |
| 3815 | ;; We treat the one-arg case, as in (+ x), like (+ x 0). | 3815 | ;; compiled as (* x 1) in order to convert markers to numbers and |
| 3816 | ;; in order to convert markers to numbers, and trigger expected errors. | 3816 | ;; trigger type errors. |
| 3817 | (defun byte-compile-associative (form) | 3817 | (defun byte-compile-variadic-numeric (form) |
| 3818 | (pcase (length form) | ||
| 3819 | (1 | ||
| 3820 | ;; No args: use the identity value for the operation. | ||
| 3821 | (byte-compile-constant (eval form))) | ||
| 3822 | (2 | ||
| 3823 | ;; One arg: compile (OP x) as (* x 1). This is identity for | ||
| 3824 | ;; all numerical values including -0.0, infinities and NaNs. | ||
| 3825 | (byte-compile-form (nth 1 form)) | ||
| 3826 | (byte-compile-constant 1) | ||
| 3827 | (byte-compile-out (get '* 'byte-opcode) 0)) | ||
| 3828 | (3 | ||
| 3829 | (byte-compile-form (nth 1 form)) | ||
| 3830 | (byte-compile-form (nth 2 form)) | ||
| 3831 | (byte-compile-out (get (car form) 'byte-opcode) 0)) | ||
| 3832 | (_ | ||
| 3833 | ;; >2 args: compile as a single function call. | ||
| 3834 | (byte-compile-normal-call form)))) | ||
| 3835 | |||
| 3836 | (defun byte-compile-min-max (form) | ||
| 3837 | "Byte-compile calls to `min' or `max'." | ||
| 3818 | (if (cdr form) | 3838 | (if (cdr form) |
| 3819 | (let ((opcode (get (car form) 'byte-opcode)) | 3839 | (byte-compile-variadic-numeric form) |
| 3820 | args) | 3840 | ;; No args: warn and emit code that raises an error when executed. |
| 3821 | (if (and (< 3 (length form)) | 3841 | (byte-compile-normal-call form))) |
| 3822 | (memq opcode (list (get '+ 'byte-opcode) | ||
| 3823 | (get '* 'byte-opcode)))) | ||
| 3824 | ;; Don't use binary operations for > 2 operands, as that | ||
| 3825 | ;; may cause overflow/truncation in float operations. | ||
| 3826 | (byte-compile-normal-call form) | ||
| 3827 | (setq args (copy-sequence (cdr form))) | ||
| 3828 | (byte-compile-form (car args)) | ||
| 3829 | (setq args (cdr args)) | ||
| 3830 | (or args (setq args '(0) | ||
| 3831 | opcode (get '+ 'byte-opcode))) | ||
| 3832 | (dolist (arg args) | ||
| 3833 | (byte-compile-form arg) | ||
| 3834 | (byte-compile-out opcode 0)))) | ||
| 3835 | (byte-compile-constant (eval form)))) | ||
| 3836 | 3842 | ||
| 3837 | 3843 | ||
| 3838 | ;; more complicated compiler macros | 3844 | ;; more complicated compiler macros |
| @@ -3847,7 +3853,7 @@ discarding." | |||
| 3847 | (byte-defop-compiler indent-to) | 3853 | (byte-defop-compiler indent-to) |
| 3848 | (byte-defop-compiler insert) | 3854 | (byte-defop-compiler insert) |
| 3849 | (byte-defop-compiler-1 function byte-compile-function-form) | 3855 | (byte-defop-compiler-1 function byte-compile-function-form) |
| 3850 | (byte-defop-compiler-1 - byte-compile-minus) | 3856 | (byte-defop-compiler (- byte-diff) byte-compile-minus) |
| 3851 | (byte-defop-compiler (/ byte-quo) byte-compile-quo) | 3857 | (byte-defop-compiler (/ byte-quo) byte-compile-quo) |
| 3852 | (byte-defop-compiler nconc) | 3858 | (byte-defop-compiler nconc) |
| 3853 | 3859 | ||
| @@ -3914,30 +3920,17 @@ discarding." | |||
| 3914 | ((byte-compile-normal-call form))))) | 3920 | ((byte-compile-normal-call form))))) |
| 3915 | 3921 | ||
| 3916 | (defun byte-compile-minus (form) | 3922 | (defun byte-compile-minus (form) |
| 3917 | (let ((len (length form))) | 3923 | (if (/= (length form) 2) |
| 3918 | (cond | 3924 | (byte-compile-variadic-numeric form) |
| 3919 | ((= 1 len) (byte-compile-constant 0)) | 3925 | (byte-compile-form (cadr form)) |
| 3920 | ((= 2 len) | 3926 | (byte-compile-out 'byte-negate 0))) |
| 3921 | (byte-compile-form (cadr form)) | ||
| 3922 | (byte-compile-out 'byte-negate 0)) | ||
| 3923 | ((= 3 len) | ||
| 3924 | (byte-compile-form (nth 1 form)) | ||
| 3925 | (byte-compile-form (nth 2 form)) | ||
| 3926 | (byte-compile-out 'byte-diff 0)) | ||
| 3927 | ;; Don't use binary operations for > 2 operands, as that may | ||
| 3928 | ;; cause overflow/truncation in float operations. | ||
| 3929 | (t (byte-compile-normal-call form))))) | ||
| 3930 | 3927 | ||
| 3931 | (defun byte-compile-quo (form) | 3928 | (defun byte-compile-quo (form) |
| 3932 | (let ((len (length form))) | 3929 | (if (= (length form) 3) |
| 3933 | (cond ((< len 2) | 3930 | (byte-compile-two-args form) |
| 3934 | (byte-compile-subr-wrong-args form "1 or more")) | 3931 | ;; N-ary `/' is not the left-reduction of binary `/' because if any |
| 3935 | ((= len 3) | 3932 | ;; argument is a float, then everything is done in floating-point. |
| 3936 | (byte-compile-two-args form)) | 3933 | (byte-compile-normal-call form))) |
| 3937 | (t | ||
| 3938 | ;; Don't use binary operations for > 2 operands, as that | ||
| 3939 | ;; may cause overflow/truncation in float operations. | ||
| 3940 | (byte-compile-normal-call form))))) | ||
| 3941 | 3934 | ||
| 3942 | (defun byte-compile-nconc (form) | 3935 | (defun byte-compile-nconc (form) |
| 3943 | (let ((len (length form))) | 3936 | (let ((len (length form))) |
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index 4e8423eb5b1..02da07daaf4 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el | |||
| @@ -211,7 +211,16 @@ DEFAULT-BODY, if present, is used as the body of a default method. | |||
| 211 | [&rest [&or | 211 | [&rest [&or |
| 212 | ("declare" &rest sexp) | 212 | ("declare" &rest sexp) |
| 213 | (":argument-precedence-order" &rest sexp) | 213 | (":argument-precedence-order" &rest sexp) |
| 214 | (&define ":method" [&rest atom] | 214 | (&define ":method" |
| 215 | ;; FIXME: The `:unique' | ||
| 216 | ;; construct works around | ||
| 217 | ;; Bug#42672. We'd rather want | ||
| 218 | ;; names like those generated by | ||
| 219 | ;; `cl-defmethod', but that | ||
| 220 | ;; requires larger changes to | ||
| 221 | ;; Edebug. | ||
| 222 | :unique "cl-generic-:method@" | ||
| 223 | [&rest cl-generic-method-qualifier] | ||
| 215 | cl-generic-method-args lambda-doc | 224 | cl-generic-method-args lambda-doc |
| 216 | def-body)]] | 225 | def-body)]] |
| 217 | def-body))) | 226 | def-body))) |
| @@ -432,9 +441,8 @@ The set of acceptable TYPEs (also called \"specializers\") is defined | |||
| 432 | (&define ; this means we are defining something | 441 | (&define ; this means we are defining something |
| 433 | [&or name ("setf" name :name setf)] | 442 | [&or name ("setf" name :name setf)] |
| 434 | ;; ^^ This is the methods symbol | 443 | ;; ^^ This is the methods symbol |
| 435 | [ &rest atom ] ; Multiple qualifiers are allowed. | 444 | [ &rest cl-generic-method-qualifier ] |
| 436 | ; Like in CLOS spec, we support | 445 | ;; Multiple qualifiers are allowed. |
| 437 | ; any non-list values. | ||
| 438 | cl-generic-method-args ; arguments | 446 | cl-generic-method-args ; arguments |
| 439 | lambda-doc ; documentation string | 447 | lambda-doc ; documentation string |
| 440 | def-body))) ; part to be debugged | 448 | def-body))) ; part to be debugged |
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 6c1426ce5cb..c38019d4a73 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el | |||
| @@ -2016,7 +2016,12 @@ info node `(cl) Function Bindings' for details. | |||
| 2016 | 2016 | ||
| 2017 | \(fn ((FUNC ARGLIST BODY...) ...) FORM...)" | 2017 | \(fn ((FUNC ARGLIST BODY...) ...) FORM...)" |
| 2018 | (declare (indent 1) | 2018 | (declare (indent 1) |
| 2019 | (debug ((&rest [&or (&define name function-form) (cl-defun)]) | 2019 | (debug ((&rest [&or (&define name :unique "cl-flet@" function-form) |
| 2020 | (&define name :unique "cl-flet@" | ||
| 2021 | cl-lambda-list | ||
| 2022 | cl-declarations-or-string | ||
| 2023 | [&optional ("interactive" interactive)] | ||
| 2024 | def-body)]) | ||
| 2020 | cl-declarations body))) | 2025 | cl-declarations body))) |
| 2021 | (let ((binds ()) (newenv macroexpand-all-environment)) | 2026 | (let ((binds ()) (newenv macroexpand-all-environment)) |
| 2022 | (dolist (binding bindings) | 2027 | (dolist (binding bindings) |
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index a565e8f6dcb..d9bbf6129c6 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el | |||
| @@ -1240,6 +1240,13 @@ purpose by adding an entry to this alist, and setting | |||
| 1240 | ;; since it wraps the list of forms with a call to `edebug-enter'. | 1240 | ;; since it wraps the list of forms with a call to `edebug-enter'. |
| 1241 | ;; Uses the dynamically bound vars edebug-def-name and edebug-def-args. | 1241 | ;; Uses the dynamically bound vars edebug-def-name and edebug-def-args. |
| 1242 | ;; Do this after parsing since that may find a name. | 1242 | ;; Do this after parsing since that may find a name. |
| 1243 | (when (string-match-p (rx bos "edebug-anon" (+ digit) eos) | ||
| 1244 | (symbol-name edebug-old-def-name)) | ||
| 1245 | ;; FIXME: Due to Bug#42701, we reset an anonymous name so that | ||
| 1246 | ;; backtracking doesn't generate duplicate definitions. It would | ||
| 1247 | ;; be better to not define wrappers in the case of a non-matching | ||
| 1248 | ;; specification branch to begin with. | ||
| 1249 | (setq edebug-old-def-name nil)) | ||
| 1243 | (setq edebug-def-name | 1250 | (setq edebug-def-name |
| 1244 | (or edebug-def-name edebug-old-def-name (gensym "edebug-anon"))) | 1251 | (or edebug-def-name edebug-old-def-name (gensym "edebug-anon"))) |
| 1245 | `(edebug-enter | 1252 | `(edebug-enter |
| @@ -1725,12 +1732,15 @@ contains a circular object." | |||
| 1725 | (&define . edebug-match-&define) | 1732 | (&define . edebug-match-&define) |
| 1726 | (name . edebug-match-name) | 1733 | (name . edebug-match-name) |
| 1727 | (:name . edebug-match-colon-name) | 1734 | (:name . edebug-match-colon-name) |
| 1735 | (:unique . edebug-match-:unique) | ||
| 1728 | (arg . edebug-match-arg) | 1736 | (arg . edebug-match-arg) |
| 1729 | (def-body . edebug-match-def-body) | 1737 | (def-body . edebug-match-def-body) |
| 1730 | (def-form . edebug-match-def-form) | 1738 | (def-form . edebug-match-def-form) |
| 1731 | ;; Less frequently used: | 1739 | ;; Less frequently used: |
| 1732 | ;; (function . edebug-match-function) | 1740 | ;; (function . edebug-match-function) |
| 1733 | (lambda-expr . edebug-match-lambda-expr) | 1741 | (lambda-expr . edebug-match-lambda-expr) |
| 1742 | (cl-generic-method-qualifier | ||
| 1743 | . edebug-match-cl-generic-method-qualifier) | ||
| 1734 | (cl-generic-method-args . edebug-match-cl-generic-method-args) | 1744 | (cl-generic-method-args . edebug-match-cl-generic-method-args) |
| 1735 | (cl-macrolet-expr . edebug-match-cl-macrolet-expr) | 1745 | (cl-macrolet-expr . edebug-match-cl-macrolet-expr) |
| 1736 | (cl-macrolet-name . edebug-match-cl-macrolet-name) | 1746 | (cl-macrolet-name . edebug-match-cl-macrolet-name) |
| @@ -2035,6 +2045,27 @@ contains a circular object." | |||
| 2035 | spec)) | 2045 | spec)) |
| 2036 | nil) | 2046 | nil) |
| 2037 | 2047 | ||
| 2048 | (defun edebug-match-:unique (_cursor spec) | ||
| 2049 | "Match a `:unique PREFIX' specifier. | ||
| 2050 | SPEC is the symbol name prefix for `gensym'." | ||
| 2051 | (let ((suffix (gensym spec))) | ||
| 2052 | (setq edebug-def-name | ||
| 2053 | (if edebug-def-name | ||
| 2054 | ;; Construct a new name by appending to previous name. | ||
| 2055 | (intern (format "%s@%s" edebug-def-name suffix)) | ||
| 2056 | suffix))) | ||
| 2057 | nil) | ||
| 2058 | |||
| 2059 | (defun edebug-match-cl-generic-method-qualifier (cursor) | ||
| 2060 | "Match a QUALIFIER for `cl-defmethod' at CURSOR." | ||
| 2061 | (let ((args (edebug-top-element-required cursor "Expected qualifier"))) | ||
| 2062 | ;; Like in CLOS spec, we support any non-list values. | ||
| 2063 | (unless (atom args) (edebug-no-match cursor "Atom expected")) | ||
| 2064 | ;; Append the arguments to `edebug-def-name' (Bug#42671). | ||
| 2065 | (setq edebug-def-name (intern (format "%s %s" edebug-def-name args))) | ||
| 2066 | (edebug-move-cursor cursor) | ||
| 2067 | (list args))) | ||
| 2068 | |||
| 2038 | (defun edebug-match-cl-generic-method-args (cursor) | 2069 | (defun edebug-match-cl-generic-method-args (cursor) |
| 2039 | (let ((args (edebug-top-element-required cursor "Expected arguments"))) | 2070 | (let ((args (edebug-top-element-required cursor "Expected arguments"))) |
| 2040 | (if (not (consp args)) | 2071 | (if (not (consp args)) |
diff --git a/lisp/emacs-lisp/hierarchy.el b/lisp/emacs-lisp/hierarchy.el new file mode 100644 index 00000000000..8cef029c4cf --- /dev/null +++ b/lisp/emacs-lisp/hierarchy.el | |||
| @@ -0,0 +1,579 @@ | |||
| 1 | ;;; hierarchy.el --- Library to create and display hierarchy structures -*- lexical-binding: t; -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2020 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Damien Cassou <damien@cassou.me> | ||
| 6 | ;; Maintainer: emacs-devel@gnu.org | ||
| 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 | ;; Library to create, query, navigate and display hierarchy structures. | ||
| 26 | |||
| 27 | ;; Creation: After having created a hierarchy with `hierarchy-new', | ||
| 28 | ;; populate it by calling `hierarchy-add-tree' or | ||
| 29 | ;; `hierarchy-add-trees'. You can then optionally sort its element | ||
| 30 | ;; with `hierarchy-sort'. | ||
| 31 | |||
| 32 | ;; Querying: You can learn more about your hierarchy by using | ||
| 33 | ;; functions such as `hierarchy-roots', `hierarchy-has-item', | ||
| 34 | ;; `hierarchy-length', `hierarchy-parent', `hierarchy-descendant-p'. | ||
| 35 | |||
| 36 | ;; Navigation: When your hierarchy is ready, you can use | ||
| 37 | ;; `hierarchy-map-item', `hierarchy-map', and `map-tree' to apply | ||
| 38 | ;; functions to elements of the hierarchy. | ||
| 39 | |||
| 40 | ;; Display: You can display a hierarchy as a tabulated list using | ||
| 41 | ;; `hierarchy-tabulated-display' and as an expandable/foldable tree | ||
| 42 | ;; using `hierarchy-convert-to-tree-widget'. The | ||
| 43 | ;; `hierarchy-labelfn-*' functions will help you display each item of | ||
| 44 | ;; the hierarchy the way you want it. | ||
| 45 | |||
| 46 | ;;; Limitation: | ||
| 47 | |||
| 48 | ;; - Current implementation uses #'equal to find and distinguish | ||
| 49 | ;; elements. Support for user-provided equality definition is | ||
| 50 | ;; desired but not yet implemented; | ||
| 51 | ;; | ||
| 52 | ;; - nil can't be added to a hierarchy; | ||
| 53 | ;; | ||
| 54 | ;; - the hierarchy is computed eagerly. | ||
| 55 | |||
| 56 | ;;; Code: | ||
| 57 | |||
| 58 | (require 'seq) | ||
| 59 | (require 'map) | ||
| 60 | (require 'subr-x) | ||
| 61 | (require 'cl-lib) | ||
| 62 | |||
| 63 | |||
| 64 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 65 | ;; Helpers | ||
| 66 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 67 | |||
| 68 | (cl-defstruct (hierarchy | ||
| 69 | (:constructor hierarchy--make) | ||
| 70 | (:conc-name hierarchy--)) | ||
| 71 | (roots (list)) ; list of the hierarchy roots (no parent) | ||
| 72 | (parents (make-hash-table :test 'equal)) ; map an item to its parent | ||
| 73 | (children (make-hash-table :test 'equal)) ; map an item to its childre | ||
| 74 | ;; cache containing the set of all items in the hierarchy | ||
| 75 | (seen-items (make-hash-table :test 'equal))) ; map an item to t | ||
| 76 | |||
| 77 | (defun hierarchy--seen-items-add (hierarchy item) | ||
| 78 | "In HIERARCHY, add ITEM to seen items." | ||
| 79 | (map-put! (hierarchy--seen-items hierarchy) item t)) | ||
| 80 | |||
| 81 | (defun hierarchy--compute-roots (hierarchy) | ||
| 82 | "Search roots of HIERARCHY and return them." | ||
| 83 | (cl-set-difference | ||
| 84 | (map-keys (hierarchy--seen-items hierarchy)) | ||
| 85 | (map-keys (hierarchy--parents hierarchy)) | ||
| 86 | :test #'equal)) | ||
| 87 | |||
| 88 | (defun hierarchy--sort-roots (hierarchy sortfn) | ||
| 89 | "Compute, sort and store the roots of HIERARCHY. | ||
| 90 | |||
| 91 | SORTFN is a function taking two items of the hierarchy as parameter and | ||
| 92 | returning non-nil if the first parameter is lower than the second." | ||
| 93 | (setf (hierarchy--roots hierarchy) | ||
| 94 | (sort (hierarchy--compute-roots hierarchy) | ||
| 95 | sortfn))) | ||
| 96 | |||
| 97 | (defun hierarchy--add-relation (hierarchy item parent acceptfn) | ||
| 98 | "In HIERARCHY, add ITEM as child of PARENT. | ||
| 99 | |||
| 100 | ACCEPTFN is a function returning non-nil if its parameter (any object) | ||
| 101 | should be an item of the hierarchy." | ||
| 102 | (let* ((existing-parent (hierarchy-parent hierarchy item)) | ||
| 103 | (has-parent-p (funcall acceptfn existing-parent))) | ||
| 104 | (cond | ||
| 105 | ((and has-parent-p (not (equal existing-parent parent))) | ||
| 106 | (error "An item (%s) can only have one parent: '%s' vs '%s'" | ||
| 107 | item existing-parent parent)) | ||
| 108 | ((not has-parent-p) | ||
| 109 | (let ((existing-children (map-elt (hierarchy--children hierarchy) | ||
| 110 | parent (list)))) | ||
| 111 | (map-put! (hierarchy--children hierarchy) | ||
| 112 | parent (append existing-children (list item)))) | ||
| 113 | (map-put! (hierarchy--parents hierarchy) item parent))))) | ||
| 114 | |||
| 115 | (defun hierarchy--set-equal (list1 list2 &rest cl-keys) | ||
| 116 | "Return non-nil if LIST1 and LIST2 have same elements. | ||
| 117 | |||
| 118 | I.e., if every element of LIST1 also appears in LIST2 and if | ||
| 119 | every element of LIST2 also appears in LIST1. | ||
| 120 | |||
| 121 | CL-KEYS are key-value pairs just like in `cl-subsetp'. Supported | ||
| 122 | keys are :key and :test." | ||
| 123 | (and (apply 'cl-subsetp list1 list2 cl-keys) | ||
| 124 | (apply 'cl-subsetp list2 list1 cl-keys))) | ||
| 125 | |||
| 126 | |||
| 127 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 128 | ;; Creation | ||
| 129 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 130 | |||
| 131 | (defun hierarchy-new () | ||
| 132 | "Create a hierarchy and return it." | ||
| 133 | (hierarchy--make)) | ||
| 134 | |||
| 135 | (defun hierarchy-add-tree (hierarchy item parentfn &optional childrenfn acceptfn) | ||
| 136 | "In HIERARCHY, add ITEM. | ||
| 137 | |||
| 138 | PARENTFN is either nil or a function defining the child-to-parent | ||
| 139 | relationship: this function takes an item as parameter and should return | ||
| 140 | the parent of this item in the hierarchy. If the item has no parent in the | ||
| 141 | hierarchy (i.e., it should be a root), the function should return an object | ||
| 142 | not accepted by acceptfn (i.e., nil for the default value of acceptfn). | ||
| 143 | |||
| 144 | CHILDRENFN is either nil or a function defining the parent-to-children | ||
| 145 | relationship: this function takes an item as parameter and should return a | ||
| 146 | list of children of this item in the hierarchy. | ||
| 147 | |||
| 148 | If both PARENTFN and CHILDRENFN are non-nil, the results of PARENTFN and | ||
| 149 | CHILDRENFN are expected to be coherent with each other. | ||
| 150 | |||
| 151 | ACCEPTFN is a function returning non-nil if its parameter (any object) | ||
| 152 | should be an item of the hierarchy. By default, ACCEPTFN returns non-nil | ||
| 153 | if its parameter is non-nil." | ||
| 154 | (unless (hierarchy-has-item hierarchy item) | ||
| 155 | (let ((acceptfn (or acceptfn #'identity))) | ||
| 156 | (hierarchy--seen-items-add hierarchy item) | ||
| 157 | (let ((parent (and parentfn (funcall parentfn item)))) | ||
| 158 | (when (funcall acceptfn parent) | ||
| 159 | (hierarchy--add-relation hierarchy item parent acceptfn) | ||
| 160 | (hierarchy-add-tree hierarchy parent parentfn childrenfn))) | ||
| 161 | (let ((children (and childrenfn (funcall childrenfn item)))) | ||
| 162 | (mapc (lambda (child) | ||
| 163 | (when (funcall acceptfn child) | ||
| 164 | (hierarchy--add-relation hierarchy child item acceptfn) | ||
| 165 | (hierarchy-add-tree hierarchy child parentfn childrenfn))) | ||
| 166 | children))))) | ||
| 167 | |||
| 168 | (defun hierarchy-add-trees (hierarchy items parentfn &optional childrenfn acceptfn) | ||
| 169 | "Call `hierarchy-add-tree' on HIERARCHY and each element of ITEMS. | ||
| 170 | |||
| 171 | PARENTFN, CHILDRENFN and ACCEPTFN have the same meaning as in `hierarchy-add'." | ||
| 172 | (seq-map (lambda (item) | ||
| 173 | (hierarchy-add-tree hierarchy item parentfn childrenfn acceptfn)) | ||
| 174 | items)) | ||
| 175 | |||
| 176 | (defun hierarchy-add-list (hierarchy list &optional wrap childrenfn) | ||
| 177 | "Add to HIERARCHY the sub-lists in LIST. | ||
| 178 | |||
| 179 | If WRAP is non-nil, allow duplicate items in LIST by wraping each | ||
| 180 | item in a cons (id . item). The root's id is 1. | ||
| 181 | |||
| 182 | CHILDRENFN is a function (defaults to `cdr') taking LIST as a | ||
| 183 | parameter which should return LIST's children (a list). Each | ||
| 184 | child is (recursively) passed as a parameter to CHILDRENFN to get | ||
| 185 | its own children. Because of this parameter, LIST can be | ||
| 186 | anything, not necessarily a list." | ||
| 187 | (let* ((childrenfn (or childrenfn #'cdr)) | ||
| 188 | (id 0) | ||
| 189 | (wrapfn (lambda (item) | ||
| 190 | (if wrap | ||
| 191 | (cons (setq id (1+ id)) item) | ||
| 192 | item))) | ||
| 193 | (unwrapfn (if wrap #'cdr #'identity))) | ||
| 194 | (hierarchy-add-tree | ||
| 195 | hierarchy (funcall wrapfn list) nil | ||
| 196 | (lambda (item) | ||
| 197 | (mapcar wrapfn (funcall childrenfn | ||
| 198 | (funcall unwrapfn item))))) | ||
| 199 | hierarchy)) | ||
| 200 | |||
| 201 | (defun hierarchy-from-list (list &optional wrap childrenfn) | ||
| 202 | "Create and return a hierarchy built from LIST. | ||
| 203 | |||
| 204 | This function passes LIST, WRAP and CHILDRENFN unchanged to | ||
| 205 | `hierarchy-add-list'." | ||
| 206 | (hierarchy-add-list (hierarchy-new) list wrap childrenfn)) | ||
| 207 | |||
| 208 | (defun hierarchy-sort (hierarchy &optional sortfn) | ||
| 209 | "Modify HIERARCHY so that its roots and item's children are sorted. | ||
| 210 | |||
| 211 | SORTFN is a function taking two items of the hierarchy as parameter and | ||
| 212 | returning non-nil if the first parameter is lower than the second. By | ||
| 213 | default, SORTFN is `string-lessp'." | ||
| 214 | (let ((sortfn (or sortfn #'string-lessp))) | ||
| 215 | (hierarchy--sort-roots hierarchy sortfn) | ||
| 216 | (mapc (lambda (parent) | ||
| 217 | (setf | ||
| 218 | (map-elt (hierarchy--children hierarchy) parent) | ||
| 219 | (sort (map-elt (hierarchy--children hierarchy) parent) sortfn))) | ||
| 220 | (map-keys (hierarchy--children hierarchy))))) | ||
| 221 | |||
| 222 | (defun hierarchy-extract-tree (hierarchy item) | ||
| 223 | "Return a copy of HIERARCHY with ITEM's descendants and parents." | ||
| 224 | (if (not (hierarchy-has-item hierarchy item)) | ||
| 225 | nil | ||
| 226 | (let ((tree (hierarchy-new))) | ||
| 227 | (hierarchy-add-tree tree item | ||
| 228 | (lambda (each) (hierarchy-parent hierarchy each)) | ||
| 229 | (lambda (each) | ||
| 230 | (when (or (equal each item) | ||
| 231 | (hierarchy-descendant-p hierarchy each item)) | ||
| 232 | (hierarchy-children hierarchy each)))) | ||
| 233 | tree))) | ||
| 234 | |||
| 235 | (defun hierarchy-copy (hierarchy) | ||
| 236 | "Return a copy of HIERARCHY. | ||
| 237 | |||
| 238 | Items in HIERARCHY are shared, but structure is not." | ||
| 239 | (hierarchy-map-hierarchy (lambda (item _) (identity item)) hierarchy)) | ||
| 240 | |||
| 241 | |||
| 242 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 243 | ;; Querying | ||
| 244 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 245 | |||
| 246 | (defun hierarchy-items (hierarchy) | ||
| 247 | "Return a list of all items of HIERARCHY." | ||
| 248 | (map-keys (hierarchy--seen-items hierarchy))) | ||
| 249 | |||
| 250 | (defun hierarchy-has-item (hierarchy item) | ||
| 251 | "Return t if HIERARCHY includes ITEM." | ||
| 252 | (map-contains-key (hierarchy--seen-items hierarchy) item)) | ||
| 253 | |||
| 254 | (defun hierarchy-empty-p (hierarchy) | ||
| 255 | "Return t if HIERARCHY is empty." | ||
| 256 | (= 0 (hierarchy-length hierarchy))) | ||
| 257 | |||
| 258 | (defun hierarchy-length (hierarchy) | ||
| 259 | "Return the number of items in HIERARCHY." | ||
| 260 | (hash-table-count (hierarchy--seen-items hierarchy))) | ||
| 261 | |||
| 262 | (defun hierarchy-has-root (hierarchy item) | ||
| 263 | "Return t if one of HIERARCHY's roots is ITEM. | ||
| 264 | |||
| 265 | A root is an item with no parent." | ||
| 266 | (seq-contains-p (hierarchy-roots hierarchy) item)) | ||
| 267 | |||
| 268 | (defun hierarchy-roots (hierarchy) | ||
| 269 | "Return all roots of HIERARCHY. | ||
| 270 | |||
| 271 | A root is an item with no parent." | ||
| 272 | (let ((roots (hierarchy--roots hierarchy))) | ||
| 273 | (or roots | ||
| 274 | (hierarchy--compute-roots hierarchy)))) | ||
| 275 | |||
| 276 | (defun hierarchy-leafs (hierarchy &optional node) | ||
| 277 | "Return all leafs of HIERARCHY. | ||
| 278 | |||
| 279 | A leaf is an item with no child. | ||
| 280 | |||
| 281 | If NODE is an item of HIERARCHY, only return leafs under NODE." | ||
| 282 | (let ((leafs (cl-set-difference | ||
| 283 | (map-keys (hierarchy--seen-items hierarchy)) | ||
| 284 | (map-keys (hierarchy--children hierarchy))))) | ||
| 285 | (if (hierarchy-has-item hierarchy node) | ||
| 286 | (seq-filter (lambda (item) | ||
| 287 | (hierarchy-descendant-p hierarchy item node)) | ||
| 288 | leafs) | ||
| 289 | leafs))) | ||
| 290 | |||
| 291 | (defun hierarchy-parent (hierarchy item) | ||
| 292 | "In HIERARCHY, return parent of ITEM." | ||
| 293 | (map-elt (hierarchy--parents hierarchy) item)) | ||
| 294 | |||
| 295 | (defun hierarchy-children (hierarchy parent) | ||
| 296 | "In HIERARCHY, return children of PARENT." | ||
| 297 | (map-elt (hierarchy--children hierarchy) parent (list))) | ||
| 298 | |||
| 299 | (defun hierarchy-child-p (hierarchy item1 item2) | ||
| 300 | "In HIERARCHY, return non-nil if and only if ITEM1 is a child of ITEM2." | ||
| 301 | (equal (hierarchy-parent hierarchy item1) item2)) | ||
| 302 | |||
| 303 | (defun hierarchy-descendant-p (hierarchy item1 item2) | ||
| 304 | "In HIERARCHY, return non-nil if and only if ITEM1 is a descendant of ITEM2. | ||
| 305 | |||
| 306 | ITEM1 is a descendant of ITEM2 if and only if both are items of HIERARCHY | ||
| 307 | and either: | ||
| 308 | |||
| 309 | - ITEM1 is child of ITEM2, or | ||
| 310 | - ITEM1's parent is a descendant of ITEM2." | ||
| 311 | (and | ||
| 312 | (hierarchy-has-item hierarchy item1) | ||
| 313 | (hierarchy-has-item hierarchy item2) | ||
| 314 | (or | ||
| 315 | (hierarchy-child-p hierarchy item1 item2) | ||
| 316 | (hierarchy-descendant-p | ||
| 317 | hierarchy (hierarchy-parent hierarchy item1) item2)))) | ||
| 318 | |||
| 319 | (defun hierarchy-equal (hierarchy1 hierarchy2) | ||
| 320 | "Return t if HIERARCHY1 and HIERARCHY2 are equal. | ||
| 321 | |||
| 322 | Two equal hierarchies share the same items and the same | ||
| 323 | relationships among them." | ||
| 324 | (and (hierarchy-p hierarchy1) | ||
| 325 | (hierarchy-p hierarchy2) | ||
| 326 | (= (hierarchy-length hierarchy1) (hierarchy-length hierarchy2)) | ||
| 327 | ;; parents are the same | ||
| 328 | (seq-every-p (lambda (child) | ||
| 329 | (equal (hierarchy-parent hierarchy1 child) | ||
| 330 | (hierarchy-parent hierarchy2 child))) | ||
| 331 | (map-keys (hierarchy--parents hierarchy1))) | ||
| 332 | ;; children are the same | ||
| 333 | (seq-every-p (lambda (parent) | ||
| 334 | (hierarchy--set-equal | ||
| 335 | (hierarchy-children hierarchy1 parent) | ||
| 336 | (hierarchy-children hierarchy2 parent) | ||
| 337 | :test #'equal)) | ||
| 338 | (map-keys (hierarchy--children hierarchy1))))) | ||
| 339 | |||
| 340 | |||
| 341 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 342 | ;; Navigation | ||
| 343 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 344 | |||
| 345 | (defun hierarchy-map-item (func item hierarchy &optional indent) | ||
| 346 | "Return the result of applying FUNC to ITEM and its descendants in HIERARCHY. | ||
| 347 | |||
| 348 | This function navigates the tree top-down: FUNCTION is first called on item | ||
| 349 | and then on each of its children. Results are concatenated in a list. | ||
| 350 | |||
| 351 | INDENT is a number (default 0) representing the indentation of ITEM in | ||
| 352 | HIERARCHY. FUNC should take 2 argument: the item and its indentation | ||
| 353 | level." | ||
| 354 | (let ((indent (or indent 0))) | ||
| 355 | (cons | ||
| 356 | (funcall func item indent) | ||
| 357 | (seq-mapcat (lambda (child) (hierarchy-map-item func child | ||
| 358 | hierarchy (1+ indent))) | ||
| 359 | (hierarchy-children hierarchy item))))) | ||
| 360 | |||
| 361 | (defun hierarchy-map (func hierarchy &optional indent) | ||
| 362 | "Return the result of applying FUNC to each element of HIERARCHY. | ||
| 363 | |||
| 364 | This function navigates the tree top-down: FUNCTION is first called on each | ||
| 365 | root. To do so, it calls `hierarchy-map-item' on each root | ||
| 366 | sequentially. Results are concatenated in a list. | ||
| 367 | |||
| 368 | FUNC should take 2 arguments: the item and its indentation level. | ||
| 369 | |||
| 370 | INDENT is a number (default 0) representing the indentation of HIERARCHY's | ||
| 371 | roots." | ||
| 372 | (let ((indent (or indent 0))) | ||
| 373 | (seq-mapcat (lambda (root) (hierarchy-map-item func root hierarchy indent)) | ||
| 374 | (hierarchy-roots hierarchy)))) | ||
| 375 | |||
| 376 | (defun hierarchy-map-tree (function hierarchy &optional item indent) | ||
| 377 | "Apply FUNCTION on each item of HIERARCHY under ITEM. | ||
| 378 | |||
| 379 | This function navigates the tree bottom-up: FUNCTION is first called on | ||
| 380 | leafs and the result is passed as parameter when calling FUNCTION on | ||
| 381 | parents. | ||
| 382 | |||
| 383 | FUNCTION should take 3 parameters: the current item, its indentation | ||
| 384 | level (a number), and a list representing the result of applying | ||
| 385 | `hierarchy-map-tree' to each child of the item. | ||
| 386 | |||
| 387 | INDENT is 0 by default and is passed as second parameter to FUNCTION. | ||
| 388 | INDENT is incremented by 1 at each level of the tree. | ||
| 389 | |||
| 390 | This function returns the result of applying FUNCTION to ITEM (the first | ||
| 391 | root if nil)." | ||
| 392 | (let ((item (or item (car (hierarchy-roots hierarchy)))) | ||
| 393 | (indent (or indent 0))) | ||
| 394 | (funcall function item indent | ||
| 395 | (mapcar (lambda (child) | ||
| 396 | (hierarchy-map-tree function hierarchy | ||
| 397 | child (1+ indent))) | ||
| 398 | (hierarchy-children hierarchy item))))) | ||
| 399 | |||
| 400 | (defun hierarchy-map-hierarchy (function hierarchy) | ||
| 401 | "Apply FUNCTION to each item of HIERARCHY in a new hierarchy. | ||
| 402 | |||
| 403 | FUNCTION should take 2 parameters, the current item and its | ||
| 404 | indentation level (a number), and should return an item to be | ||
| 405 | added to the new hierarchy." | ||
| 406 | (let* ((items (make-hash-table :test #'equal)) | ||
| 407 | (transform (lambda (item) (map-elt items item)))) | ||
| 408 | ;; Make 'items', a table mapping original items to their | ||
| 409 | ;; transformation | ||
| 410 | (hierarchy-map (lambda (item indent) | ||
| 411 | (map-put! items item (funcall function item indent))) | ||
| 412 | hierarchy) | ||
| 413 | (hierarchy--make | ||
| 414 | :roots (mapcar transform (hierarchy-roots hierarchy)) | ||
| 415 | :parents (let ((result (make-hash-table :test #'equal))) | ||
| 416 | (map-apply (lambda (child parent) | ||
| 417 | (map-put! result | ||
| 418 | (funcall transform child) | ||
| 419 | (funcall transform parent))) | ||
| 420 | (hierarchy--parents hierarchy)) | ||
| 421 | result) | ||
| 422 | :children (let ((result (make-hash-table :test #'equal))) | ||
| 423 | (map-apply (lambda (parent children) | ||
| 424 | (map-put! result | ||
| 425 | (funcall transform parent) | ||
| 426 | (seq-map transform children))) | ||
| 427 | (hierarchy--children hierarchy)) | ||
| 428 | result) | ||
| 429 | :seen-items (let ((result (make-hash-table :test #'equal))) | ||
| 430 | (map-apply (lambda (item v) | ||
| 431 | (map-put! result | ||
| 432 | (funcall transform item) | ||
| 433 | v)) | ||
| 434 | (hierarchy--seen-items hierarchy)) | ||
| 435 | result)))) | ||
| 436 | |||
| 437 | |||
| 438 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 439 | ;; Display | ||
| 440 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 441 | |||
| 442 | (defun hierarchy-labelfn-indent (labelfn &optional indent-string) | ||
| 443 | "Return a function rendering LABELFN indented with INDENT-STRING. | ||
| 444 | |||
| 445 | INDENT-STRING defaults to a 2-space string. Indentation is | ||
| 446 | multiplied by the depth of the displayed item." | ||
| 447 | (let ((indent-string (or indent-string " "))) | ||
| 448 | (lambda (item indent) | ||
| 449 | (dotimes (_ indent) (insert indent-string)) | ||
| 450 | (funcall labelfn item indent)))) | ||
| 451 | |||
| 452 | (defun hierarchy-labelfn-button (labelfn actionfn) | ||
| 453 | "Return a function rendering LABELFN in a button. | ||
| 454 | |||
| 455 | Clicking the button triggers ACTIONFN. ACTIONFN is a function | ||
| 456 | taking an item of HIERARCHY and an indentation value (a number) | ||
| 457 | as input. This function is called when an item is clicked. The | ||
| 458 | return value of ACTIONFN is ignored." | ||
| 459 | (lambda (item indent) | ||
| 460 | (let ((start (point))) | ||
| 461 | (funcall labelfn item indent) | ||
| 462 | (make-text-button start (point) | ||
| 463 | 'action (lambda (_) (funcall actionfn item indent)))))) | ||
| 464 | |||
| 465 | (defun hierarchy-labelfn-button-if (labelfn buttonp actionfn) | ||
| 466 | "Return a function rendering LABELFN as a button if BUTTONP. | ||
| 467 | |||
| 468 | Pass LABELFN and ACTIONFN to `hierarchy-labelfn-button' if | ||
| 469 | BUTTONP is non-nil. Otherwise, render LABELFN without making it | ||
| 470 | a button. | ||
| 471 | |||
| 472 | BUTTONP is a function taking an item of HIERARCHY and an | ||
| 473 | indentation value (a number) as input." | ||
| 474 | (lambda (item indent) | ||
| 475 | (if (funcall buttonp item indent) | ||
| 476 | (funcall (hierarchy-labelfn-button labelfn actionfn) item indent) | ||
| 477 | (funcall labelfn item indent)))) | ||
| 478 | |||
| 479 | (defun hierarchy-labelfn-to-string (labelfn item indent) | ||
| 480 | "Execute LABELFN on ITEM and INDENT. Return result as a string." | ||
| 481 | (with-temp-buffer | ||
| 482 | (funcall labelfn item indent) | ||
| 483 | (buffer-substring (point-min) (point-max)))) | ||
| 484 | |||
| 485 | (defun hierarchy-print (hierarchy &optional to-string) | ||
| 486 | "Insert HIERARCHY in current buffer as plain text. | ||
| 487 | |||
| 488 | Use TO-STRING to convert each element to a string. TO-STRING is | ||
| 489 | a function taking an item of HIERARCHY as input and returning a | ||
| 490 | string. If nil, TO-STRING defaults to a call to `format' with \"%s\"." | ||
| 491 | (let ((to-string (or to-string (lambda (item) (format "%s" item))))) | ||
| 492 | (hierarchy-map | ||
| 493 | (hierarchy-labelfn-indent (lambda (item _) | ||
| 494 | (insert (funcall to-string item) "\n"))) | ||
| 495 | hierarchy))) | ||
| 496 | |||
| 497 | (defun hierarchy-to-string (hierarchy &optional to-string) | ||
| 498 | "Return a string representing HIERARCHY. | ||
| 499 | |||
| 500 | TO-STRING is passed unchanged to `hierarchy-print'." | ||
| 501 | (with-temp-buffer | ||
| 502 | (hierarchy-print hierarchy to-string) | ||
| 503 | (buffer-substring (point-min) (point-max)))) | ||
| 504 | |||
| 505 | (defun hierarchy-tabulated-imenu-action (_item-name position) | ||
| 506 | "Move to ITEM-NAME at POSITION in current buffer." | ||
| 507 | (goto-char position) | ||
| 508 | (back-to-indentation)) | ||
| 509 | |||
| 510 | (define-derived-mode hierarchy-tabulated-mode tabulated-list-mode "Hierarchy tabulated" | ||
| 511 | "Major mode to display a hierarchy as a tabulated list." | ||
| 512 | (setq-local imenu-generic-expression | ||
| 513 | ;; debbugs: 26457 - Cannot pass a function to | ||
| 514 | ;; imenu-generic-expression. Add | ||
| 515 | ;; `hierarchy-tabulated-imenu-action' to the end of the | ||
| 516 | ;; list when bug is fixed | ||
| 517 | '(("Item" "^[[:space:]]+\\(?1:.+\\)$" 1)))) | ||
| 518 | |||
| 519 | (defun hierarchy-tabulated-display (hierarchy labelfn &optional buffer) | ||
| 520 | "Display HIERARCHY as a tabulated list in `hierarchy-tabulated-mode'. | ||
| 521 | |||
| 522 | LABELFN is a function taking an item of HIERARCHY and an indentation | ||
| 523 | level (a number) as input and inserting a string to be displayed in the | ||
| 524 | table. | ||
| 525 | |||
| 526 | The tabulated list is displayed in BUFFER, or a newly created buffer if | ||
| 527 | nil. The buffer is returned." | ||
| 528 | (let ((buffer (or buffer (generate-new-buffer "hierarchy-tabulated")))) | ||
| 529 | (with-current-buffer buffer | ||
| 530 | (hierarchy-tabulated-mode) | ||
| 531 | (setq tabulated-list-format | ||
| 532 | (vector '("Item name" 0 nil))) | ||
| 533 | (setq tabulated-list-entries | ||
| 534 | (hierarchy-map (lambda (item indent) | ||
| 535 | (list item (vector (hierarchy-labelfn-to-string | ||
| 536 | labelfn item indent)))) | ||
| 537 | hierarchy)) | ||
| 538 | (tabulated-list-init-header) | ||
| 539 | (tabulated-list-print)) | ||
| 540 | buffer)) | ||
| 541 | |||
| 542 | (declare-function widget-convert "wid-edit") | ||
| 543 | (defun hierarchy-convert-to-tree-widget (hierarchy labelfn) | ||
| 544 | "Return a tree-widget for HIERARCHY. | ||
| 545 | |||
| 546 | LABELFN is a function taking an item of HIERARCHY and an indentation | ||
| 547 | value (a number) as parameter and inserting a string to be displayed as a | ||
| 548 | node label." | ||
| 549 | (require 'wid-edit) | ||
| 550 | (require 'tree-widget) | ||
| 551 | (hierarchy-map-tree (lambda (item indent children) | ||
| 552 | (widget-convert | ||
| 553 | 'tree-widget | ||
| 554 | :tag (hierarchy-labelfn-to-string labelfn item indent) | ||
| 555 | :args children)) | ||
| 556 | hierarchy)) | ||
| 557 | |||
| 558 | (defun hierarchy-tree-display (hierarchy labelfn &optional buffer) | ||
| 559 | "Display HIERARCHY as a tree widget in a new buffer. | ||
| 560 | |||
| 561 | HIERARCHY and LABELFN are passed unchanged to | ||
| 562 | `hierarchy-convert-to-tree-widget'. | ||
| 563 | |||
| 564 | The tree widget is displayed in BUFFER, or a newly created buffer if | ||
| 565 | nil. The buffer is returned." | ||
| 566 | (let ((buffer (or buffer (generate-new-buffer "*hierarchy-tree*"))) | ||
| 567 | (tree-widget (hierarchy-convert-to-tree-widget hierarchy labelfn))) | ||
| 568 | (with-current-buffer buffer | ||
| 569 | (setq-local buffer-read-only t) | ||
| 570 | (let ((inhibit-read-only t)) | ||
| 571 | (erase-buffer) | ||
| 572 | (widget-create tree-widget) | ||
| 573 | (goto-char (point-min)) | ||
| 574 | (special-mode))) | ||
| 575 | buffer)) | ||
| 576 | |||
| 577 | (provide 'hierarchy) | ||
| 578 | |||
| 579 | ;;; hierarchy.el ends here | ||
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el index 4c1a1797adc..1cc68e19edd 100644 --- a/lisp/emacs-lisp/seq.el +++ b/lisp/emacs-lisp/seq.el | |||
| @@ -492,6 +492,7 @@ keys. Keys are compared using `equal'." | |||
| 492 | SEQUENCE must be a sequence of numbers or markers." | 492 | SEQUENCE must be a sequence of numbers or markers." |
| 493 | (apply #'min (seq-into sequence 'list))) | 493 | (apply #'min (seq-into sequence 'list))) |
| 494 | 494 | ||
| 495 | ;;;###autoload | ||
| 495 | (cl-defgeneric seq-max (sequence) | 496 | (cl-defgeneric seq-max (sequence) |
| 496 | "Return the largest element of SEQUENCE. | 497 | "Return the largest element of SEQUENCE. |
| 497 | SEQUENCE must be a sequence of numbers or markers." | 498 | SEQUENCE must be a sequence of numbers or markers." |
diff --git a/lisp/epa-file.el b/lisp/epa-file.el index 20043a9eae4..bbd9279a9a8 100644 --- a/lisp/epa-file.el +++ b/lisp/epa-file.el | |||
| @@ -151,17 +151,25 @@ encryption is used." | |||
| 151 | (nth 3 error))) | 151 | (nth 3 error))) |
| 152 | (let ((exists (file-exists-p local-file))) | 152 | (let ((exists (file-exists-p local-file))) |
| 153 | (when exists | 153 | (when exists |
| 154 | ;; Hack to prevent find-file from opening empty buffer | 154 | (epa-display-error context) |
| 155 | ;; when decryption failed (bug#6568). See the place | 155 | ;; When the .gpg file isn't an encrypted file (e.g., |
| 156 | ;; where `find-file-not-found-functions' are called in | 156 | ;; it's a keyring.gpg file instead), then gpg will |
| 157 | ;; `find-file-noselect-1'. | 157 | ;; say "Unexpected exit" as the error message. In |
| 158 | (setq-local epa-file-error error) | 158 | ;; that case, just display the bytes. |
| 159 | (add-hook 'find-file-not-found-functions | 159 | (if (equal (caddr error) "Unexpected; Exit") |
| 160 | 'epa-file--find-file-not-found-function | 160 | (setq string (with-temp-buffer |
| 161 | nil t) | 161 | (insert-file-contents-literally local-file) |
| 162 | (epa-display-error context)) | 162 | (buffer-string))) |
| 163 | (signal (if exists 'file-error 'file-missing) | 163 | ;; Hack to prevent find-file from opening empty buffer |
| 164 | (cons "Opening input file" (cdr error)))))) | 164 | ;; when decryption failed (bug#6568). See the place |
| 165 | ;; where `find-file-not-found-functions' are called in | ||
| 166 | ;; `find-file-noselect-1'. | ||
| 167 | (setq-local epa-file-error error) | ||
| 168 | (add-hook 'find-file-not-found-functions | ||
| 169 | 'epa-file--find-file-not-found-function | ||
| 170 | nil t) | ||
| 171 | (signal (if exists 'file-error 'file-missing) | ||
| 172 | (cons "Opening input file" (cdr error)))))))) | ||
| 165 | (set-buffer buf) ;In case timer/filter changed/killed it (bug#16029)! | 173 | (set-buffer buf) ;In case timer/filter changed/killed it (bug#16029)! |
| 166 | (setq-local epa-file-encrypt-to | 174 | (setq-local epa-file-encrypt-to |
| 167 | (mapcar #'car (epg-context-result-for | 175 | (mapcar #'car (epg-context-result-for |
diff --git a/lisp/erc/erc-capab.el b/lisp/erc/erc-capab.el index fc45725f789..4afe6a7614b 100644 --- a/lisp/erc/erc-capab.el +++ b/lisp/erc/erc-capab.el | |||
| @@ -170,11 +170,11 @@ PARSED is an `erc-parsed' response struct." | |||
| 170 | (string-match "^\\([-\\+]\\)\\(.+\\)$" msg)) | 170 | (string-match "^\\([-\\+]\\)\\(.+\\)$" msg)) |
| 171 | (setf (erc-response.contents parsed) | 171 | (setf (erc-response.contents parsed) |
| 172 | (if erc-capab-identify-mode | 172 | (if erc-capab-identify-mode |
| 173 | (erc-propertize (match-string 2 msg) | 173 | (propertize (match-string 2 msg) |
| 174 | 'erc-identified | 174 | 'erc-identified |
| 175 | (if (string= (match-string 1 msg) "+") | 175 | (if (string= (match-string 1 msg) "+") |
| 176 | 1 | 176 | 1 |
| 177 | 0)) | 177 | 0)) |
| 178 | (match-string 2 msg))) | 178 | (match-string 2 msg))) |
| 179 | nil))) | 179 | nil))) |
| 180 | 180 | ||
| @@ -190,9 +190,9 @@ PARSED is an `erc-parsed' response struct." | |||
| 190 | ;; assuming the first use of `nickname' is the sender's nick | 190 | ;; assuming the first use of `nickname' is the sender's nick |
| 191 | (re-search-forward (regexp-quote nickname) nil t)) | 191 | (re-search-forward (regexp-quote nickname) nil t)) |
| 192 | (goto-char (match-beginning 0)) | 192 | (goto-char (match-beginning 0)) |
| 193 | (insert (erc-propertize erc-capab-identify-prefix | 193 | (insert (propertize erc-capab-identify-prefix |
| 194 | 'font-lock-face | 194 | 'font-lock-face |
| 195 | 'erc-capab-identify-unidentified)))))) | 195 | 'erc-capab-identify-unidentified)))))) |
| 196 | 196 | ||
| 197 | (defun erc-capab-identify-get-unidentified-nickname (parsed) | 197 | (defun erc-capab-identify-get-unidentified-nickname (parsed) |
| 198 | "Return the nickname of the user if unidentified. | 198 | "Return the nickname of the user if unidentified. |
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 388728b04a0..d71221b2674 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el | |||
| @@ -43,12 +43,12 @@ Return the same string, if the encoding operation is trivial. | |||
| 43 | See `erc-encoding-coding-alist'." | 43 | See `erc-encoding-coding-alist'." |
| 44 | (encode-coding-string s coding-system t)) | 44 | (encode-coding-string s coding-system t)) |
| 45 | 45 | ||
| 46 | (defalias 'erc-propertize 'propertize) | 46 | (define-obsolete-function-alias 'erc-propertize #'propertize "28.1") |
| 47 | (defalias 'erc-view-mode-enter 'view-mode-enter) | 47 | (define-obsolete-function-alias 'erc-view-mode-enter #'view-mode-enter "28.1") |
| 48 | (autoload 'help-function-arglist "help-fns") | 48 | (autoload 'help-function-arglist "help-fns") |
| 49 | (defalias 'erc-function-arglist 'help-function-arglist) | 49 | (define-obsolete-function-alias 'erc-function-arglist #'help-function-arglist "28.1") |
| 50 | (defalias 'erc-delete-dups 'delete-dups) | 50 | (define-obsolete-function-alias 'erc-delete-dups #'delete-dups "28.1") |
| 51 | (defalias 'erc-replace-regexp-in-string 'replace-regexp-in-string) | 51 | (define-obsolete-function-alias 'erc-replace-regexp-in-string #'replace-regexp-in-string "28.1") |
| 52 | 52 | ||
| 53 | (defun erc-set-write-file-functions (new-val) | 53 | (defun erc-set-write-file-functions (new-val) |
| 54 | (set (make-local-variable 'write-file-functions) new-val)) | 54 | (set (make-local-variable 'write-file-functions) new-val)) |
diff --git a/lisp/erc/erc-dcc.el b/lisp/erc/erc-dcc.el index 8ccceec4594..bf98eb818f3 100644 --- a/lisp/erc/erc-dcc.el +++ b/lisp/erc/erc-dcc.el | |||
| @@ -423,7 +423,7 @@ where FOO is one of CLOSE, GET, SEND, LIST, CHAT, etc." | |||
| 423 | #'(lambda (elt) | 423 | #'(lambda (elt) |
| 424 | (eq (plist-get elt :type) 'CHAT)) | 424 | (eq (plist-get elt :type) 'CHAT)) |
| 425 | erc-dcc-list))) | 425 | erc-dcc-list))) |
| 426 | ('close (erc-delete-dups | 426 | ('close (delete-dups |
| 427 | (mapcar (lambda (elt) (symbol-name (plist-get elt :type))) | 427 | (mapcar (lambda (elt) (symbol-name (plist-get elt :type))) |
| 428 | erc-dcc-list))) | 428 | erc-dcc-list))) |
| 429 | ('get (mapcar #'erc-dcc-nick | 429 | ('get (mapcar #'erc-dcc-nick |
| @@ -636,8 +636,8 @@ that subcommand." | |||
| 636 | 636 | ||
| 637 | (define-inline erc-dcc-unquote-filename (filename) | 637 | (define-inline erc-dcc-unquote-filename (filename) |
| 638 | (inline-quote | 638 | (inline-quote |
| 639 | (erc-replace-regexp-in-string "\\\\\\\\" "\\" | 639 | (replace-regexp-in-string "\\\\\\\\" "\\" |
| 640 | (erc-replace-regexp-in-string "\\\\\"" "\"" ,filename t t) t t))) | 640 | (replace-regexp-in-string "\\\\\"" "\"" ,filename t t) t t))) |
| 641 | 641 | ||
| 642 | (defun erc-dcc-handle-ctcp-send (proc query nick login host to) | 642 | (defun erc-dcc-handle-ctcp-send (proc query nick login host to) |
| 643 | "This is called if a CTCP DCC SEND subcommand is sent to the client. | 643 | "This is called if a CTCP DCC SEND subcommand is sent to the client. |
| @@ -1193,8 +1193,8 @@ other client." | |||
| 1193 | (setq posn (match-end 0)) | 1193 | (setq posn (match-end 0)) |
| 1194 | (erc-display-message | 1194 | (erc-display-message |
| 1195 | nil nil proc | 1195 | nil nil proc |
| 1196 | 'dcc-chat-privmsg ?n (erc-propertize erc-dcc-from 'font-lock-face | 1196 | 'dcc-chat-privmsg ?n (propertize erc-dcc-from 'font-lock-face |
| 1197 | 'erc-nick-default-face) ?m line)) | 1197 | 'erc-nick-default-face) ?m line)) |
| 1198 | (setq erc-dcc-unprocessed-output (substring str posn))))) | 1198 | (setq erc-dcc-unprocessed-output (substring str posn))))) |
| 1199 | 1199 | ||
| 1200 | (defun erc-dcc-chat-buffer-killed () | 1200 | (defun erc-dcc-chat-buffer-killed () |
diff --git a/lisp/erc/erc-list.el b/lisp/erc/erc-list.el index 5faeabb721a..036d7733ed7 100644 --- a/lisp/erc/erc-list.el +++ b/lisp/erc/erc-list.el | |||
| @@ -71,13 +71,13 @@ | |||
| 71 | (defun erc-list-make-string (channel users topic) | 71 | (defun erc-list-make-string (channel users topic) |
| 72 | (concat | 72 | (concat |
| 73 | channel | 73 | channel |
| 74 | (erc-propertize " " | 74 | (propertize " " |
| 75 | 'display (list 'space :align-to erc-list-nusers-column) | 75 | 'display (list 'space :align-to erc-list-nusers-column) |
| 76 | 'face 'fixed-pitch) | 76 | 'face 'fixed-pitch) |
| 77 | users | 77 | users |
| 78 | (erc-propertize " " | 78 | (propertize " " |
| 79 | 'display (list 'space :align-to erc-list-topic-column) | 79 | 'display (list 'space :align-to erc-list-topic-column) |
| 80 | 'face 'fixed-pitch) | 80 | 'face 'fixed-pitch) |
| 81 | topic)) | 81 | topic)) |
| 82 | 82 | ||
| 83 | ;; Insert a record into the list buffer. | 83 | ;; Insert a record into the list buffer. |
| @@ -143,19 +143,19 @@ | |||
| 143 | 143 | ||
| 144 | ;; Helper function that makes a buttonized column header. | 144 | ;; Helper function that makes a buttonized column header. |
| 145 | (defun erc-list-button (title column) | 145 | (defun erc-list-button (title column) |
| 146 | (erc-propertize title | 146 | (propertize title |
| 147 | 'column-number column | 147 | 'column-number column |
| 148 | 'help-echo "mouse-1: sort by column" | 148 | 'help-echo "mouse-1: sort by column" |
| 149 | 'mouse-face 'header-line-highlight | 149 | 'mouse-face 'header-line-highlight |
| 150 | 'keymap erc-list-menu-sort-button-map)) | 150 | 'keymap erc-list-menu-sort-button-map)) |
| 151 | 151 | ||
| 152 | (define-derived-mode erc-list-menu-mode special-mode "ERC-List" | 152 | (define-derived-mode erc-list-menu-mode special-mode "ERC-List" |
| 153 | "Major mode for editing a list of irc channels." | 153 | "Major mode for editing a list of irc channels." |
| 154 | (setq header-line-format | 154 | (setq header-line-format |
| 155 | (concat | 155 | (concat |
| 156 | (erc-propertize " " | 156 | (propertize " " |
| 157 | 'display '(space :align-to 0) | 157 | 'display '(space :align-to 0) |
| 158 | 'face 'fixed-pitch) | 158 | 'face 'fixed-pitch) |
| 159 | (erc-list-make-string (erc-list-button "Channel" 1) | 159 | (erc-list-make-string (erc-list-button "Channel" 1) |
| 160 | (erc-list-button "# Users" 2) | 160 | (erc-list-button "# Users" 2) |
| 161 | "Topic"))) | 161 | "Topic"))) |
diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el index 1bad6d16c87..e2c066da9b1 100644 --- a/lisp/erc/erc-log.el +++ b/lisp/erc/erc-log.el | |||
| @@ -334,7 +334,7 @@ This will not work with full paths, only names. | |||
| 334 | 334 | ||
| 335 | Any unsafe characters in the name are replaced with \"!\". The | 335 | Any unsafe characters in the name are replaced with \"!\". The |
| 336 | filename is downcased." | 336 | filename is downcased." |
| 337 | (downcase (erc-replace-regexp-in-string | 337 | (downcase (replace-regexp-in-string |
| 338 | "[/\\]" "!" (convert-standard-filename filename)))) | 338 | "[/\\]" "!" (convert-standard-filename filename)))) |
| 339 | 339 | ||
| 340 | (defun erc-current-logfile (&optional buffer) | 340 | (defun erc-current-logfile (&optional buffer) |
diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 0e98f2bc613..6e87a183fc1 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el | |||
| @@ -577,9 +577,9 @@ See `erc-log-match-format'." | |||
| 577 | (with-current-buffer buffer | 577 | (with-current-buffer buffer |
| 578 | (unless buffer-already | 578 | (unless buffer-already |
| 579 | (insert " == Type \"q\" to dismiss messages ==\n") | 579 | (insert " == Type \"q\" to dismiss messages ==\n") |
| 580 | (erc-view-mode-enter nil (lambda (buffer) | 580 | (view-mode-enter nil (lambda (buffer) |
| 581 | (when (y-or-n-p "Discard messages? ") | 581 | (when (y-or-n-p "Discard messages? ") |
| 582 | (kill-buffer buffer))))) | 582 | (kill-buffer buffer))))) |
| 583 | buffer))) | 583 | buffer))) |
| 584 | 584 | ||
| 585 | (defun erc-log-matches-come-back (proc parsed) | 585 | (defun erc-log-matches-come-back (proc parsed) |
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 415fb53fee0..8551cdd1dee 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el | |||
| @@ -812,7 +812,7 @@ As an example: | |||
| 812 | (let* ((completion-ignore-case t) | 812 | (let* ((completion-ignore-case t) |
| 813 | (net (intern | 813 | (net (intern |
| 814 | (completing-read "Network: " | 814 | (completing-read "Network: " |
| 815 | (erc-delete-dups | 815 | (delete-dups |
| 816 | (mapcar (lambda (x) | 816 | (mapcar (lambda (x) |
| 817 | (list (symbol-name (nth 1 x)))) | 817 | (list (symbol-name (nth 1 x)))) |
| 818 | erc-server-alist))))) | 818 | erc-server-alist))))) |
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 8830dd4c45e..404a4c09975 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el | |||
| @@ -63,6 +63,8 @@ | |||
| 63 | (require 'thingatpt) | 63 | (require 'thingatpt) |
| 64 | (require 'auth-source) | 64 | (require 'auth-source) |
| 65 | (require 'erc-compat) | 65 | (require 'erc-compat) |
| 66 | (require 'time-date) | ||
| 67 | (require 'iso8601) | ||
| 66 | (eval-when-compile (require 'subr-x)) | 68 | (eval-when-compile (require 'subr-x)) |
| 67 | 69 | ||
| 68 | (defvar erc-official-location | 70 | (defvar erc-official-location |
| @@ -1628,9 +1630,10 @@ symbol, it may have these values: | |||
| 1628 | (and (erc-server-buffer-p) | 1630 | (and (erc-server-buffer-p) |
| 1629 | (not (erc-server-process-alive))))) | 1631 | (not (erc-server-process-alive))))) |
| 1630 | ;; Channel buffer; check that it's from the right server. | 1632 | ;; Channel buffer; check that it's from the right server. |
| 1631 | (with-current-buffer (get-buffer candidate) | 1633 | (and target |
| 1632 | (and (string= erc-session-server server) | 1634 | (with-current-buffer (get-buffer candidate) |
| 1633 | (erc-port-equal erc-session-port port))))) | 1635 | (and (string= erc-session-server server) |
| 1636 | (erc-port-equal erc-session-port port)))))) | ||
| 1634 | (setq buffer-name candidate))) | 1637 | (setq buffer-name candidate))) |
| 1635 | ;; if buffer-name is unset, neither candidate worked out for us, | 1638 | ;; if buffer-name is unset, neither candidate worked out for us, |
| 1636 | ;; fallback to the old <N> uniquification method: | 1639 | ;; fallback to the old <N> uniquification method: |
| @@ -1860,7 +1863,7 @@ buffer rather than a server buffer.") | |||
| 1860 | ;; modify `transforms' to specify what needs to be changed | 1863 | ;; modify `transforms' to specify what needs to be changed |
| 1861 | ;; each item is in the format '(old . new) | 1864 | ;; each item is in the format '(old . new) |
| 1862 | (let ((transforms '((pcomplete . completion)))) | 1865 | (let ((transforms '((pcomplete . completion)))) |
| 1863 | (erc-delete-dups | 1866 | (delete-dups |
| 1864 | (mapcar (lambda (m) (or (cdr (assoc m transforms)) m)) | 1867 | (mapcar (lambda (m) (or (cdr (assoc m transforms)) m)) |
| 1865 | mods)))) | 1868 | mods)))) |
| 1866 | 1869 | ||
| @@ -2313,7 +2316,7 @@ and appears in face `erc-input-face' in the buffer." | |||
| 2313 | (setq result (concat result network-name | 2316 | (setq result (concat result network-name |
| 2314 | " << " line "\n"))) | 2317 | " << " line "\n"))) |
| 2315 | result) | 2318 | result) |
| 2316 | (erc-propertize | 2319 | (propertize |
| 2317 | (concat network-name " >> " string | 2320 | (concat network-name " >> " string |
| 2318 | (if (/= ?\n | 2321 | (if (/= ?\n |
| 2319 | (aref string | 2322 | (aref string |
| @@ -2336,7 +2339,7 @@ If ARG is non-nil, show the *erc-protocol* buffer." | |||
| 2336 | (interactive "P") | 2339 | (interactive "P") |
| 2337 | (let* ((buf (get-buffer-create "*erc-protocol*"))) | 2340 | (let* ((buf (get-buffer-create "*erc-protocol*"))) |
| 2338 | (with-current-buffer buf | 2341 | (with-current-buffer buf |
| 2339 | (erc-view-mode-enter) | 2342 | (view-mode-enter) |
| 2340 | (when (null (current-local-map)) | 2343 | (when (null (current-local-map)) |
| 2341 | (let ((inhibit-read-only t)) | 2344 | (let ((inhibit-read-only t)) |
| 2342 | (insert (erc-make-notice "This buffer displays all IRC protocol traffic exchanged with each server.\n")) | 2345 | (insert (erc-make-notice "This buffer displays all IRC protocol traffic exchanged with each server.\n")) |
| @@ -2770,7 +2773,7 @@ See also `erc-server-send'." | |||
| 2770 | 2773 | ||
| 2771 | (defun erc-get-arglist (fun) | 2774 | (defun erc-get-arglist (fun) |
| 2772 | "Return the argument list of a function without the parens." | 2775 | "Return the argument list of a function without the parens." |
| 2773 | (let ((arglist (format "%S" (erc-function-arglist fun)))) | 2776 | (let ((arglist (format "%S" (help-function-arglist fun)))) |
| 2774 | (if (string-match "\\`(\\(.*\\))\\'" arglist) | 2777 | (if (string-match "\\`(\\(.*\\))\\'" arglist) |
| 2775 | (match-string 1 arglist) | 2778 | (match-string 1 arglist) |
| 2776 | arglist))) | 2779 | arglist))) |
| @@ -2905,6 +2908,44 @@ therefore has to contain the command itself as well." | |||
| 2905 | (erc-server-send (substring line 1)) | 2908 | (erc-server-send (substring line 1)) |
| 2906 | t) | 2909 | t) |
| 2907 | 2910 | ||
| 2911 | (defvar erc--read-time-period-history nil) | ||
| 2912 | |||
| 2913 | (defun erc--read-time-period (prompt) | ||
| 2914 | "Read a time period on the \"2h\" format. | ||
| 2915 | If there's no letter spec, the input is interpreted as a number of seconds. | ||
| 2916 | |||
| 2917 | If input is blank, this function returns nil. Otherwise it | ||
| 2918 | returns the time spec converted to a number of seconds." | ||
| 2919 | (let ((period (string-trim | ||
| 2920 | (read-string prompt nil 'erc--read-time-period-history)))) | ||
| 2921 | (cond | ||
| 2922 | ;; Blank input. | ||
| 2923 | ((zerop (length period)) | ||
| 2924 | nil) | ||
| 2925 | ;; All-number -- interpret as seconds. | ||
| 2926 | ((string-match-p "\\`[0-9]+\\'" period) | ||
| 2927 | (string-to-number period)) | ||
| 2928 | ;; Parse as a time spec. | ||
| 2929 | (t | ||
| 2930 | (let ((time (condition-case nil | ||
| 2931 | (iso8601-parse-duration | ||
| 2932 | (concat (cond | ||
| 2933 | ((string-match-p "\\`P" (upcase period)) | ||
| 2934 | ;; Somebody typed in a full ISO8601 period. | ||
| 2935 | (upcase period)) | ||
| 2936 | ((string-match-p "[YD]" (upcase period)) | ||
| 2937 | ;; If we have a year/day element, | ||
| 2938 | ;; we have a full spec. | ||
| 2939 | "P") | ||
| 2940 | (t | ||
| 2941 | ;; Otherwise it's just a sub-day spec. | ||
| 2942 | "PT")) | ||
| 2943 | (upcase period))) | ||
| 2944 | (wrong-type-argument nil)))) | ||
| 2945 | (unless time | ||
| 2946 | (user-error "%s is not a valid time period" period)) | ||
| 2947 | (decoded-time-period time)))))) | ||
| 2948 | |||
| 2908 | (defun erc-cmd-IGNORE (&optional user) | 2949 | (defun erc-cmd-IGNORE (&optional user) |
| 2909 | "Ignore USER. This should be a regexp matching nick!user@host. | 2950 | "Ignore USER. This should be a regexp matching nick!user@host. |
| 2910 | If no USER argument is specified, list the contents of `erc-ignore-list'." | 2951 | If no USER argument is specified, list the contents of `erc-ignore-list'." |
| @@ -2914,10 +2955,18 @@ If no USER argument is specified, list the contents of `erc-ignore-list'." | |||
| 2914 | (y-or-n-p (format "Use regexp-quoted form (%s) instead? " | 2955 | (y-or-n-p (format "Use regexp-quoted form (%s) instead? " |
| 2915 | quoted))) | 2956 | quoted))) |
| 2916 | (setq user quoted)) | 2957 | (setq user quoted)) |
| 2917 | (erc-display-line | 2958 | (let ((timeout |
| 2918 | (erc-make-notice (format "Now ignoring %s" user)) | 2959 | (erc--read-time-period |
| 2919 | 'active) | 2960 | "Add a timeout? (Blank for no, or a time spec like 2h): ")) |
| 2920 | (erc-with-server-buffer (add-to-list 'erc-ignore-list user))) | 2961 | (buffer (current-buffer))) |
| 2962 | (when timeout | ||
| 2963 | (run-at-time timeout nil | ||
| 2964 | (lambda () | ||
| 2965 | (erc--unignore-user user buffer)))) | ||
| 2966 | (erc-display-line | ||
| 2967 | (erc-make-notice (format "Now ignoring %s" user)) | ||
| 2968 | 'active) | ||
| 2969 | (erc-with-server-buffer (add-to-list 'erc-ignore-list user)))) | ||
| 2921 | (if (null (erc-with-server-buffer erc-ignore-list)) | 2970 | (if (null (erc-with-server-buffer erc-ignore-list)) |
| 2922 | (erc-display-line (erc-make-notice "Ignore list is empty") 'active) | 2971 | (erc-display-line (erc-make-notice "Ignore list is empty") 'active) |
| 2923 | (erc-display-line (erc-make-notice "Ignore list:") 'active) | 2972 | (erc-display-line (erc-make-notice "Ignore list:") 'active) |
| @@ -2941,12 +2990,17 @@ If no USER argument is specified, list the contents of `erc-ignore-list'." | |||
| 2941 | (erc-make-notice (format "%s is not currently ignored!" user)) | 2990 | (erc-make-notice (format "%s is not currently ignored!" user)) |
| 2942 | 'active))) | 2991 | 'active))) |
| 2943 | (when ignored-nick | 2992 | (when ignored-nick |
| 2993 | (erc--unignore-user user (current-buffer)))) | ||
| 2994 | t) | ||
| 2995 | |||
| 2996 | (defun erc--unignore-user (user buffer) | ||
| 2997 | (when (buffer-live-p buffer) | ||
| 2998 | (with-current-buffer buffer | ||
| 2944 | (erc-display-line | 2999 | (erc-display-line |
| 2945 | (erc-make-notice (format "No longer ignoring %s" user)) | 3000 | (erc-make-notice (format "No longer ignoring %s" user)) |
| 2946 | 'active) | 3001 | 'active) |
| 2947 | (erc-with-server-buffer | 3002 | (erc-with-server-buffer |
| 2948 | (setq erc-ignore-list (delete ignored-nick erc-ignore-list))))) | 3003 | (setq erc-ignore-list (delete user erc-ignore-list)))))) |
| 2949 | t) | ||
| 2950 | 3004 | ||
| 2951 | (defun erc-cmd-CLEAR () | 3005 | (defun erc-cmd-CLEAR () |
| 2952 | "Clear the window content." | 3006 | "Clear the window content." |
| @@ -3504,7 +3558,7 @@ If S is non-nil, it will be used as the quit reason." | |||
| 3504 | If S is non-nil, it will be used as the quit reason." | 3558 | If S is non-nil, it will be used as the quit reason." |
| 3505 | (or s | 3559 | (or s |
| 3506 | (if (fboundp 'yow) | 3560 | (if (fboundp 'yow) |
| 3507 | (erc-replace-regexp-in-string "\n" "" (yow)) | 3561 | (replace-regexp-in-string "\n" "" (yow)) |
| 3508 | (erc-quit/part-reason-default)))) | 3562 | (erc-quit/part-reason-default)))) |
| 3509 | 3563 | ||
| 3510 | (make-obsolete 'erc-quit-reason-zippy "it will be removed." "24.4") | 3564 | (make-obsolete 'erc-quit-reason-zippy "it will be removed." "24.4") |
| @@ -3531,7 +3585,7 @@ If S is non-nil, it will be used as the part reason." | |||
| 3531 | If S is non-nil, it will be used as the quit reason." | 3585 | If S is non-nil, it will be used as the quit reason." |
| 3532 | (or s | 3586 | (or s |
| 3533 | (if (fboundp 'yow) | 3587 | (if (fboundp 'yow) |
| 3534 | (erc-replace-regexp-in-string "\n" "" (yow)) | 3588 | (replace-regexp-in-string "\n" "" (yow)) |
| 3535 | (erc-quit/part-reason-default)))) | 3589 | (erc-quit/part-reason-default)))) |
| 3536 | 3590 | ||
| 3537 | (make-obsolete 'erc-part-reason-zippy "it will be removed." "24.4") | 3591 | (make-obsolete 'erc-part-reason-zippy "it will be removed." "24.4") |
| @@ -3947,13 +4001,13 @@ If FACE is non-nil, it will be used to propertize the prompt. If it is nil, | |||
| 3947 | ;; Do not extend the text properties when typing at the end | 4001 | ;; Do not extend the text properties when typing at the end |
| 3948 | ;; of the prompt, but stuff typed in front of the prompt | 4002 | ;; of the prompt, but stuff typed in front of the prompt |
| 3949 | ;; shall remain part of the prompt. | 4003 | ;; shall remain part of the prompt. |
| 3950 | (setq prompt (erc-propertize prompt | 4004 | (setq prompt (propertize prompt |
| 3951 | 'start-open t ; XEmacs | 4005 | 'start-open t ; XEmacs |
| 3952 | 'rear-nonsticky t ; Emacs | 4006 | 'rear-nonsticky t ; Emacs |
| 3953 | 'erc-prompt t | 4007 | 'erc-prompt t |
| 3954 | 'field t | 4008 | 'field t |
| 3955 | 'front-sticky t | 4009 | 'front-sticky t |
| 3956 | 'read-only t)) | 4010 | 'read-only t)) |
| 3957 | (erc-put-text-property 0 (1- (length prompt)) | 4011 | (erc-put-text-property 0 (1- (length prompt)) |
| 3958 | 'font-lock-face (or face 'erc-prompt-face) | 4012 | 'font-lock-face (or face 'erc-prompt-face) |
| 3959 | prompt) | 4013 | prompt) |
| @@ -4336,15 +4390,15 @@ See also `erc-format-nick-function'." | |||
| 4336 | (defun erc-get-user-mode-prefix (user) | 4390 | (defun erc-get-user-mode-prefix (user) |
| 4337 | (when user | 4391 | (when user |
| 4338 | (cond ((erc-channel-user-owner-p user) | 4392 | (cond ((erc-channel-user-owner-p user) |
| 4339 | (erc-propertize "~" 'help-echo "owner")) | 4393 | (propertize "~" 'help-echo "owner")) |
| 4340 | ((erc-channel-user-admin-p user) | 4394 | ((erc-channel-user-admin-p user) |
| 4341 | (erc-propertize "&" 'help-echo "admin")) | 4395 | (propertize "&" 'help-echo "admin")) |
| 4342 | ((erc-channel-user-op-p user) | 4396 | ((erc-channel-user-op-p user) |
| 4343 | (erc-propertize "@" 'help-echo "operator")) | 4397 | (propertize "@" 'help-echo "operator")) |
| 4344 | ((erc-channel-user-halfop-p user) | 4398 | ((erc-channel-user-halfop-p user) |
| 4345 | (erc-propertize "%" 'help-echo "half-op")) | 4399 | (propertize "%" 'help-echo "half-op")) |
| 4346 | ((erc-channel-user-voice-p user) | 4400 | ((erc-channel-user-voice-p user) |
| 4347 | (erc-propertize "+" 'help-echo "voice")) | 4401 | (propertize "+" 'help-echo "voice")) |
| 4348 | (t "")))) | 4402 | (t "")))) |
| 4349 | 4403 | ||
| 4350 | (defun erc-format-@nick (&optional user _channel-data) | 4404 | (defun erc-format-@nick (&optional user _channel-data) |
| @@ -4355,7 +4409,7 @@ prefix. Use CHANNEL-DATA to determine op and voice status. See | |||
| 4355 | also `erc-format-nick-function'." | 4409 | also `erc-format-nick-function'." |
| 4356 | (when user | 4410 | (when user |
| 4357 | (let ((nick (erc-server-user-nickname user))) | 4411 | (let ((nick (erc-server-user-nickname user))) |
| 4358 | (concat (erc-propertize | 4412 | (concat (propertize |
| 4359 | (erc-get-user-mode-prefix nick) | 4413 | (erc-get-user-mode-prefix nick) |
| 4360 | 'font-lock-face 'erc-nick-prefix-face) | 4414 | 'font-lock-face 'erc-nick-prefix-face) |
| 4361 | nick)))) | 4415 | nick)))) |
| @@ -4368,12 +4422,12 @@ also `erc-format-nick-function'." | |||
| 4368 | (nick (erc-current-nick)) | 4422 | (nick (erc-current-nick)) |
| 4369 | (mode (erc-get-user-mode-prefix nick))) | 4423 | (mode (erc-get-user-mode-prefix nick))) |
| 4370 | (concat | 4424 | (concat |
| 4371 | (erc-propertize open 'font-lock-face 'erc-default-face) | 4425 | (propertize open 'font-lock-face 'erc-default-face) |
| 4372 | (erc-propertize mode 'font-lock-face 'erc-my-nick-prefix-face) | 4426 | (propertize mode 'font-lock-face 'erc-my-nick-prefix-face) |
| 4373 | (erc-propertize nick 'font-lock-face 'erc-my-nick-face) | 4427 | (propertize nick 'font-lock-face 'erc-my-nick-face) |
| 4374 | (erc-propertize close 'font-lock-face 'erc-default-face))) | 4428 | (propertize close 'font-lock-face 'erc-default-face))) |
| 4375 | (let ((prefix "> ")) | 4429 | (let ((prefix "> ")) |
| 4376 | (erc-propertize prefix 'font-lock-face 'erc-default-face)))) | 4430 | (propertize prefix 'font-lock-face 'erc-default-face)))) |
| 4377 | 4431 | ||
| 4378 | (defun erc-echo-notice-in-default-buffer (s parsed buffer _sender) | 4432 | (defun erc-echo-notice-in-default-buffer (s parsed buffer _sender) |
| 4379 | "Echos a private notice in the default buffer, namely the | 4433 | "Echos a private notice in the default buffer, namely the |
| @@ -6435,16 +6489,16 @@ if `erc-away' is non-nil." | |||
| 6435 | (fill-region (point-min) (point-max)) | 6489 | (fill-region (point-min) (point-max)) |
| 6436 | (buffer-string)))) | 6490 | (buffer-string)))) |
| 6437 | (setq header-line-format | 6491 | (setq header-line-format |
| 6438 | (erc-replace-regexp-in-string | 6492 | (replace-regexp-in-string |
| 6439 | "%" | 6493 | "%" |
| 6440 | "%%" | 6494 | "%%" |
| 6441 | (if face | 6495 | (if face |
| 6442 | (erc-propertize header 'help-echo help-echo | 6496 | (propertize header 'help-echo help-echo |
| 6443 | 'face face) | 6497 | 'face face) |
| 6444 | (erc-propertize header 'help-echo help-echo)))))) | 6498 | (propertize header 'help-echo help-echo)))))) |
| 6445 | (t (setq header-line-format | 6499 | (t (setq header-line-format |
| 6446 | (if face | 6500 | (if face |
| 6447 | (erc-propertize header 'face face) | 6501 | (propertize header 'face face) |
| 6448 | header))))))) | 6502 | header))))))) |
| 6449 | (force-mode-line-update))) | 6503 | (force-mode-line-update))) |
| 6450 | 6504 | ||
| @@ -6711,7 +6765,7 @@ functions." | |||
| 6711 | nick user host channel | 6765 | nick user host channel |
| 6712 | (if (not (string= reason "")) | 6766 | (if (not (string= reason "")) |
| 6713 | (format ": %s" | 6767 | (format ": %s" |
| 6714 | (erc-replace-regexp-in-string "%" "%%" reason)) | 6768 | (replace-regexp-in-string "%" "%%" reason)) |
| 6715 | ""))))) | 6769 | ""))))) |
| 6716 | 6770 | ||
| 6717 | 6771 | ||
diff --git a/lisp/files.el b/lisp/files.el index 742fd78df1d..19096693461 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -2683,8 +2683,6 @@ since only a single case-insensitive search through the alist is made." | |||
| 2683 | ("\\.p\\'" . pascal-mode) | 2683 | ("\\.p\\'" . pascal-mode) |
| 2684 | ("\\.pas\\'" . pascal-mode) | 2684 | ("\\.pas\\'" . pascal-mode) |
| 2685 | ("\\.\\(dpr\\|DPR\\)\\'" . delphi-mode) | 2685 | ("\\.\\(dpr\\|DPR\\)\\'" . delphi-mode) |
| 2686 | ("\\.ad[abs]\\'" . ada-mode) | ||
| 2687 | ("\\.ad[bs]\\.dg\\'" . ada-mode) | ||
| 2688 | ("\\.\\([pP]\\([Llm]\\|erl\\|od\\)\\|al\\)\\'" . perl-mode) | 2686 | ("\\.\\([pP]\\([Llm]\\|erl\\|od\\)\\|al\\)\\'" . perl-mode) |
| 2689 | ("Imakefile\\'" . makefile-imake-mode) | 2687 | ("Imakefile\\'" . makefile-imake-mode) |
| 2690 | ("Makeppfile\\(?:\\.mk\\)?\\'" . makefile-makepp-mode) ; Put this before .mk | 2688 | ("Makeppfile\\(?:\\.mk\\)?\\'" . makefile-makepp-mode) ; Put this before .mk |
diff --git a/lisp/finder.el b/lisp/finder.el index f04d73e098f..820d6d0a3b9 100644 --- a/lisp/finder.el +++ b/lisp/finder.el | |||
| @@ -197,7 +197,7 @@ from; the default is `load-path'." | |||
| 197 | (cons d f)) | 197 | (cons d f)) |
| 198 | (directory-files d nil el-file-regexp)))) | 198 | (directory-files d nil el-file-regexp)))) |
| 199 | (progress (make-progress-reporter | 199 | (progress (make-progress-reporter |
| 200 | (byte-compile-info-string "Scanning files for finder") | 200 | (byte-compile-info "Scanning files for finder") |
| 201 | 0 (length files))) | 201 | 0 (length files))) |
| 202 | package-override base-name ; processed | 202 | package-override base-name ; processed |
| 203 | summary keywords package version entry desc) | 203 | summary keywords package version entry desc) |
diff --git a/lisp/generic-x.el b/lisp/generic-x.el index cd24f497c96..48ac1232051 100644 --- a/lisp/generic-x.el +++ b/lisp/generic-x.el | |||
| @@ -643,7 +643,7 @@ like an INI file. You can add this hook to `find-file-hook'." | |||
| 643 | ("\\([^ =\n\r]+\\)=\\([^ \n\r]*\\)" | 643 | ("\\([^ =\n\r]+\\)=\\([^ \n\r]*\\)" |
| 644 | (1 font-lock-variable-name-face) | 644 | (1 font-lock-variable-name-face) |
| 645 | (2 font-lock-keyword-face))) | 645 | (2 font-lock-keyword-face))) |
| 646 | '("inventory") | 646 | '("inventory\\'") |
| 647 | (list | 647 | (list |
| 648 | (function | 648 | (function |
| 649 | (lambda () | 649 | (lambda () |
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el index cb20d7102bd..e0339cc1f32 100644 --- a/lisp/gnus/gnus-art.el +++ b/lisp/gnus/gnus-art.el | |||
| @@ -5849,7 +5849,10 @@ all parts." | |||
| 5849 | (concat "; " gnus-tmp-name)))) | 5849 | (concat "; " gnus-tmp-name)))) |
| 5850 | (unless (equal gnus-tmp-description "") | 5850 | (unless (equal gnus-tmp-description "") |
| 5851 | (setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long))) | 5851 | (setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long))) |
| 5852 | (when (zerop gnus-tmp-length) | 5852 | (when (and (zerop gnus-tmp-length) |
| 5853 | ;; Only nnimap supports partial fetches so far. | ||
| 5854 | nnimap-fetch-partial-articles | ||
| 5855 | (string-match "^nnimap\\+" gnus-newsgroup-name)) | ||
| 5853 | (setq gnus-tmp-type-long | 5856 | (setq gnus-tmp-type-long |
| 5854 | (concat | 5857 | (concat |
| 5855 | gnus-tmp-type-long | 5858 | gnus-tmp-type-long |
| @@ -6018,6 +6021,7 @@ If nil, don't show those extra buttons." | |||
| 6018 | (defun gnus-mime-display-single (handle) | 6021 | (defun gnus-mime-display-single (handle) |
| 6019 | (let ((type (mm-handle-media-type handle)) | 6022 | (let ((type (mm-handle-media-type handle)) |
| 6020 | (ignored gnus-ignored-mime-types) | 6023 | (ignored gnus-ignored-mime-types) |
| 6024 | (mm-inline-font-lock (gnus-visual-p 'article-highlight 'highlight)) | ||
| 6021 | (not-attachment t) | 6025 | (not-attachment t) |
| 6022 | display text) | 6026 | display text) |
| 6023 | (catch 'ignored | 6027 | (catch 'ignored |
| @@ -8340,6 +8344,7 @@ url is put as the `gnus-button-url' overlay property on the button." | |||
| 8340 | (and (match-end 6) (list (string-to-number (match-string 6 address)))))))) | 8344 | (and (match-end 6) (list (string-to-number (match-string 6 address)))))))) |
| 8341 | 8345 | ||
| 8342 | (defun gnus-url-parse-query-string (query &optional downcase) | 8346 | (defun gnus-url-parse-query-string (query &optional downcase) |
| 8347 | (declare (obsolete message-parse-mailto-url "28.1")) | ||
| 8343 | (let (retval pairs cur key val) | 8348 | (let (retval pairs cur key val) |
| 8344 | (setq pairs (split-string query "&")) | 8349 | (setq pairs (split-string query "&")) |
| 8345 | (while pairs | 8350 | (while pairs |
| @@ -8359,31 +8364,8 @@ url is put as the `gnus-button-url' overlay property on the button." | |||
| 8359 | 8364 | ||
| 8360 | (defun gnus-url-mailto (url) | 8365 | (defun gnus-url-mailto (url) |
| 8361 | ;; Send mail to someone | 8366 | ;; Send mail to someone |
| 8362 | (setq url (replace-regexp-in-string "\n" " " url)) | 8367 | (gnus-msg-mail) |
| 8363 | (when (string-match "mailto:/*\\(.*\\)" url) | 8368 | (message-mailto-1 url)) |
| 8364 | (setq url (substring url (match-beginning 1) nil))) | ||
| 8365 | (let* ((args (gnus-url-parse-query-string | ||
| 8366 | (if (string-match "^\\?" url) | ||
| 8367 | (substring url 1) | ||
| 8368 | (if (string-match "^\\([^?]+\\)\\?\\(.*\\)" url) | ||
| 8369 | (concat "to=" (match-string 1 url) "&" | ||
| 8370 | (match-string 2 url)) | ||
| 8371 | (concat "to=" url))))) | ||
| 8372 | (subject (cdr-safe (assoc "subject" args))) | ||
| 8373 | func) | ||
| 8374 | (gnus-msg-mail) | ||
| 8375 | (while args | ||
| 8376 | (setq func (intern-soft (concat "message-goto-" (downcase (caar args))))) | ||
| 8377 | (if (fboundp func) | ||
| 8378 | (funcall func) | ||
| 8379 | (message-position-on-field (caar args))) | ||
| 8380 | (insert (replace-regexp-in-string | ||
| 8381 | "\r\n" "\n" | ||
| 8382 | (mapconcat #'identity (reverse (cdar args)) ", ") nil t)) | ||
| 8383 | (setq args (cdr args))) | ||
| 8384 | (if subject | ||
| 8385 | (message-goto-body) | ||
| 8386 | (message-goto-subject)))) | ||
| 8387 | 8369 | ||
| 8388 | (defun gnus-button-embedded-url (address) | 8370 | (defun gnus-button-embedded-url (address) |
| 8389 | "Activate ADDRESS with `browse-url'." | 8371 | "Activate ADDRESS with `browse-url'." |
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 305e17fd8fc..29d3e30780f 100644 --- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el | |||
| @@ -312,7 +312,8 @@ status will be retrieved from the first matching attendee record." | |||
| 312 | 312 | ||
| 313 | (unless (gnus-icalendar-find-if (lambda (x) (string-match "^ATTENDEE" x)) | 313 | (unless (gnus-icalendar-find-if (lambda (x) (string-match "^ATTENDEE" x)) |
| 314 | reply-event-lines) | 314 | reply-event-lines) |
| 315 | (error "Could not find an event attendee matching given identity")) | 315 | (lwarn 'gnus-icalendar :warning |
| 316 | "Could not find an event attendee matching given identity")) | ||
| 316 | 317 | ||
| 317 | (mapconcat #'identity `("BEGIN:VEVENT" | 318 | (mapconcat #'identity `("BEGIN:VEVENT" |
| 318 | ,@(nreverse reply-event-lines) | 319 | ,@(nreverse reply-event-lines) |
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el index 719498a0337..4363860eac8 100644 --- a/lisp/gnus/gnus-sum.el +++ b/lisp/gnus/gnus-sum.el | |||
| @@ -12284,7 +12284,7 @@ no matter what the properties `:decode' and `:headers' are." | |||
| 12284 | (interactive (gnus-interactive "P\ny")) | 12284 | (interactive (gnus-interactive "P\ny")) |
| 12285 | (require 'gnus-art) | 12285 | (require 'gnus-art) |
| 12286 | (let* ((articles (gnus-summary-work-articles n)) | 12286 | (let* ((articles (gnus-summary-work-articles n)) |
| 12287 | (result-buffer "*Shell Command Output*") | 12287 | (result-buffer shell-command-buffer-name) |
| 12288 | (all-headers (not (memq sym '(nil r)))) | 12288 | (all-headers (not (memq sym '(nil r)))) |
| 12289 | (gnus-save-all-headers (or all-headers gnus-save-all-headers)) | 12289 | (gnus-save-all-headers (or all-headers gnus-save-all-headers)) |
| 12290 | (raw (eq sym 'r)) | 12290 | (raw (eq sym 'r)) |
diff --git a/lisp/gnus/gnus-util.el b/lisp/gnus/gnus-util.el index 8d8956f1fb9..abe546b8cb6 100644 --- a/lisp/gnus/gnus-util.el +++ b/lisp/gnus/gnus-util.el | |||
| @@ -1654,6 +1654,7 @@ The first found will be returned if a file has hard or symbolic links." | |||
| 1654 | "To each element of LIST apply PREDICATE. | 1654 | "To each element of LIST apply PREDICATE. |
| 1655 | Return nil if LIST is no list or is empty or some test returns nil; | 1655 | Return nil if LIST is no list or is empty or some test returns nil; |
| 1656 | otherwise, return t." | 1656 | otherwise, return t." |
| 1657 | (declare (obsolete nil "28.1")) | ||
| 1657 | (when (and list (listp list)) | 1658 | (when (and list (listp list)) |
| 1658 | (let ((result (mapcar predicate list))) | 1659 | (let ((result (mapcar predicate list))) |
| 1659 | (not (memq nil result))))) | 1660 | (not (memq nil result))))) |
diff --git a/lisp/gnus/gnus-win.el b/lisp/gnus/gnus-win.el index 36b28350362..baa3146e64e 100644 --- a/lisp/gnus/gnus-win.el +++ b/lisp/gnus/gnus-win.el | |||
| @@ -142,7 +142,7 @@ used to display Gnus windows." | |||
| 142 | (pipe | 142 | (pipe |
| 143 | (vertical 1.0 | 143 | (vertical 1.0 |
| 144 | (summary 0.25 point) | 144 | (summary 0.25 point) |
| 145 | ("*Shell Command Output*" 1.0))) | 145 | (shell-command-buffer-name 1.0))) |
| 146 | (bug | 146 | (bug |
| 147 | (vertical 1.0 | 147 | (vertical 1.0 |
| 148 | (if gnus-bug-create-help-buffer '("*Gnus Help Bug*" 0.5)) | 148 | (if gnus-bug-create-help-buffer '("*Gnus Help Bug*" 0.5)) |
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index fb560f0eab8..ab625be9e37 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el | |||
| @@ -303,6 +303,13 @@ any confusion." | |||
| 303 | :link '(custom-manual "(message)Message Headers") | 303 | :link '(custom-manual "(message)Message Headers") |
| 304 | :type 'regexp) | 304 | :type 'regexp) |
| 305 | 305 | ||
| 306 | (defcustom message-screenshot-command '("import" "png:-") | ||
| 307 | "Command to take a screenshot. | ||
| 308 | The command should insert a PNG in the current buffer." | ||
| 309 | :group 'message-various | ||
| 310 | :type '(list string) | ||
| 311 | :version "28.1") | ||
| 312 | |||
| 306 | ;;; Start of variables adopted from `message-utils.el'. | 313 | ;;; Start of variables adopted from `message-utils.el'. |
| 307 | 314 | ||
| 308 | (defcustom message-subject-trailing-was-query t | 315 | (defcustom message-subject-trailing-was-query t |
| @@ -2730,6 +2737,64 @@ systematically send encrypted emails when possible." | |||
| 2730 | (when (message-all-epg-keys-available-p) | 2737 | (when (message-all-epg-keys-available-p) |
| 2731 | (mml-secure-message-sign-encrypt))) | 2738 | (mml-secure-message-sign-encrypt))) |
| 2732 | 2739 | ||
| 2740 | (defcustom message-openpgp-header nil | ||
| 2741 | "Specification for the \"OpenPGP\" header of outgoing messages. | ||
| 2742 | |||
| 2743 | The value must be a list of three elements, all strings: | ||
| 2744 | - Key ID, in hexadecimal form; | ||
| 2745 | - Key URL or ASCII armoured key; and | ||
| 2746 | - Protection preference, one of: \"unprotected\", \"sign\", | ||
| 2747 | \"encrypt\" or \"signencrypt\". | ||
| 2748 | |||
| 2749 | Each of the elements may be nil, in which case its part in the | ||
| 2750 | OpenPGP header will be left out. If all the values are nil, | ||
| 2751 | or `message-openpgp-header' is itself nil, the OpenPGP header | ||
| 2752 | will not be inserted." | ||
| 2753 | :type '(choice | ||
| 2754 | (const nil :tag "Don't add OpenPGP header") | ||
| 2755 | (list (choice (string :tag "ID") | ||
| 2756 | (const nil :tag "No ID")) | ||
| 2757 | (choice (string :tag "Key") | ||
| 2758 | (const nil :tag "No Key")) | ||
| 2759 | (choice (other nil :tag "None") | ||
| 2760 | (const "unprotected" :tag "Unprotected") | ||
| 2761 | (const "sign" :tag "Sign") | ||
| 2762 | (const "encrypt" :tag "Encrypt") | ||
| 2763 | (const "signencrypt" :tag "Sign and Encrypt")))) | ||
| 2764 | :version "28.1") | ||
| 2765 | |||
| 2766 | (defun message-add-openpgp-header () | ||
| 2767 | "Add OpenPGP header to point to public key. | ||
| 2768 | |||
| 2769 | Header will be constructed as specified in `message-openpgp-header'. | ||
| 2770 | |||
| 2771 | Consider adding this function to `message-send-hook'." | ||
| 2772 | ;; See https://tools.ietf.org/html/draft-josefsson-openpgp-mailnews-header | ||
| 2773 | (when (and message-openpgp-header | ||
| 2774 | (or (nth 0 message-openpgp-header) | ||
| 2775 | (nth 1 message-openpgp-header) | ||
| 2776 | (nth 2 message-openpgp-header))) | ||
| 2777 | (with-temp-buffer | ||
| 2778 | (insert "OpenPGP: ") | ||
| 2779 | ;; add ID | ||
| 2780 | (let (need-sep) | ||
| 2781 | (when (nth 0 message-openpgp-header) | ||
| 2782 | (insert "id=" (nth 0 message-openpgp-header)) | ||
| 2783 | (setq need-sep t)) | ||
| 2784 | ;; add URL | ||
| 2785 | (when (nth 1 message-openpgp-header) | ||
| 2786 | (when need-sep (insert "; ")) | ||
| 2787 | (if (string-match-p ";") | ||
| 2788 | (insert "url=\"" (nth 1 message-openpgp-header) "\"") | ||
| 2789 | (insert "url=\"" (nth 1 message-openpgp-header) "\"")) | ||
| 2790 | (setq need-sep t)) | ||
| 2791 | ;; add preference | ||
| 2792 | (when (nth 2 message-openpgp-header) | ||
| 2793 | (when need-sep (insert "; ")) | ||
| 2794 | (insert "preference=" (nth 2 message-openpgp-header)))) | ||
| 2795 | ;; insert header | ||
| 2796 | (message-add-header (buffer-string))))) | ||
| 2797 | |||
| 2733 | 2798 | ||
| 2734 | 2799 | ||
| 2735 | ;;; | 2800 | ;;; |
| @@ -2810,6 +2875,7 @@ systematically send encrypted emails when possible." | |||
| 2810 | (define-key message-mode-map [remap split-line] 'message-split-line) | 2875 | (define-key message-mode-map [remap split-line] 'message-split-line) |
| 2811 | 2876 | ||
| 2812 | (define-key message-mode-map "\C-c\C-a" 'mml-attach-file) | 2877 | (define-key message-mode-map "\C-c\C-a" 'mml-attach-file) |
| 2878 | (define-key message-mode-map "\C-c\C-p" 'message-insert-screenshot) | ||
| 2813 | 2879 | ||
| 2814 | (define-key message-mode-map "\C-a" 'message-beginning-of-line) | 2880 | (define-key message-mode-map "\C-a" 'message-beginning-of-line) |
| 2815 | (define-key message-mode-map "\t" 'message-tab) | 2881 | (define-key message-mode-map "\t" 'message-tab) |
| @@ -2839,6 +2905,8 @@ systematically send encrypted emails when possible." | |||
| 2839 | :active (message-mark-active-p) :help "Mark region with enclosing tags"] | 2905 | :active (message-mark-active-p) :help "Mark region with enclosing tags"] |
| 2840 | ["Insert File Marked..." message-mark-insert-file | 2906 | ["Insert File Marked..." message-mark-insert-file |
| 2841 | :help "Insert file at point marked with enclosing tags"] | 2907 | :help "Insert file at point marked with enclosing tags"] |
| 2908 | ["Attach File..." mml-attach-file t] | ||
| 2909 | ["Insert Screenshot" message-insert-screenshot t] | ||
| 2842 | "----" | 2910 | "----" |
| 2843 | ["Send Message" message-send-and-exit :help "Send this message"] | 2911 | ["Send Message" message-send-and-exit :help "Send this message"] |
| 2844 | ["Postpone Message" message-dont-send | 2912 | ["Postpone Message" message-dont-send |
| @@ -6988,15 +7056,28 @@ want to get rid of this query permanently."))) | |||
| 6988 | 7056 | ||
| 6989 | ;; Build the header alist. Allow the user to be asked whether | 7057 | ;; Build the header alist. Allow the user to be asked whether |
| 6990 | ;; or not to reply to all recipients in a wide reply. | 7058 | ;; or not to reply to all recipients in a wide reply. |
| 6991 | (setq follow-to (list (cons 'To (cdr (pop recipients))))) | 7059 | (when (or (< (length recipients) 2) |
| 6992 | (when (and recipients | 7060 | (not message-wide-reply-confirm-recipients) |
| 6993 | (or (not message-wide-reply-confirm-recipients) | 7061 | (y-or-n-p "Reply to all recipients? ")) |
| 6994 | (y-or-n-p "Reply to all recipients? "))) | 7062 | (if never-mct |
| 6995 | (setq recipients (mapconcat | 7063 | ;; The author has requested never to get a (wide) |
| 6996 | (lambda (addr) (cdr addr)) recipients ", ")) | 7064 | ;; response, so put everybody else into the To header. |
| 6997 | (if (string-match "^ +" recipients) | 7065 | ;; This avoids looking as if we're To-in somebody else in |
| 6998 | (setq recipients (substring recipients (match-end 0)))) | 7066 | ;; specific, and just Cc-in the rest. |
| 6999 | (push (cons 'Cc recipients) follow-to))) | 7067 | (setq follow-to (list |
| 7068 | (cons 'To | ||
| 7069 | (mapconcat | ||
| 7070 | (lambda (addr) | ||
| 7071 | (cdr addr)) recipients ", ")))) | ||
| 7072 | ;; Put the first recipient in the To header. | ||
| 7073 | (setq follow-to (list (cons 'To (cdr (pop recipients))))) | ||
| 7074 | ;; Put the rest of the recipients in Cc. | ||
| 7075 | (when recipients | ||
| 7076 | (setq recipients (mapconcat | ||
| 7077 | (lambda (addr) (cdr addr)) recipients ", ")) | ||
| 7078 | (if (string-match "^ +" recipients) | ||
| 7079 | (setq recipients (substring recipients (match-end 0)))) | ||
| 7080 | (push (cons 'Cc recipients) follow-to))))) | ||
| 7000 | follow-to)) | 7081 | follow-to)) |
| 7001 | 7082 | ||
| 7002 | (defun message-prune-recipients (recipients) | 7083 | (defun message-prune-recipients (recipients) |
| @@ -8652,6 +8733,108 @@ Used in `message-simplify-recipients'." | |||
| 8652 | (* 0.5 (- (nth 3 edges) (nth 1 edges))))) | 8733 | (* 0.5 (- (nth 3 edges) (nth 1 edges))))) |
| 8653 | string))))))) | 8734 | string))))))) |
| 8654 | 8735 | ||
| 8736 | (defun message-insert-screenshot (delay) | ||
| 8737 | "Take a screenshot and insert in the current buffer. | ||
| 8738 | DELAY (the numeric prefix) says how many seconds to wait before | ||
| 8739 | starting the screenshotting process. | ||
| 8740 | |||
| 8741 | The `message-screenshot-command' variable says what command is | ||
| 8742 | used to take the screenshot." | ||
| 8743 | (interactive "p") | ||
| 8744 | (unless (executable-find (car message-screenshot-command)) | ||
| 8745 | (error "Can't find %s to take the screenshot" | ||
| 8746 | (car message-screenshot-command))) | ||
| 8747 | (cl-decf delay) | ||
| 8748 | (unless (zerop delay) | ||
| 8749 | (dotimes (i delay) | ||
| 8750 | (message "Sleeping %d second%s..." | ||
| 8751 | (- delay i) | ||
| 8752 | (if (= (- delay i) 1) | ||
| 8753 | "" | ||
| 8754 | "s")) | ||
| 8755 | (sleep-for 1))) | ||
| 8756 | (message "Take screenshot") | ||
| 8757 | (let ((image | ||
| 8758 | (with-temp-buffer | ||
| 8759 | (set-buffer-multibyte nil) | ||
| 8760 | (apply #'call-process | ||
| 8761 | (car message-screenshot-command) nil (current-buffer) nil | ||
| 8762 | (cdr message-screenshot-command)) | ||
| 8763 | (buffer-string)))) | ||
| 8764 | (set-mark (point)) | ||
| 8765 | (insert-image | ||
| 8766 | (create-image image 'png t | ||
| 8767 | :max-width (truncate (* (frame-pixel-width) 0.8)) | ||
| 8768 | :max-height (truncate (* (frame-pixel-height) 0.8)) | ||
| 8769 | :scale 1) | ||
| 8770 | (format "<#part type=\"image/png\" disposition=inline data-encoding=base64 raw=t>\n%s\n<#/part>" | ||
| 8771 | ;; Get a base64 version of the image -- this avoids later | ||
| 8772 | ;; complications if we're auto-saving the buffer and | ||
| 8773 | ;; restoring from a file. | ||
| 8774 | (with-temp-buffer | ||
| 8775 | (set-buffer-multibyte nil) | ||
| 8776 | (insert image) | ||
| 8777 | (base64-encode-region (point-min) (point-max) t) | ||
| 8778 | (buffer-string)))) | ||
| 8779 | (insert "\n\n") | ||
| 8780 | (message ""))) | ||
| 8781 | |||
| 8782 | (declare-function gnus-url-unhex-string "gnus-util") | ||
| 8783 | |||
| 8784 | (defun message-parse-mailto-url (url) | ||
| 8785 | "Parse a mailto: url." | ||
| 8786 | (setq url (replace-regexp-in-string "\n" " " url)) | ||
| 8787 | (when (string-match "mailto:/*\\(.*\\)" url) | ||
| 8788 | (setq url (substring url (match-beginning 1) nil))) | ||
| 8789 | (setq url (if (string-match "^\\?" url) | ||
| 8790 | (substring url 1) | ||
| 8791 | (if (string-match "^\\([^?]+\\)\\?\\(.*\\)" url) | ||
| 8792 | (concat "to=" (match-string 1 url) "&" | ||
| 8793 | (match-string 2 url)) | ||
| 8794 | (concat "to=" url)))) | ||
| 8795 | (let (retval pairs cur key val) | ||
| 8796 | (setq pairs (split-string url "&")) | ||
| 8797 | (while pairs | ||
| 8798 | (setq cur (car pairs) | ||
| 8799 | pairs (cdr pairs)) | ||
| 8800 | (if (not (string-match "=" cur)) | ||
| 8801 | nil ; Grace | ||
| 8802 | (setq key (downcase (gnus-url-unhex-string | ||
| 8803 | (substring cur 0 (match-beginning 0)))) | ||
| 8804 | val (gnus-url-unhex-string (substring cur (match-end 0) nil) t)) | ||
| 8805 | (setq cur (assoc key retval)) | ||
| 8806 | (if cur | ||
| 8807 | (setcdr cur (cons val (cdr cur))) | ||
| 8808 | (setq retval (cons (list key val) retval))))) | ||
| 8809 | retval)) | ||
| 8810 | |||
| 8811 | ;;;###autoload | ||
| 8812 | (defun message-mailto () | ||
| 8813 | "Command to parse command line mailto: links. | ||
| 8814 | This is meant to be used for MIME handlers: Setting the handler | ||
| 8815 | for \"x-scheme-handler/mailto;\" to \"emacs -f message-mailto %u\" | ||
| 8816 | will then start up Emacs ready to compose mail." | ||
| 8817 | (interactive) | ||
| 8818 | ;; <a href="mailto:someone@example.com?subject=This%20is%20the%20subject&cc=someone_else@example.com&body=This%20is%20the%20body">Send email</a> | ||
| 8819 | (message-mail) | ||
| 8820 | (message-mailto-1 (pop command-line-args-left))) | ||
| 8821 | |||
| 8822 | (defun message-mailto-1 (url) | ||
| 8823 | (let ((args (message-parse-mailto-url url))) | ||
| 8824 | (dolist (arg args) | ||
| 8825 | (unless (equal (car arg) "body") | ||
| 8826 | (message-position-on-field (capitalize (car arg))) | ||
| 8827 | (insert (replace-regexp-in-string | ||
| 8828 | "\r\n" "\n" | ||
| 8829 | (mapconcat #'identity (reverse (cdr arg)) ", ") nil t)))) | ||
| 8830 | (when (assoc "body" args) | ||
| 8831 | (message-goto-body) | ||
| 8832 | (dolist (body (cdr (assoc "body" args))) | ||
| 8833 | (insert body "\n"))) | ||
| 8834 | (if (assoc "subject" args) | ||
| 8835 | (message-goto-body) | ||
| 8836 | (message-goto-subject)))) | ||
| 8837 | |||
| 8655 | (provide 'message) | 8838 | (provide 'message) |
| 8656 | 8839 | ||
| 8657 | (run-hooks 'message-load-hook) | 8840 | (run-hooks 'message-load-hook) |
diff --git a/lisp/gnus/mm-decode.el b/lisp/gnus/mm-decode.el index 587c4e01b92..7f8ab5f9ef5 100644 --- a/lisp/gnus/mm-decode.el +++ b/lisp/gnus/mm-decode.el | |||
| @@ -1680,6 +1680,12 @@ If RECURSIVE, search recursively." | |||
| 1680 | (t (y-or-n-p | 1680 | (t (y-or-n-p |
| 1681 | (format "Decrypt (S/MIME) part? ")))) | 1681 | (format "Decrypt (S/MIME) part? ")))) |
| 1682 | (mm-view-pkcs7 parts from)) | 1682 | (mm-view-pkcs7 parts from)) |
| 1683 | (goto-char (point-min)) | ||
| 1684 | ;; The encrypted document is a MIME part, and may use either | ||
| 1685 | ;; CRLF (Outlook and the like) or newlines for end-of-line | ||
| 1686 | ;; markers. Translate from CRLF. | ||
| 1687 | (while (search-forward "\r\n" nil t) | ||
| 1688 | (replace-match "\n")) | ||
| 1683 | ;; Normally there will be a Content-type header here, but | 1689 | ;; Normally there will be a Content-type header here, but |
| 1684 | ;; some mailers don't add that to the encrypted part, which | 1690 | ;; some mailers don't add that to the encrypted part, which |
| 1685 | ;; makes the subsequent re-dissection fail here. | 1691 | ;; makes the subsequent re-dissection fail here. |
diff --git a/lisp/gnus/mm-view.el b/lisp/gnus/mm-view.el index 828ac633dc5..bd5960c18b2 100644 --- a/lisp/gnus/mm-view.el +++ b/lisp/gnus/mm-view.el | |||
| @@ -59,11 +59,16 @@ | |||
| 59 | "The attributes of renderer types for text/html.") | 59 | "The attributes of renderer types for text/html.") |
| 60 | 60 | ||
| 61 | (defcustom mm-fill-flowed t | 61 | (defcustom mm-fill-flowed t |
| 62 | "If non-nil a format=flowed article will be displayed flowed." | 62 | "If non-nil, format=flowed articles will be displayed flowed." |
| 63 | :type 'boolean | 63 | :type 'boolean |
| 64 | :version "22.1" | 64 | :version "22.1" |
| 65 | :group 'mime-display) | 65 | :group 'mime-display) |
| 66 | 66 | ||
| 67 | ;; Not a defcustom, since it's usually overridden by the callers of | ||
| 68 | ;; the mm functions. | ||
| 69 | (defvar mm-inline-font-lock t | ||
| 70 | "If non-nil, do font locking of inline media types that support it.") | ||
| 71 | |||
| 67 | (defcustom mm-inline-large-images-proportion 0.9 | 72 | (defcustom mm-inline-large-images-proportion 0.9 |
| 68 | "Maximum proportion large images can occupy in the buffer. | 73 | "Maximum proportion large images can occupy in the buffer. |
| 69 | This is only used if `mm-inline-large-images' is set to | 74 | This is only used if `mm-inline-large-images' is set to |
| @@ -502,7 +507,8 @@ If MODE is not set, try to find mode automatically." | |||
| 502 | (delay-mode-hooks (set-auto-mode)) | 507 | (delay-mode-hooks (set-auto-mode)) |
| 503 | (setq mode major-mode))) | 508 | (setq mode major-mode))) |
| 504 | ;; Do not fontify if the guess mode is fundamental. | 509 | ;; Do not fontify if the guess mode is fundamental. |
| 505 | (unless (eq major-mode 'fundamental-mode) | 510 | (when (and (not (eq major-mode 'fundamental-mode)) |
| 511 | mm-inline-font-lock) | ||
| 506 | (font-lock-ensure)))) | 512 | (font-lock-ensure)))) |
| 507 | (setq text (buffer-string)) | 513 | (setq text (buffer-string)) |
| 508 | (when (eq mode 'diff-mode) | 514 | (when (eq mode 'diff-mode) |
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el index 740e1d2b722..69852c381d6 100644 --- a/lisp/gnus/mml-sec.el +++ b/lisp/gnus/mml-sec.el | |||
| @@ -665,8 +665,9 @@ The passphrase is read and cached." | |||
| 665 | (epg-user-id-string uid)))) | 665 | (epg-user-id-string uid)))) |
| 666 | (equal (downcase (car (mail-header-parse-address | 666 | (equal (downcase (car (mail-header-parse-address |
| 667 | (epg-user-id-string uid)))) | 667 | (epg-user-id-string uid)))) |
| 668 | (downcase (car (mail-header-parse-address | 668 | (downcase (or (car (mail-header-parse-address |
| 669 | recipient)))) | 669 | recipient)) |
| 670 | recipient))) | ||
| 670 | (not (memq (epg-user-id-validity uid) | 671 | (not (memq (epg-user-id-validity uid) |
| 671 | '(revoked expired)))) | 672 | '(revoked expired)))) |
| 672 | (throw 'break t)))))) | 673 | (throw 'break t)))))) |
| @@ -937,6 +938,10 @@ If no one is selected, symmetric encryption will be performed. " | |||
| 937 | (signal (car error) (cdr error)))) | 938 | (signal (car error) (cdr error)))) |
| 938 | cipher)) | 939 | cipher)) |
| 939 | 940 | ||
| 941 | ;; Should probably be removed and the interface should be different. | ||
| 942 | (defvar mml-secure-allow-signing-with-unknown-recipient nil | ||
| 943 | "Variable to bind to allow automatic recipient selection.") | ||
| 944 | |||
| 940 | (defun mml-secure-epg-sign (protocol mode) | 945 | (defun mml-secure-epg-sign (protocol mode) |
| 941 | ;; Based on code appearing inside mml2015-epg-sign. | 946 | ;; Based on code appearing inside mml2015-epg-sign. |
| 942 | (let* ((context (epg-make-context protocol)) | 947 | (let* ((context (epg-make-context protocol)) |
| @@ -953,7 +958,8 @@ If no one is selected, symmetric encryption will be performed. " | |||
| 953 | ;; then there's no point advising the user to examine it. If | 958 | ;; then there's no point advising the user to examine it. If |
| 954 | ;; there are any other variables worth examining, please | 959 | ;; there are any other variables worth examining, please |
| 955 | ;; improve this error message by having it mention them. | 960 | ;; improve this error message by having it mention them. |
| 956 | (error "Couldn't find any signer names%s" maybe-msg))) | 961 | (unless mml-secure-allow-signing-with-unknown-recipient |
| 962 | (error "Couldn't find any signer names%s" maybe-msg)))) | ||
| 957 | (when (eq 'OpenPGP protocol) | 963 | (when (eq 'OpenPGP protocol) |
| 958 | (setf (epg-context-armor context) t) | 964 | (setf (epg-context-armor context) t) |
| 959 | (setf (epg-context-textmode context) t) | 965 | (setf (epg-context-textmode context) t) |
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el index 21491499eb8..ef8aa6ac019 100644 --- a/lisp/gnus/mml.el +++ b/lisp/gnus/mml.el | |||
| @@ -295,6 +295,17 @@ part. This is for the internal use, you should never modify the value.") | |||
| 295 | (t | 295 | (t |
| 296 | (mm-find-mime-charset-region point (point) | 296 | (mm-find-mime-charset-region point (point) |
| 297 | mm-hack-charsets)))) | 297 | mm-hack-charsets)))) |
| 298 | ;; We have a part that already has a transfer encoding. Undo | ||
| 299 | ;; that so that we don't double-encode later. | ||
| 300 | (when (and raw | ||
| 301 | (cdr (assq 'data-encoding tag))) | ||
| 302 | (with-temp-buffer | ||
| 303 | (set-buffer-multibyte nil) | ||
| 304 | (insert contents) | ||
| 305 | (mm-decode-content-transfer-encoding | ||
| 306 | (intern (cdr (assq 'data-encoding tag))) | ||
| 307 | (cdr (assq 'type tag))) | ||
| 308 | (setq contents (buffer-string)))) | ||
| 298 | (when (and (not raw) (memq nil charsets)) | 309 | (when (and (not raw) (memq nil charsets)) |
| 299 | (if (or (memq 'unknown-encoding mml-confirmation-set) | 310 | (if (or (memq 'unknown-encoding mml-confirmation-set) |
| 300 | (message-options-get 'unknown-encoding) | 311 | (message-options-get 'unknown-encoding) |
| @@ -313,8 +324,8 @@ Message contains characters with unknown encoding. Really send? ") | |||
| 313 | (eq 'mml (car tag)) | 324 | (eq 'mml (car tag)) |
| 314 | (< (length charsets) 2)) | 325 | (< (length charsets) 2)) |
| 315 | (if (or (not no-markup-p) | 326 | (if (or (not no-markup-p) |
| 327 | ;; Don't create blank parts. | ||
| 316 | (string-match "[^ \t\r\n]" contents)) | 328 | (string-match "[^ \t\r\n]" contents)) |
| 317 | ;; Don't create blank parts. | ||
| 318 | (push (nconc tag (list (cons 'contents contents))) | 329 | (push (nconc tag (list (cons 'contents contents))) |
| 319 | struct)) | 330 | struct)) |
| 320 | (let ((nstruct (mml-parse-singlepart-with-multiple-charsets | 331 | (let ((nstruct (mml-parse-singlepart-with-multiple-charsets |
diff --git a/lisp/gnus/smime.el b/lisp/gnus/smime.el index fe6daf6b037..5500148e518 100644 --- a/lisp/gnus/smime.el +++ b/lisp/gnus/smime.el | |||
| @@ -185,6 +185,9 @@ and the files themselves should be in PEM format." | |||
| 185 | :version "22.1" | 185 | :version "22.1" |
| 186 | :type '(choice (const :tag "Triple DES" "-des3") | 186 | :type '(choice (const :tag "Triple DES" "-des3") |
| 187 | (const :tag "DES" "-des") | 187 | (const :tag "DES" "-des") |
| 188 | (const :tag "AES 256 bits" "-aes256") | ||
| 189 | (const :tag "AES 192 bits" "-aes192") | ||
| 190 | (const :tag "AES 128 bits" "-aes128") | ||
| 188 | (const :tag "RC2 40 bits" "-rc2-40") | 191 | (const :tag "RC2 40 bits" "-rc2-40") |
| 189 | (const :tag "RC2 64 bits" "-rc2-64") | 192 | (const :tag "RC2 64 bits" "-rc2-64") |
| 190 | (const :tag "RC2 128 bits" "-rc2-128")) | 193 | (const :tag "RC2 128 bits" "-rc2-128")) |
diff --git a/lisp/help-fns.el b/lisp/help-fns.el index 082a44d9bf5..d40b9286f8e 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el | |||
| @@ -1778,6 +1778,50 @@ documentation for the major and minor modes of that buffer." | |||
| 1778 | ;; For the sake of IELM and maybe others | 1778 | ;; For the sake of IELM and maybe others |
| 1779 | nil) | 1779 | nil) |
| 1780 | 1780 | ||
| 1781 | ;; Widgets. | ||
| 1782 | |||
| 1783 | (defvar describe-widget-functions | ||
| 1784 | '(button-describe widget-describe) | ||
| 1785 | "A list of functions for `describe-widget' to call. | ||
| 1786 | Each function should take one argument, a buffer position, and return | ||
| 1787 | non-nil if it described a widget at that position.") | ||
| 1788 | |||
| 1789 | ;;;###autoload | ||
| 1790 | (defun describe-widget (&optional pos) | ||
| 1791 | "Display a buffer with information about a widget. | ||
| 1792 | You can use this command to describe buttons (e.g., the links in a *Help* | ||
| 1793 | buffer), editable fields of the customization buffers, etc. | ||
| 1794 | |||
| 1795 | Interactively, click on a widget to describe it, or hit RET to describe the | ||
| 1796 | widget at point. | ||
| 1797 | |||
| 1798 | When called from Lisp, POS may be a buffer position or a mouse position list. | ||
| 1799 | |||
| 1800 | Calls each function of the list `describe-widget-functions' in turn, until | ||
| 1801 | one of them returns non-nil." | ||
| 1802 | (interactive | ||
| 1803 | (list | ||
| 1804 | (let ((key | ||
| 1805 | (read-key | ||
| 1806 | "Click on a widget, or hit RET to describe the widget at point"))) | ||
| 1807 | (cond ((eq key ?\C-m) (point)) | ||
| 1808 | ((and (mouse-event-p key) | ||
| 1809 | (eq (event-basic-type key) 'mouse-1) | ||
| 1810 | (equal (event-modifiers key) '(click))) | ||
| 1811 | (event-end key)) | ||
| 1812 | ((eq key ?\C-g) (signal 'quit nil)) | ||
| 1813 | (t (user-error "You didn't specify a widget")))))) | ||
| 1814 | (let (buf) | ||
| 1815 | ;; Allow describing a widget in a different window. | ||
| 1816 | (when (posnp pos) | ||
| 1817 | (setq buf (window-buffer (posn-window pos)) | ||
| 1818 | pos (posn-point pos))) | ||
| 1819 | (with-current-buffer (or buf (current-buffer)) | ||
| 1820 | (unless (cl-some (lambda (fun) (when (fboundp fun) (funcall fun pos))) | ||
| 1821 | describe-widget-functions) | ||
| 1822 | (message "No widget found at that position"))))) | ||
| 1823 | |||
| 1824 | |||
| 1781 | ;;; Replacements for old lib-src/ programs. Don't seem especially useful. | 1825 | ;;; Replacements for old lib-src/ programs. Don't seem especially useful. |
| 1782 | 1826 | ||
| 1783 | ;; Replaces lib-src/digest-doc.c. | 1827 | ;; Replaces lib-src/digest-doc.c. |
diff --git a/lisp/hi-lock.el b/lisp/hi-lock.el index a18310322ad..33ca40f8dec 100644 --- a/lisp/hi-lock.el +++ b/lisp/hi-lock.el | |||
| @@ -812,7 +812,9 @@ SPACES-REGEXP is a regexp to substitute spaces in font-lock search." | |||
| 812 | (setq hi-lock-interactive-patterns | 812 | (setq hi-lock-interactive-patterns |
| 813 | (cdr hi-lock-interactive-patterns) | 813 | (cdr hi-lock-interactive-patterns) |
| 814 | hi-lock-interactive-lighters | 814 | hi-lock-interactive-lighters |
| 815 | (cdr hi-lock-interactive-lighters))))))))) | 815 | (cdr hi-lock-interactive-lighters)))) |
| 816 | (when (or (> search-start (point-min)) (< search-end (point-max))) | ||
| 817 | (message "Hi-lock added only in range %d-%d" search-start search-end))))))) | ||
| 816 | 818 | ||
| 817 | (defun hi-lock-set-file-patterns (patterns) | 819 | (defun hi-lock-set-file-patterns (patterns) |
| 818 | "Replace file patterns list with PATTERNS and refontify." | 820 | "Replace file patterns list with PATTERNS and refontify." |
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el index bfb9787a96d..c9ca1f87424 100644 --- a/lisp/ibuf-ext.el +++ b/lisp/ibuf-ext.el | |||
| @@ -504,7 +504,7 @@ format. See `ibuffer-update-saved-filters-format' and | |||
| 504 | (ibuffer-forward-line 0)) | 504 | (ibuffer-forward-line 0)) |
| 505 | 505 | ||
| 506 | (defun ibuffer--maybe-erase-shell-cmd-output () | 506 | (defun ibuffer--maybe-erase-shell-cmd-output () |
| 507 | (let ((buf (get-buffer "*Shell Command Output*"))) | 507 | (let ((buf (get-buffer shell-command-buffer-name))) |
| 508 | (when (and (buffer-live-p buf) | 508 | (when (and (buffer-live-p buf) |
| 509 | (not shell-command-dont-erase-buffer) | 509 | (not shell-command-dont-erase-buffer) |
| 510 | (not (zerop (buffer-size buf)))) | 510 | (not (zerop (buffer-size buf)))) |
| @@ -517,7 +517,7 @@ format. See `ibuffer-update-saved-filters-format' and | |||
| 517 | :opstring "Shell command executed on" | 517 | :opstring "Shell command executed on" |
| 518 | :before (ibuffer--maybe-erase-shell-cmd-output) | 518 | :before (ibuffer--maybe-erase-shell-cmd-output) |
| 519 | :modifier-p nil) | 519 | :modifier-p nil) |
| 520 | (let ((out-buf (get-buffer-create "*Shell Command Output*"))) | 520 | (let ((out-buf (get-buffer-create shell-command-buffer-name))) |
| 521 | (with-current-buffer out-buf (goto-char (point-max))) | 521 | (with-current-buffer out-buf (goto-char (point-max))) |
| 522 | (call-shell-region (point-min) (point-max) | 522 | (call-shell-region (point-min) (point-max) |
| 523 | command nil out-buf))) | 523 | command nil out-buf))) |
| @@ -542,7 +542,7 @@ format. See `ibuffer-update-saved-filters-format' and | |||
| 542 | :modifier-p nil) | 542 | :modifier-p nil) |
| 543 | (let ((file (and (not (buffer-modified-p)) | 543 | (let ((file (and (not (buffer-modified-p)) |
| 544 | buffer-file-name)) | 544 | buffer-file-name)) |
| 545 | (out-buf (get-buffer-create "*Shell Command Output*"))) | 545 | (out-buf (get-buffer-create shell-command-buffer-name))) |
| 546 | (unless (and file (file-exists-p file)) | 546 | (unless (and file (file-exists-p file)) |
| 547 | (setq file | 547 | (setq file |
| 548 | (make-temp-file | 548 | (make-temp-file |
diff --git a/lisp/image-file.el b/lisp/image-file.el index 89cd75d50dd..22366c89e6a 100644 --- a/lisp/image-file.el +++ b/lisp/image-file.el | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | ;;; Code: | 32 | ;;; Code: |
| 33 | 33 | ||
| 34 | (require 'image) | 34 | (require 'image) |
| 35 | (require 'image-converter) | ||
| 35 | 36 | ||
| 36 | 37 | ||
| 37 | ;;;###autoload | 38 | ;;;###autoload |
| @@ -80,10 +81,13 @@ the variable is set using \\[customize]." | |||
| 80 | (let ((exts-regexp | 81 | (let ((exts-regexp |
| 81 | (and image-file-name-extensions | 82 | (and image-file-name-extensions |
| 82 | (concat "\\." | 83 | (concat "\\." |
| 83 | (regexp-opt (nconc (mapcar #'upcase | 84 | (regexp-opt |
| 84 | image-file-name-extensions) | 85 | (append (mapcar #'upcase image-file-name-extensions) |
| 85 | image-file-name-extensions) | 86 | image-file-name-extensions |
| 86 | t) | 87 | (mapcar #'upcase |
| 88 | image-converter-file-name-extensions) | ||
| 89 | image-converter-file-name-extensions) | ||
| 90 | t) | ||
| 87 | "\\'")))) | 91 | "\\'")))) |
| 88 | (mapconcat | 92 | (mapconcat |
| 89 | 'identity | 93 | 'identity |
diff --git a/lisp/image-mode.el b/lisp/image-mode.el index 1bb213c2489..948e62e10d0 100644 --- a/lisp/image-mode.el +++ b/lisp/image-mode.el | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | 40 | ||
| 41 | (require 'image) | 41 | (require 'image) |
| 42 | (require 'exif) | 42 | (require 'exif) |
| 43 | (require 'dired) | ||
| 43 | (eval-when-compile (require 'cl-lib)) | 44 | (eval-when-compile (require 'cl-lib)) |
| 44 | 45 | ||
| 45 | ;;; Image mode window-info management. | 46 | ;;; Image mode window-info management. |
| @@ -614,21 +615,23 @@ Key bindings: | |||
| 614 | (if (not (image-get-display-property)) | 615 | (if (not (image-get-display-property)) |
| 615 | (progn | 616 | (progn |
| 616 | (when (condition-case err | 617 | (when (condition-case err |
| 617 | (progn | 618 | (progn |
| 618 | (image-toggle-display-image) | 619 | (image-toggle-display-image) |
| 619 | t) | 620 | t) |
| 620 | (unknown-image-type | 621 | (unknown-image-type |
| 621 | (image-mode-as-text) | 622 | (image-mode-as-text) |
| 622 | (funcall | 623 | (funcall |
| 623 | (if (called-interactively-p 'any) 'error 'message) | 624 | (if (called-interactively-p 'any) 'error 'message) |
| 624 | "Unknown image type; consider switching `image-use-external-converter' on") | 625 | (if image-use-external-converter |
| 625 | nil) | 626 | "Unknown image type" |
| 626 | (error | 627 | "Unknown image type; consider switching `image-use-external-converter' on")) |
| 627 | (image-mode-as-text) | 628 | nil) |
| 628 | (funcall | 629 | (error |
| 629 | (if (called-interactively-p 'any) 'error 'message) | 630 | (image-mode-as-text) |
| 630 | "Cannot display image: %s" (cdr err)) | 631 | (funcall |
| 631 | nil)) | 632 | (if (called-interactively-p 'any) 'error 'message) |
| 633 | "Cannot display image: %s" (cdr err)) | ||
| 634 | nil)) | ||
| 632 | ;; If attempt to display the image fails. | 635 | ;; If attempt to display the image fails. |
| 633 | (if (not (image-get-display-property)) | 636 | (if (not (image-get-display-property)) |
| 634 | (error "Invalid image")) | 637 | (error "Invalid image")) |
| @@ -816,13 +819,21 @@ was inserted." | |||
| 816 | (- (nth 2 edges) (nth 0 edges)))) | 819 | (- (nth 2 edges) (nth 0 edges)))) |
| 817 | (max-height (when edges | 820 | (max-height (when edges |
| 818 | (- (nth 3 edges) (nth 1 edges)))) | 821 | (- (nth 3 edges) (nth 1 edges)))) |
| 819 | (type (if (image--imagemagick-wanted-p filename) | ||
| 820 | 'imagemagick | ||
| 821 | (image-type file-or-data nil data-p))) | ||
| 822 | (inhibit-read-only t) | 822 | (inhibit-read-only t) |
| 823 | (buffer-undo-list t) | 823 | (buffer-undo-list t) |
| 824 | (modified (buffer-modified-p)) | 824 | (modified (buffer-modified-p)) |
| 825 | props image) | 825 | props image type) |
| 826 | |||
| 827 | ;; If the data in the current buffer isn't from an existing file, | ||
| 828 | ;; but we have a file name (this happens when visiting images from | ||
| 829 | ;; a zip file, for instance), provide a type hint based on the | ||
| 830 | ;; suffix. | ||
| 831 | (when (and data-p filename) | ||
| 832 | (setq data-p (intern (format "image/%s" | ||
| 833 | (file-name-extension filename))))) | ||
| 834 | (setq type (if (image--imagemagick-wanted-p filename) | ||
| 835 | 'imagemagick | ||
| 836 | (image-type file-or-data nil data-p))) | ||
| 826 | 837 | ||
| 827 | ;; Get the rotation data from the file, if any. | 838 | ;; Get the rotation data from the file, if any. |
| 828 | (when (zerop image-transform-rotation) ; don't reset modified value | 839 | (when (zerop image-transform-rotation) ; don't reset modified value |
| @@ -839,10 +850,13 @@ was inserted." | |||
| 839 | ;; :scale 1: If we do not set this, create-image will apply | 850 | ;; :scale 1: If we do not set this, create-image will apply |
| 840 | ;; default scaling based on font size. | 851 | ;; default scaling based on font size. |
| 841 | (setq image (if (not edges) | 852 | (setq image (if (not edges) |
| 842 | (create-image file-or-data type data-p :scale 1) | 853 | (create-image file-or-data type data-p :scale 1 |
| 854 | :format (and filename data-p)) | ||
| 843 | (create-image file-or-data type data-p :scale 1 | 855 | (create-image file-or-data type data-p :scale 1 |
| 844 | :max-width max-width | 856 | :max-width max-width |
| 845 | :max-height max-height))) | 857 | :max-height max-height |
| 858 | ;; Type hint. | ||
| 859 | :format (and filename data-p)))) | ||
| 846 | 860 | ||
| 847 | ;; Discard any stale image data before looking it up again. | 861 | ;; Discard any stale image data before looking it up again. |
| 848 | (image-flush image) | 862 | (image-flush image) |
| @@ -1072,28 +1086,87 @@ replacing the current Image mode buffer." | |||
| 1072 | (error "The buffer is not in Image mode")) | 1086 | (error "The buffer is not in Image mode")) |
| 1073 | (unless buffer-file-name | 1087 | (unless buffer-file-name |
| 1074 | (error "The current image is not associated with a file")) | 1088 | (error "The current image is not associated with a file")) |
| 1075 | (let* ((file (file-name-nondirectory buffer-file-name)) | 1089 | (let ((next (image-mode--next-file buffer-file-name n))) |
| 1076 | (images (image-mode--images-in-directory file)) | 1090 | (unless next |
| 1077 | (idx 0)) | 1091 | (user-error "No %s file in this directory" |
| 1078 | (catch 'image-visit-next-file | 1092 | (if (> n 0) |
| 1079 | (dolist (f images) | 1093 | "next" |
| 1080 | (if (string= f file) | 1094 | "prev"))) |
| 1081 | (throw 'image-visit-next-file (1+ idx))) | 1095 | (if (stringp next) |
| 1082 | (setq idx (1+ idx)))) | 1096 | (find-alternate-file next) |
| 1083 | (setq idx (mod (+ idx (or n 1)) (length images))) | 1097 | (funcall next)))) |
| 1084 | (let ((image (nth idx images)) | 1098 | |
| 1085 | (dir (file-name-directory buffer-file-name))) | 1099 | (defun image-mode--directory-buffers (file) |
| 1086 | (find-alternate-file image) | 1100 | "Return a alist of type/buffer for all \"parent\" buffers to image FILE. |
| 1087 | ;; If we have dired buffer(s) open to where this image is, then | 1101 | This is normally a list of dired buffers, but can also be archive and |
| 1088 | ;; place point on it. | 1102 | tar mode buffers." |
| 1103 | (let ((buffers nil) | ||
| 1104 | (dir (file-name-directory file))) | ||
| 1105 | (cond | ||
| 1106 | ((and (boundp 'tar-superior-buffer) | ||
| 1107 | tar-superior-buffer) | ||
| 1108 | (when (buffer-live-p tar-superior-buffer) | ||
| 1109 | (push (cons 'tar tar-superior-buffer) buffers))) | ||
| 1110 | ((and (boundp 'archive-superior-buffer) | ||
| 1111 | archive-superior-buffer) | ||
| 1112 | (when (buffer-live-p archive-superior-buffer) | ||
| 1113 | (push (cons 'archive archive-superior-buffer) buffers))) | ||
| 1114 | (t | ||
| 1115 | ;; Find a dired buffer. | ||
| 1089 | (dolist (buffer (buffer-list)) | 1116 | (dolist (buffer (buffer-list)) |
| 1090 | (with-current-buffer buffer | 1117 | (with-current-buffer buffer |
| 1091 | (when (and (derived-mode-p 'dired-mode) | 1118 | (when (and (derived-mode-p 'dired-mode) |
| 1092 | (equal (file-truename dir) | 1119 | (equal (file-truename dir) |
| 1093 | (file-truename default-directory))) | 1120 | (file-truename default-directory))) |
| 1094 | (save-window-excursion | 1121 | (push (cons 'dired (current-buffer)) buffers)))) |
| 1095 | (switch-to-buffer (current-buffer) t t) | 1122 | ;; If we can't find any buffers to navigate in, we open a dired |
| 1096 | (dired-goto-file (expand-file-name image dir))))))))) | 1123 | ;; buffer. |
| 1124 | (unless buffers | ||
| 1125 | (push (cons 'dired (find-file-noselect dir)) buffers) | ||
| 1126 | (message "Opened a dired buffer on %s" dir)))) | ||
| 1127 | buffers)) | ||
| 1128 | |||
| 1129 | (declare-function archive-next-file-displayer "arc-mode") | ||
| 1130 | (declare-function tar-next-file-displayer "tar-mode") | ||
| 1131 | |||
| 1132 | (defun image-mode--next-file (file n) | ||
| 1133 | "Go to the next image file in the parent buffer of FILE. | ||
| 1134 | This is typically a dired buffer, but may also be a tar/archive buffer. | ||
| 1135 | Return the next image file from that buffer. | ||
| 1136 | If N is negative, go to the previous file." | ||
| 1137 | (let ((regexp (image-file-name-regexp)) | ||
| 1138 | (buffers (image-mode--directory-buffers file)) | ||
| 1139 | next) | ||
| 1140 | (dolist (buffer buffers) | ||
| 1141 | ;; We do this traversal for all the dired buffers open on this | ||
| 1142 | ;; directory. There probably is just one, but we want to move | ||
| 1143 | ;; point in all of them. | ||
| 1144 | (save-window-excursion | ||
| 1145 | (switch-to-buffer (cdr buffer) t t) | ||
| 1146 | (cl-case (car buffer) | ||
| 1147 | ('dired | ||
| 1148 | (dired-goto-file file) | ||
| 1149 | (let (found) | ||
| 1150 | (while (and (not found) | ||
| 1151 | ;; Stop if we reach the end/start of the buffer. | ||
| 1152 | (if (> n 0) | ||
| 1153 | (not (eobp)) | ||
| 1154 | (not (bobp)))) | ||
| 1155 | (dired-next-line n) | ||
| 1156 | (let ((candidate (dired-get-filename nil t))) | ||
| 1157 | (when (and candidate | ||
| 1158 | (string-match-p regexp candidate)) | ||
| 1159 | (setq found candidate)))) | ||
| 1160 | (if found | ||
| 1161 | (setq next found) | ||
| 1162 | ;; If we didn't find a next/prev file, then restore | ||
| 1163 | ;; point. | ||
| 1164 | (dired-goto-file file)))) | ||
| 1165 | ('archive | ||
| 1166 | (setq next (archive-next-file-displayer file regexp n))) | ||
| 1167 | ('tar | ||
| 1168 | (setq next (tar-next-file-displayer file regexp n)))))) | ||
| 1169 | next)) | ||
| 1097 | 1170 | ||
| 1098 | (defun image-previous-file (&optional n) | 1171 | (defun image-previous-file (&optional n) |
| 1099 | "Visit the preceding image in the same directory as the current file. | 1172 | "Visit the preceding image in the same directory as the current file. |
diff --git a/lisp/image/image-converter.el b/lisp/image/image-converter.el index b694052f5b9..ee1dc845fb5 100644 --- a/lisp/image/image-converter.el +++ b/lisp/image/image-converter.el | |||
| @@ -42,6 +42,9 @@ installed on the system." | |||
| 42 | (defvar image-converter-regexp nil | 42 | (defvar image-converter-regexp nil |
| 43 | "A regexp that matches the file name suffixes that can be converted.") | 43 | "A regexp that matches the file name suffixes that can be converted.") |
| 44 | 44 | ||
| 45 | (defvar image-converter-file-name-extensions nil | ||
| 46 | "A list of file name suffixes that can be converted.") | ||
| 47 | |||
| 45 | (defvar image-converter--converters | 48 | (defvar image-converter--converters |
| 46 | '((graphicsmagick :command ("gm" "convert") :probe ("-list" "format")) | 49 | '((graphicsmagick :command ("gm" "convert") :probe ("-list" "format")) |
| 47 | (ffmpeg :command "ffmpeg" :probe "-decoders") | 50 | (ffmpeg :command "ffmpeg" :probe "-decoders") |
| @@ -58,9 +61,11 @@ is a string, it should be a MIME format string like | |||
| 58 | (unless image-converter | 61 | (unless image-converter |
| 59 | (image-converter--find-converter)) | 62 | (image-converter--find-converter)) |
| 60 | ;; When image-converter was customized | 63 | ;; When image-converter was customized |
| 61 | (if (and image-converter (not image-converter-regexp)) | 64 | (when (and image-converter (not image-converter-regexp)) |
| 62 | (when-let ((formats (image-converter--probe image-converter))) | 65 | (when-let ((formats (image-converter--probe image-converter))) |
| 63 | (setq image-converter-regexp (concat "\\." (regexp-opt formats) "\\'")))) | 66 | (setq image-converter-regexp |
| 67 | (concat "\\." (regexp-opt formats) "\\'")) | ||
| 68 | (setq image-converter-file-name-extensions formats))) | ||
| 64 | (and image-converter | 69 | (and image-converter |
| 65 | (or (and (not data-p) | 70 | (or (and (not data-p) |
| 66 | (string-match image-converter-regexp source)) | 71 | (string-match image-converter-regexp source)) |
| @@ -183,7 +188,8 @@ data is returned as a string." | |||
| 183 | (dolist (elem image-converter--converters) | 188 | (dolist (elem image-converter--converters) |
| 184 | (when-let ((formats (image-converter--probe (car elem)))) | 189 | (when-let ((formats (image-converter--probe (car elem)))) |
| 185 | (setq image-converter (car elem) | 190 | (setq image-converter (car elem) |
| 186 | image-converter-regexp (concat "\\." (regexp-opt formats) "\\'")) | 191 | image-converter-regexp (concat "\\." (regexp-opt formats) "\\'") |
| 192 | image-converter-file-name-extensions formats) | ||
| 187 | (throw 'done image-converter))))) | 193 | (throw 'done image-converter))))) |
| 188 | 194 | ||
| 189 | (cl-defmethod image-converter--convert ((type (eql graphicsmagick)) source | 195 | (cl-defmethod image-converter--convert ((type (eql graphicsmagick)) source |
diff --git a/lisp/international/ja-dic-cnv.el b/lisp/international/ja-dic-cnv.el index 45e13462656..f5e70ce7021 100644 --- a/lisp/international/ja-dic-cnv.el +++ b/lisp/international/ja-dic-cnv.el | |||
| @@ -48,7 +48,7 @@ | |||
| 48 | (defvar ja-dic-filename "ja-dic.el") | 48 | (defvar ja-dic-filename "ja-dic.el") |
| 49 | 49 | ||
| 50 | (defun skkdic-convert-okuri-ari (skkbuf buf) | 50 | (defun skkdic-convert-okuri-ari (skkbuf buf) |
| 51 | (byte-compile-info-message "Processing OKURI-ARI entries") | 51 | (byte-compile-info "Processing OKURI-ARI entries" t) |
| 52 | (goto-char (point-min)) | 52 | (goto-char (point-min)) |
| 53 | (with-current-buffer buf | 53 | (with-current-buffer buf |
| 54 | (insert ";; Setting okuri-ari entries.\n" | 54 | (insert ";; Setting okuri-ari entries.\n" |
| @@ -97,7 +97,7 @@ | |||
| 97 | ("ゆき" "行"))) | 97 | ("ゆき" "行"))) |
| 98 | 98 | ||
| 99 | (defun skkdic-convert-postfix (skkbuf buf) | 99 | (defun skkdic-convert-postfix (skkbuf buf) |
| 100 | (byte-compile-info-message "Processing POSTFIX entries") | 100 | (byte-compile-info "Processing POSTFIX entries" t) |
| 101 | (goto-char (point-min)) | 101 | (goto-char (point-min)) |
| 102 | (with-current-buffer buf | 102 | (with-current-buffer buf |
| 103 | (insert ";; Setting postfix entries.\n" | 103 | (insert ";; Setting postfix entries.\n" |
| @@ -151,7 +151,7 @@ | |||
| 151 | (defconst skkdic-prefix-list '(skkdic-prefix-list)) | 151 | (defconst skkdic-prefix-list '(skkdic-prefix-list)) |
| 152 | 152 | ||
| 153 | (defun skkdic-convert-prefix (skkbuf buf) | 153 | (defun skkdic-convert-prefix (skkbuf buf) |
| 154 | (byte-compile-info-message "Processing PREFIX entries") | 154 | (byte-compile-info "Processing PREFIX entries" t) |
| 155 | (goto-char (point-min)) | 155 | (goto-char (point-min)) |
| 156 | (with-current-buffer buf | 156 | (with-current-buffer buf |
| 157 | (insert ";; Setting prefix entries.\n" | 157 | (insert ";; Setting prefix entries.\n" |
| @@ -273,7 +273,7 @@ | |||
| 273 | (defun skkdic-collect-okuri-nasi () | 273 | (defun skkdic-collect-okuri-nasi () |
| 274 | (save-excursion | 274 | (save-excursion |
| 275 | (let ((progress (make-progress-reporter | 275 | (let ((progress (make-progress-reporter |
| 276 | (byte-compile-info-message "Collecting OKURI-NASI entries") | 276 | (byte-compile-info "Collecting OKURI-NASI entries" t) |
| 277 | (point) (point-max) | 277 | (point) (point-max) |
| 278 | nil 10))) | 278 | nil 10))) |
| 279 | (while (re-search-forward "^\\(\\cH+\\) \\(/\\cj.*\\)/$" | 279 | (while (re-search-forward "^\\(\\cH+\\) \\(/\\cj.*\\)/$" |
| @@ -301,7 +301,7 @@ | |||
| 301 | "(skkdic-set-okuri-nasi\n") | 301 | "(skkdic-set-okuri-nasi\n") |
| 302 | (let ((l (nreverse skkdic-okuri-nasi-entries)) | 302 | (let ((l (nreverse skkdic-okuri-nasi-entries)) |
| 303 | (progress (make-progress-reporter | 303 | (progress (make-progress-reporter |
| 304 | (byte-compile-info-message "Processing OKURI-NASI entries") | 304 | (byte-compile-info "Processing OKURI-NASI entries" t) |
| 305 | 0 skkdic-okuri-nasi-entries-count | 305 | 0 skkdic-okuri-nasi-entries-count |
| 306 | nil 10)) | 306 | nil 10)) |
| 307 | (count 0)) | 307 | (count 0)) |
| @@ -531,8 +531,7 @@ To get complete usage, invoke: | |||
| 531 | ',(let ((l entries) | 531 | ',(let ((l entries) |
| 532 | (map '(skdic-okuri-nasi)) | 532 | (map '(skdic-okuri-nasi)) |
| 533 | (progress (make-progress-reporter | 533 | (progress (make-progress-reporter |
| 534 | (byte-compile-info-message | 534 | (byte-compile-info "Extracting OKURI-NASI entries") |
| 535 | "Extracting OKURI-NASI entries") | ||
| 536 | 0 (length entries))) | 535 | 0 (length entries))) |
| 537 | (count 0) | 536 | (count 0) |
| 538 | entry) | 537 | entry) |
diff --git a/lisp/mouse.el b/lisp/mouse.el index 640f10af4e1..d369545f18e 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el | |||
| @@ -49,7 +49,10 @@ | |||
| 49 | "If non-nil, copy to kill-ring upon mouse adjustments of the region. | 49 | "If non-nil, copy to kill-ring upon mouse adjustments of the region. |
| 50 | 50 | ||
| 51 | This affects `mouse-save-then-kill' (\\[mouse-save-then-kill]) in | 51 | This affects `mouse-save-then-kill' (\\[mouse-save-then-kill]) in |
| 52 | addition to mouse drags." | 52 | addition to mouse drags. |
| 53 | |||
| 54 | This variable applies only to mouse adjustments in Emacs, not | ||
| 55 | selecting and adjusting regions in other windows." | ||
| 53 | :type 'boolean | 56 | :type 'boolean |
| 54 | :version "24.1") | 57 | :version "24.1") |
| 55 | 58 | ||
diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index 8892e800cd6..2b8d4d0ce62 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; browse-url.el --- pass a URL to a WWW browser | 1 | ;;; browse-url.el --- pass a URL to a WWW browser -*- lexical-binding: t; -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 1995-2020 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 1995-2020 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -425,25 +425,6 @@ Passing an interactive argument to \\[browse-url], or specific browser | |||
| 425 | commands reverses the effect of this variable." | 425 | commands reverses the effect of this variable." |
| 426 | :type 'boolean) | 426 | :type 'boolean) |
| 427 | 427 | ||
| 428 | (defcustom browse-url-mosaic-program "xmosaic" | ||
| 429 | "The name by which to invoke Mosaic (or mMosaic)." | ||
| 430 | :type 'string | ||
| 431 | :version "20.3") | ||
| 432 | |||
| 433 | (make-obsolete-variable 'browse-url-mosaic-program nil "25.1") | ||
| 434 | |||
| 435 | (defcustom browse-url-mosaic-arguments nil | ||
| 436 | "A list of strings to pass to Mosaic as arguments." | ||
| 437 | :type '(repeat (string :tag "Argument"))) | ||
| 438 | |||
| 439 | (make-obsolete-variable 'browse-url-mosaic-arguments nil "25.1") | ||
| 440 | |||
| 441 | (defcustom browse-url-mosaic-pidfile "~/.mosaicpid" | ||
| 442 | "The name of the pidfile created by Mosaic." | ||
| 443 | :type 'string) | ||
| 444 | |||
| 445 | (make-obsolete-variable 'browse-url-mosaic-pidfile nil "25.1") | ||
| 446 | |||
| 447 | (defcustom browse-url-conkeror-program "conkeror" | 428 | (defcustom browse-url-conkeror-program "conkeror" |
| 448 | "The name by which to invoke Conkeror." | 429 | "The name by which to invoke Conkeror." |
| 449 | :type 'string | 430 | :type 'string |
| @@ -498,22 +479,6 @@ Used by the `browse-url-of-file' command." | |||
| 498 | "Hook run after `browse-url-of-file' has asked a browser to load a file." | 479 | "Hook run after `browse-url-of-file' has asked a browser to load a file." |
| 499 | :type 'hook) | 480 | :type 'hook) |
| 500 | 481 | ||
| 501 | (defcustom browse-url-CCI-port 3003 | ||
| 502 | "Port to access XMosaic via CCI. | ||
| 503 | This can be any number between 1024 and 65535 but must correspond to | ||
| 504 | the value set in the browser." | ||
| 505 | :type 'integer) | ||
| 506 | |||
| 507 | (make-obsolete-variable 'browse-url-CCI-port nil "25.1") | ||
| 508 | |||
| 509 | (defcustom browse-url-CCI-host "localhost" | ||
| 510 | "Host to access XMosaic via CCI. | ||
| 511 | This should be the host name of the machine running XMosaic with CCI | ||
| 512 | enabled. The port number should be set in `browse-url-CCI-port'." | ||
| 513 | :type 'string) | ||
| 514 | |||
| 515 | (make-obsolete-variable 'browse-url-CCI-host nil "25.1") | ||
| 516 | |||
| 517 | (defvar browse-url-temp-file-name nil) | 482 | (defvar browse-url-temp-file-name nil) |
| 518 | (make-variable-buffer-local 'browse-url-temp-file-name) | 483 | (make-variable-buffer-local 'browse-url-temp-file-name) |
| 519 | 484 | ||
| @@ -622,7 +587,7 @@ process), or nil (we don't know)." | |||
| 622 | kind))) | 587 | kind))) |
| 623 | 588 | ||
| 624 | (defun browse-url--mailto (url &rest args) | 589 | (defun browse-url--mailto (url &rest args) |
| 625 | "Calls `browse-url-mailto-function' with URL and ARGS." | 590 | "Call `browse-url-mailto-function' with URL and ARGS." |
| 626 | (funcall browse-url-mailto-function url args)) | 591 | (funcall browse-url-mailto-function url args)) |
| 627 | 592 | ||
| 628 | (defun browse-url--browser-kind-mailto (url) | 593 | (defun browse-url--browser-kind-mailto (url) |
| @@ -631,7 +596,7 @@ process), or nil (we don't know)." | |||
| 631 | #'browse-url--browser-kind-mailto) | 596 | #'browse-url--browser-kind-mailto) |
| 632 | 597 | ||
| 633 | (defun browse-url--man (url &rest args) | 598 | (defun browse-url--man (url &rest args) |
| 634 | "Calls `browse-url-man-function' with URL and ARGS." | 599 | "Call `browse-url-man-function' with URL and ARGS." |
| 635 | (funcall browse-url-man-function url args)) | 600 | (funcall browse-url-man-function url args)) |
| 636 | 601 | ||
| 637 | (defun browse-url--browser-kind-man (url) | 602 | (defun browse-url--browser-kind-man (url) |
| @@ -640,7 +605,7 @@ process), or nil (we don't know)." | |||
| 640 | #'browse-url--browser-kind-man) | 605 | #'browse-url--browser-kind-man) |
| 641 | 606 | ||
| 642 | (defun browse-url--browser (url &rest args) | 607 | (defun browse-url--browser (url &rest args) |
| 643 | "Calls `browse-url-browser-function' with URL and ARGS." | 608 | "Call `browse-url-browser-function' with URL and ARGS." |
| 644 | (funcall browse-url-browser-function url args)) | 609 | (funcall browse-url-browser-function url args)) |
| 645 | 610 | ||
| 646 | (defun browse-url--browser-kind-browser (url) | 611 | (defun browse-url--browser-kind-browser (url) |
| @@ -854,8 +819,8 @@ narrowed." | |||
| 854 | (browse-url-of-file file-name)))) | 819 | (browse-url-of-file file-name)))) |
| 855 | 820 | ||
| 856 | (defun browse-url-delete-temp-file (&optional temp-file-name) | 821 | (defun browse-url-delete-temp-file (&optional temp-file-name) |
| 857 | ;; Delete browse-url-temp-file-name from the file system | 822 | "Delete `browse-url-temp-file-name' from the file system. |
| 858 | ;; If optional arg TEMP-FILE-NAME is non-nil, delete it instead | 823 | If optional arg TEMP-FILE-NAME is non-nil, delete it instead." |
| 859 | (let ((file-name (or temp-file-name browse-url-temp-file-name))) | 824 | (let ((file-name (or temp-file-name browse-url-temp-file-name))) |
| 860 | (if (and file-name (file-exists-p file-name)) | 825 | (if (and file-name (file-exists-p file-name)) |
| 861 | (delete-file file-name)))) | 826 | (delete-file file-name)))) |
| @@ -1075,8 +1040,6 @@ instead of `browse-url-new-window-flag'." | |||
| 1075 | ;;; ((executable-find browse-url-galeon-program) 'browse-url-galeon) | 1040 | ;;; ((executable-find browse-url-galeon-program) 'browse-url-galeon) |
| 1076 | ((executable-find browse-url-kde-program) 'browse-url-kde) | 1041 | ((executable-find browse-url-kde-program) 'browse-url-kde) |
| 1077 | ;;; ((executable-find browse-url-netscape-program) 'browse-url-netscape) | 1042 | ;;; ((executable-find browse-url-netscape-program) 'browse-url-netscape) |
| 1078 | ;;; ((executable-find browse-url-mosaic-program) 'browse-url-mosaic) | ||
| 1079 | ;;; ((executable-find browse-url-conkeror-program) 'browse-url-conkeror) | ||
| 1080 | ((executable-find browse-url-chrome-program) 'browse-url-chrome) | 1043 | ((executable-find browse-url-chrome-program) 'browse-url-chrome) |
| 1081 | ((executable-find browse-url-xterm-program) 'browse-url-text-xterm) | 1044 | ((executable-find browse-url-xterm-program) 'browse-url-text-xterm) |
| 1082 | ((locate-library "w3") 'browse-url-w3) | 1045 | ((locate-library "w3") 'browse-url-w3) |
| @@ -1444,93 +1407,6 @@ used instead of `browse-url-new-window-flag'." | |||
| 1444 | 1407 | ||
| 1445 | (function-put 'browse-url-gnome-moz 'browse-url-browser-kind 'external) | 1408 | (function-put 'browse-url-gnome-moz 'browse-url-browser-kind 'external) |
| 1446 | 1409 | ||
| 1447 | ;; --- Mosaic --- | ||
| 1448 | |||
| 1449 | ;;;###autoload | ||
| 1450 | (defun browse-url-mosaic (url &optional new-window) | ||
| 1451 | "Ask the XMosaic WWW browser to load URL. | ||
| 1452 | |||
| 1453 | Default to the URL around or before point. The strings in variable | ||
| 1454 | `browse-url-mosaic-arguments' are also passed to Mosaic and the | ||
| 1455 | program is invoked according to the variable | ||
| 1456 | `browse-url-mosaic-program'. | ||
| 1457 | |||
| 1458 | When called interactively, if variable `browse-url-new-window-flag' is | ||
| 1459 | non-nil, load the document in a new Mosaic window, otherwise use a | ||
| 1460 | random existing one. A non-nil interactive prefix argument reverses | ||
| 1461 | the effect of `browse-url-new-window-flag'. | ||
| 1462 | |||
| 1463 | When called non-interactively, optional second argument NEW-WINDOW is | ||
| 1464 | used instead of `browse-url-new-window-flag'." | ||
| 1465 | (declare (obsolete nil "25.1")) | ||
| 1466 | (interactive (browse-url-interactive-arg "Mosaic URL: ")) | ||
| 1467 | (let ((pidfile (expand-file-name browse-url-mosaic-pidfile)) | ||
| 1468 | pid) | ||
| 1469 | (if (file-readable-p pidfile) | ||
| 1470 | (with-temp-buffer | ||
| 1471 | (insert-file-contents pidfile) | ||
| 1472 | (setq pid (read (current-buffer))))) | ||
| 1473 | (if (and (integerp pid) (zerop (signal-process pid 0))) ; Mosaic running | ||
| 1474 | (progn | ||
| 1475 | (with-temp-buffer | ||
| 1476 | (insert (if (browse-url-maybe-new-window new-window) | ||
| 1477 | "newwin\n" | ||
| 1478 | "goto\n") | ||
| 1479 | url "\n") | ||
| 1480 | (with-file-modes ?\700 | ||
| 1481 | (if (file-exists-p | ||
| 1482 | (setq pidfile (format "/tmp/Mosaic.%d" pid))) | ||
| 1483 | (delete-file pidfile)) | ||
| 1484 | ;; https://debbugs.gnu.org/17428. Use O_EXCL. | ||
| 1485 | (write-region nil nil pidfile nil 'silent nil 'excl))) | ||
| 1486 | ;; Send signal SIGUSR to Mosaic | ||
| 1487 | (message "Signaling Mosaic...") | ||
| 1488 | (signal-process pid 'SIGUSR1) | ||
| 1489 | ;; Or you could try: | ||
| 1490 | ;; (call-process "kill" nil 0 nil "-USR1" (int-to-string pid)) | ||
| 1491 | (message "Signaling Mosaic...done")) | ||
| 1492 | ;; Mosaic not running - start it | ||
| 1493 | (message "Starting %s..." browse-url-mosaic-program) | ||
| 1494 | (apply 'start-process "xmosaic" nil browse-url-mosaic-program | ||
| 1495 | (append browse-url-mosaic-arguments (list url))) | ||
| 1496 | (message "Starting %s...done" browse-url-mosaic-program)))) | ||
| 1497 | |||
| 1498 | (function-put 'browse-url-mosaic 'browse-url-browser-kind 'external) | ||
| 1499 | |||
| 1500 | ;; --- Mosaic using CCI --- | ||
| 1501 | |||
| 1502 | ;;;###autoload | ||
| 1503 | (defun browse-url-cci (url &optional new-window) | ||
| 1504 | "Ask the XMosaic WWW browser to load URL. | ||
| 1505 | Default to the URL around or before point. | ||
| 1506 | |||
| 1507 | This function only works for XMosaic version 2.5 or later. You must | ||
| 1508 | select `CCI' from XMosaic's File menu, set the CCI Port Address to the | ||
| 1509 | value of variable `browse-url-CCI-port', and enable `Accept requests'. | ||
| 1510 | |||
| 1511 | When called interactively, if variable `browse-url-new-window-flag' is | ||
| 1512 | non-nil, load the document in a new browser window, otherwise use a | ||
| 1513 | random existing one. A non-nil interactive prefix argument reverses | ||
| 1514 | the effect of `browse-url-new-window-flag'. | ||
| 1515 | |||
| 1516 | When called non-interactively, optional second argument NEW-WINDOW is | ||
| 1517 | used instead of `browse-url-new-window-flag'." | ||
| 1518 | (declare (obsolete nil "25.1")) | ||
| 1519 | (interactive (browse-url-interactive-arg "Mosaic URL: ")) | ||
| 1520 | (open-network-stream "browse-url" " *browse-url*" | ||
| 1521 | browse-url-CCI-host browse-url-CCI-port) | ||
| 1522 | ;; Todo: start browser if fails | ||
| 1523 | (process-send-string "browse-url" | ||
| 1524 | (concat "get url (" url ") output " | ||
| 1525 | (if (browse-url-maybe-new-window new-window) | ||
| 1526 | "new" | ||
| 1527 | "current") | ||
| 1528 | "\r\n")) | ||
| 1529 | (process-send-string "browse-url" "disconnect\r\n") | ||
| 1530 | (delete-process "browse-url")) | ||
| 1531 | |||
| 1532 | (function-put 'browse-url-cci 'browse-url-browser-kind 'external) | ||
| 1533 | |||
| 1534 | ;; --- Conkeror --- | 1410 | ;; --- Conkeror --- |
| 1535 | ;;;###autoload | 1411 | ;;;###autoload |
| 1536 | (defun browse-url-conkeror (url &optional new-window) | 1412 | (defun browse-url-conkeror (url &optional new-window) |
diff --git a/lisp/net/eww.el b/lisp/net/eww.el index edb2f729c8b..e7170b3e6d1 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el | |||
| @@ -277,6 +277,24 @@ This list can be customized via `eww-suggest-uris'." | |||
| 277 | (nreverse uris))) | 277 | (nreverse uris))) |
| 278 | 278 | ||
| 279 | ;;;###autoload | 279 | ;;;###autoload |
| 280 | (defun eww-browse () | ||
| 281 | "Function to be run to parse command line URLs. | ||
| 282 | This is meant to be used for MIME handlers or command line use. | ||
| 283 | |||
| 284 | Setting the handler for \"text/x-uri;\" to | ||
| 285 | \"emacs -f eww-browse %u\" will then start up Emacs and call eww | ||
| 286 | to browse the url. | ||
| 287 | |||
| 288 | This can also be used on the command line directly: | ||
| 289 | |||
| 290 | emacs -f eww-browse https://gnu.org | ||
| 291 | |||
| 292 | will start Emacs and browse the GNU web site." | ||
| 293 | (interactive) | ||
| 294 | (eww (pop command-line-args-left))) | ||
| 295 | |||
| 296 | |||
| 297 | ;;;###autoload | ||
| 280 | (defun eww (url &optional arg buffer) | 298 | (defun eww (url &optional arg buffer) |
| 281 | "Fetch URL and render the page. | 299 | "Fetch URL and render the page. |
| 282 | If the input doesn't look like an URL or a domain name, the | 300 | If the input doesn't look like an URL or a domain name, the |
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index 7e5af6910bb..88f5c2928e3 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el | |||
| @@ -96,8 +96,10 @@ It is used for TCP/IP devices." | |||
| 96 | (tramp--with-startup | 96 | (tramp--with-startup |
| 97 | (add-to-list 'tramp-methods | 97 | (add-to-list 'tramp-methods |
| 98 | `(,tramp-adb-method | 98 | `(,tramp-adb-method |
| 99 | (tramp-tmpdir "/data/local/tmp") | 99 | (tramp-login-program ,tramp-adb-program) |
| 100 | (tramp-default-port 5555))) | 100 | (tramp-login-args (("shell"))) |
| 101 | (tramp-tmpdir "/data/local/tmp") | ||
| 102 | (tramp-default-port 5555))) | ||
| 101 | 103 | ||
| 102 | (add-to-list 'tramp-default-host-alist `(,tramp-adb-method nil "")) | 104 | (add-to-list 'tramp-default-host-alist `(,tramp-adb-method nil "")) |
| 103 | 105 | ||
| @@ -885,158 +887,163 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." | |||
| 885 | ;; The complete STDERR buffer is available only when the process has | 887 | ;; The complete STDERR buffer is available only when the process has |
| 886 | ;; terminated. | 888 | ;; terminated. |
| 887 | (defun tramp-adb-handle-make-process (&rest args) | 889 | (defun tramp-adb-handle-make-process (&rest args) |
| 888 | "Like `make-process' for Tramp files." | 890 | "Like `make-process' for Tramp files. |
| 889 | (when args | 891 | If connection property \"direct-async-process\" is non-nil, an |
| 890 | (with-parsed-tramp-file-name (expand-file-name default-directory) nil | 892 | alternative implementation will be used." |
| 891 | (let ((name (plist-get args :name)) | 893 | (if (tramp-get-connection-property |
| 892 | (buffer (plist-get args :buffer)) | 894 | (tramp-dissect-file-name default-directory) "direct-async-process" nil) |
| 893 | (command (plist-get args :command)) | 895 | (apply #'tramp-handle-make-process args) |
| 894 | (coding (plist-get args :coding)) | 896 | (when args |
| 895 | (noquery (plist-get args :noquery)) | 897 | (with-parsed-tramp-file-name (expand-file-name default-directory) nil |
| 896 | (connection-type (plist-get args :connection-type)) | 898 | (let ((name (plist-get args :name)) |
| 897 | (filter (plist-get args :filter)) | 899 | (buffer (plist-get args :buffer)) |
| 898 | (sentinel (plist-get args :sentinel)) | 900 | (command (plist-get args :command)) |
| 899 | (stderr (plist-get args :stderr))) | 901 | (coding (plist-get args :coding)) |
| 900 | (unless (stringp name) | 902 | (noquery (plist-get args :noquery)) |
| 901 | (signal 'wrong-type-argument (list #'stringp name))) | 903 | (connection-type (plist-get args :connection-type)) |
| 902 | (unless (or (null buffer) (bufferp buffer) (stringp buffer)) | 904 | (filter (plist-get args :filter)) |
| 903 | (signal 'wrong-type-argument (list #'stringp buffer))) | 905 | (sentinel (plist-get args :sentinel)) |
| 904 | (unless (consp command) | 906 | (stderr (plist-get args :stderr))) |
| 905 | (signal 'wrong-type-argument (list #'consp command))) | 907 | (unless (stringp name) |
| 906 | (unless (or (null coding) | 908 | (signal 'wrong-type-argument (list #'stringp name))) |
| 907 | (and (symbolp coding) (memq coding coding-system-list)) | 909 | (unless (or (null buffer) (bufferp buffer) (stringp buffer)) |
| 908 | (and (consp coding) | 910 | (signal 'wrong-type-argument (list #'stringp buffer))) |
| 909 | (memq (car coding) coding-system-list) | 911 | (unless (consp command) |
| 910 | (memq (cdr coding) coding-system-list))) | 912 | (signal 'wrong-type-argument (list #'consp command))) |
| 911 | (signal 'wrong-type-argument (list #'symbolp coding))) | 913 | (unless (or (null coding) |
| 912 | (unless (or (null connection-type) (memq connection-type '(pipe pty))) | 914 | (and (symbolp coding) (memq coding coding-system-list)) |
| 913 | (signal 'wrong-type-argument (list #'symbolp connection-type))) | 915 | (and (consp coding) |
| 914 | (unless (or (null filter) (functionp filter)) | 916 | (memq (car coding) coding-system-list) |
| 915 | (signal 'wrong-type-argument (list #'functionp filter))) | 917 | (memq (cdr coding) coding-system-list))) |
| 916 | (unless (or (null sentinel) (functionp sentinel)) | 918 | (signal 'wrong-type-argument (list #'symbolp coding))) |
| 917 | (signal 'wrong-type-argument (list #'functionp sentinel))) | 919 | (unless (or (null connection-type) (memq connection-type '(pipe pty))) |
| 918 | (unless (or (null stderr) (bufferp stderr) (stringp stderr)) | 920 | (signal 'wrong-type-argument (list #'symbolp connection-type))) |
| 919 | (signal 'wrong-type-argument (list #'stringp stderr))) | 921 | (unless (or (null filter) (functionp filter)) |
| 920 | (when (and (stringp stderr) (tramp-tramp-file-p stderr) | 922 | (signal 'wrong-type-argument (list #'functionp filter))) |
| 921 | (not (tramp-equal-remote default-directory stderr))) | 923 | (unless (or (null sentinel) (functionp sentinel)) |
| 922 | (signal 'file-error (list "Wrong stderr" stderr))) | 924 | (signal 'wrong-type-argument (list #'functionp sentinel))) |
| 923 | 925 | (unless (or (null stderr) (bufferp stderr) (stringp stderr)) | |
| 924 | (let* ((buffer | 926 | (signal 'wrong-type-argument (list #'stringp stderr))) |
| 925 | (if buffer | 927 | (when (and (stringp stderr) (tramp-tramp-file-p stderr) |
| 926 | (get-buffer-create buffer) | 928 | (not (tramp-equal-remote default-directory stderr))) |
| 927 | ;; BUFFER can be nil. We use a temporary buffer. | 929 | (signal 'file-error (list "Wrong stderr" stderr))) |
| 928 | (generate-new-buffer tramp-temp-buffer-name))) | 930 | |
| 929 | ;; STDERR can also be a file name. | 931 | (let* ((buffer |
| 930 | (tmpstderr | 932 | (if buffer |
| 931 | (and stderr | 933 | (get-buffer-create buffer) |
| 932 | (if (and (stringp stderr) (tramp-tramp-file-p stderr)) | 934 | ;; BUFFER can be nil. We use a temporary buffer. |
| 933 | (tramp-unquote-file-local-name stderr) | 935 | (generate-new-buffer tramp-temp-buffer-name))) |
| 934 | (tramp-make-tramp-temp-file v)))) | 936 | ;; STDERR can also be a file name. |
| 935 | (remote-tmpstderr | 937 | (tmpstderr |
| 936 | (and tmpstderr (tramp-make-tramp-file-name v tmpstderr))) | 938 | (and stderr |
| 937 | (program (car command)) | 939 | (if (and (stringp stderr) (tramp-tramp-file-p stderr)) |
| 938 | (args (cdr command)) | 940 | (tramp-unquote-file-local-name stderr) |
| 939 | (command | 941 | (tramp-make-tramp-temp-file v)))) |
| 940 | (format "cd %s && exec %s %s" | 942 | (remote-tmpstderr |
| 941 | (tramp-shell-quote-argument localname) | 943 | (and tmpstderr (tramp-make-tramp-file-name v tmpstderr))) |
| 942 | (if tmpstderr (format "2>'%s'" tmpstderr) "") | 944 | (program (car command)) |
| 943 | (mapconcat #'tramp-shell-quote-argument | 945 | (args (cdr command)) |
| 944 | (cons program args) " "))) | 946 | (command |
| 945 | (tramp-process-connection-type | 947 | (format "cd %s && exec %s %s" |
| 946 | (or (null program) tramp-process-connection-type)) | 948 | (tramp-shell-quote-argument localname) |
| 947 | (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer))) | 949 | (if tmpstderr (format "2>'%s'" tmpstderr) "") |
| 948 | (name1 name) | 950 | (mapconcat #'tramp-shell-quote-argument |
| 949 | (i 0)) | 951 | (cons program args) " "))) |
| 950 | 952 | (tramp-process-connection-type | |
| 951 | (while (get-process name1) | 953 | (or (null program) tramp-process-connection-type)) |
| 952 | ;; NAME must be unique as process name. | 954 | (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer))) |
| 953 | (setq i (1+ i) | 955 | (name1 name) |
| 954 | name1 (format "%s<%d>" name i))) | 956 | (i 0)) |
| 955 | (setq name name1) | 957 | |
| 956 | ;; Set the new process properties. | 958 | (while (get-process name1) |
| 957 | (tramp-set-connection-property v "process-name" name) | 959 | ;; NAME must be unique as process name. |
| 958 | (tramp-set-connection-property v "process-buffer" buffer) | 960 | (setq i (1+ i) |
| 959 | 961 | name1 (format "%s<%d>" name i))) | |
| 960 | (with-current-buffer (tramp-get-connection-buffer v) | 962 | (setq name name1) |
| 961 | (unwind-protect | 963 | ;; Set the new process properties. |
| 962 | ;; We catch this event. Otherwise, `make-process' | 964 | (tramp-set-connection-property v "process-name" name) |
| 963 | ;; could be called on the local host. | 965 | (tramp-set-connection-property v "process-buffer" buffer) |
| 964 | (save-excursion | 966 | |
| 965 | (save-restriction | 967 | (with-current-buffer (tramp-get-connection-buffer v) |
| 966 | ;; Activate narrowing in order to save BUFFER | 968 | (unwind-protect |
| 967 | ;; contents. Clear also the modification time; | 969 | ;; We catch this event. Otherwise, `make-process' |
| 968 | ;; otherwise we might be interrupted by | 970 | ;; could be called on the local host. |
| 969 | ;; `verify-visited-file-modtime'. | 971 | (save-excursion |
| 970 | (let ((buffer-undo-list t) | 972 | (save-restriction |
| 971 | (inhibit-read-only t)) | 973 | ;; Activate narrowing in order to save BUFFER |
| 972 | (clear-visited-file-modtime) | 974 | ;; contents. Clear also the modification time; |
| 973 | (narrow-to-region (point-max) (point-max)) | 975 | ;; otherwise we might be interrupted by |
| 974 | ;; We call `tramp-adb-maybe-open-connection', in | 976 | ;; `verify-visited-file-modtime'. |
| 975 | ;; order to cleanup the prompt afterwards. | 977 | (let ((buffer-undo-list t) |
| 976 | (tramp-adb-maybe-open-connection v) | 978 | (inhibit-read-only t)) |
| 977 | (delete-region (point-min) (point-max)) | 979 | (clear-visited-file-modtime) |
| 978 | ;; Send the command. | 980 | (narrow-to-region (point-max) (point-max)) |
| 979 | (let* ((p (tramp-get-connection-process v))) | 981 | ;; We call `tramp-adb-maybe-open-connection', |
| 980 | (tramp-adb-send-command v command nil t) ; nooutput | 982 | ;; in order to cleanup the prompt afterwards. |
| 981 | ;; Set sentinel and filter. | 983 | (tramp-adb-maybe-open-connection v) |
| 982 | (when sentinel | 984 | (delete-region (point-min) (point-max)) |
| 983 | (set-process-sentinel p sentinel)) | 985 | ;; Send the command. |
| 984 | (when filter | 986 | (let* ((p (tramp-get-connection-process v))) |
| 985 | (set-process-filter p filter)) | 987 | (tramp-adb-send-command v command nil t) ; nooutput |
| 986 | ;; Set query flag and process marker for this | 988 | ;; Set sentinel and filter. |
| 987 | ;; process. We ignore errors, because the | 989 | (when sentinel |
| 988 | ;; process could have finished already. | 990 | (set-process-sentinel p sentinel)) |
| 989 | (ignore-errors | 991 | (when filter |
| 990 | (set-process-query-on-exit-flag p (null noquery)) | 992 | (set-process-filter p filter)) |
| 991 | (set-marker (process-mark p) (point))) | 993 | ;; Set query flag and process marker for |
| 992 | ;; We must flush them here already; otherwise | 994 | ;; this process. We ignore errors, because |
| 993 | ;; `rename-file', `delete-file' or | 995 | ;; the process could have finished already. |
| 994 | ;; `insert-file-contents' will fail. | 996 | (ignore-errors |
| 995 | (tramp-flush-connection-property v "process-name") | 997 | (set-process-query-on-exit-flag p (null noquery)) |
| 996 | (tramp-flush-connection-property v "process-buffer") | 998 | (set-marker (process-mark p) (point))) |
| 997 | ;; Copy tmpstderr file. | 999 | ;; We must flush them here already; |
| 998 | (when (and (stringp stderr) | 1000 | ;; otherwise `rename-file', `delete-file' or |
| 999 | (not (tramp-tramp-file-p stderr))) | 1001 | ;; `insert-file-contents' will fail. |
| 1000 | (add-function | 1002 | (tramp-flush-connection-property v "process-name") |
| 1001 | :after (process-sentinel p) | 1003 | (tramp-flush-connection-property v "process-buffer") |
| 1002 | (lambda (_proc _msg) | 1004 | ;; Copy tmpstderr file. |
| 1003 | (rename-file remote-tmpstderr stderr)))) | 1005 | (when (and (stringp stderr) |
| 1004 | ;; Read initial output. Remove the first line, | 1006 | (not (tramp-tramp-file-p stderr))) |
| 1005 | ;; which is the command echo. | 1007 | (add-function |
| 1006 | (while | 1008 | :after (process-sentinel p) |
| 1007 | (progn | 1009 | (lambda (_proc _msg) |
| 1008 | (goto-char (point-min)) | 1010 | (rename-file remote-tmpstderr stderr)))) |
| 1009 | (not (re-search-forward "[\n]" nil t))) | 1011 | ;; Read initial output. Remove the first |
| 1010 | (tramp-accept-process-output p 0)) | 1012 | ;; line, which is the command echo. |
| 1011 | (delete-region (point-min) (point)) | 1013 | (while |
| 1012 | ;; Provide error buffer. This shows only | 1014 | (progn |
| 1013 | ;; initial error messages; messages arriving | 1015 | (goto-char (point-min)) |
| 1014 | ;; later on will be inserted when the process | 1016 | (not (re-search-forward "[\n]" nil t))) |
| 1015 | ;; is deleted. The temporary file will exist | 1017 | (tramp-accept-process-output p 0)) |
| 1016 | ;; until the process is deleted. | 1018 | (delete-region (point-min) (point)) |
| 1017 | (when (bufferp stderr) | 1019 | ;; Provide error buffer. This shows only |
| 1018 | (with-current-buffer stderr | 1020 | ;; initial error messages; messages arriving |
| 1019 | (insert-file-contents-literally | 1021 | ;; later on will be inserted when the |
| 1020 | remote-tmpstderr 'visit)) | 1022 | ;; process is deleted. The temporary file |
| 1021 | ;; Delete tmpstderr file. | 1023 | ;; will exist until the process is deleted. |
| 1022 | (add-function | 1024 | (when (bufferp stderr) |
| 1023 | :after (process-sentinel p) | 1025 | (with-current-buffer stderr |
| 1024 | (lambda (_proc _msg) | 1026 | (insert-file-contents-literally |
| 1025 | (with-current-buffer stderr | 1027 | remote-tmpstderr 'visit)) |
| 1026 | (insert-file-contents-literally | 1028 | ;; Delete tmpstderr file. |
| 1027 | remote-tmpstderr 'visit nil nil 'replace)) | 1029 | (add-function |
| 1028 | (delete-file remote-tmpstderr)))) | 1030 | :after (process-sentinel p) |
| 1029 | ;; Return process. | 1031 | (lambda (_proc _msg) |
| 1030 | p)))) | 1032 | (with-current-buffer stderr |
| 1031 | 1033 | (insert-file-contents-literally | |
| 1032 | ;; Save exit. | 1034 | remote-tmpstderr 'visit nil nil 'replace)) |
| 1033 | (if (string-match-p tramp-temp-buffer-name (buffer-name)) | 1035 | (delete-file remote-tmpstderr)))) |
| 1034 | (ignore-errors | 1036 | ;; Return process. |
| 1035 | (set-process-buffer (tramp-get-connection-process v) nil) | 1037 | p)))) |
| 1036 | (kill-buffer (current-buffer))) | 1038 | |
| 1037 | (set-buffer-modified-p bmp)) | 1039 | ;; Save exit. |
| 1038 | (tramp-flush-connection-property v "process-name") | 1040 | (if (string-match-p tramp-temp-buffer-name (buffer-name)) |
| 1039 | (tramp-flush-connection-property v "process-buffer")))))))) | 1041 | (ignore-errors |
| 1042 | (set-process-buffer (tramp-get-connection-process v) nil) | ||
| 1043 | (kill-buffer (current-buffer))) | ||
| 1044 | (set-buffer-modified-p bmp)) | ||
| 1045 | (tramp-flush-connection-property v "process-name") | ||
| 1046 | (tramp-flush-connection-property v "process-buffer"))))))))) | ||
| 1040 | 1047 | ||
| 1041 | (defun tramp-adb-handle-exec-path () | 1048 | (defun tramp-adb-handle-exec-path () |
| 1042 | "Like `exec-path' for Tramp files." | 1049 | "Like `exec-path' for Tramp files." |
| @@ -1253,6 +1260,14 @@ connection if a previous connection has died for some reason." | |||
| 1253 | (tramp-adb-send-command | 1260 | (tramp-adb-send-command |
| 1254 | vec (format "PS1=\"///\"\"%s\"\"#$\"" prompt)) | 1261 | vec (format "PS1=\"///\"\"%s\"\"#$\"" prompt)) |
| 1255 | 1262 | ||
| 1263 | ;; Disable line editing. | ||
| 1264 | (tramp-adb-send-command | ||
| 1265 | vec "set +o vi +o vi-esccomplete +o vi-tabcomplete +o emacs") | ||
| 1266 | |||
| 1267 | ;; Dump option settings in the traces. | ||
| 1268 | (when (>= tramp-verbose 9) | ||
| 1269 | (tramp-adb-send-command vec "set -o")) | ||
| 1270 | |||
| 1256 | ;; Check whether the properties have been changed. If | 1271 | ;; Check whether the properties have been changed. If |
| 1257 | ;; yes, this is a strong indication that we must expire all | 1272 | ;; yes, this is a strong indication that we must expire all |
| 1258 | ;; connection properties. We start again. | 1273 | ;; connection properties. We start again. |
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index f9f0cbcc023..3e2eb023a33 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el | |||
| @@ -2787,228 +2787,233 @@ the result will be a local, non-Tramp, file name." | |||
| 2787 | ;; terminated. | 2787 | ;; terminated. |
| 2788 | (defun tramp-sh-handle-make-process (&rest args) | 2788 | (defun tramp-sh-handle-make-process (&rest args) |
| 2789 | "Like `make-process' for Tramp files. | 2789 | "Like `make-process' for Tramp files. |
| 2790 | STDERR can also be a file name." | 2790 | STDERR can also be a file name. If connection property |
| 2791 | (when args | 2791 | \"direct-async-process\" is non-nil, an alternative |
| 2792 | (with-parsed-tramp-file-name (expand-file-name default-directory) nil | 2792 | implementation will be used." |
| 2793 | (let ((name (plist-get args :name)) | 2793 | (if (tramp-get-connection-property |
| 2794 | (buffer (plist-get args :buffer)) | 2794 | (tramp-dissect-file-name default-directory) "direct-async-process" nil) |
| 2795 | (command (plist-get args :command)) | 2795 | (apply #'tramp-handle-make-process args) |
| 2796 | (coding (plist-get args :coding)) | 2796 | (when args |
| 2797 | (noquery (plist-get args :noquery)) | 2797 | (with-parsed-tramp-file-name (expand-file-name default-directory) nil |
| 2798 | (connection-type (plist-get args :connection-type)) | 2798 | (let ((name (plist-get args :name)) |
| 2799 | (filter (plist-get args :filter)) | 2799 | (buffer (plist-get args :buffer)) |
| 2800 | (sentinel (plist-get args :sentinel)) | 2800 | (command (plist-get args :command)) |
| 2801 | (stderr (plist-get args :stderr))) | 2801 | (coding (plist-get args :coding)) |
| 2802 | (unless (stringp name) | 2802 | (noquery (plist-get args :noquery)) |
| 2803 | (signal 'wrong-type-argument (list #'stringp name))) | 2803 | (connection-type (plist-get args :connection-type)) |
| 2804 | (unless (or (null buffer) (bufferp buffer) (stringp buffer)) | 2804 | (filter (plist-get args :filter)) |
| 2805 | (signal 'wrong-type-argument (list #'stringp buffer))) | 2805 | (sentinel (plist-get args :sentinel)) |
| 2806 | (unless (consp command) | 2806 | (stderr (plist-get args :stderr))) |
| 2807 | (signal 'wrong-type-argument (list #'consp command))) | 2807 | (unless (stringp name) |
| 2808 | (unless (or (null coding) | 2808 | (signal 'wrong-type-argument (list #'stringp name))) |
| 2809 | (and (symbolp coding) (memq coding coding-system-list)) | 2809 | (unless (or (null buffer) (bufferp buffer) (stringp buffer)) |
| 2810 | (and (consp coding) | 2810 | (signal 'wrong-type-argument (list #'stringp buffer))) |
| 2811 | (memq (car coding) coding-system-list) | 2811 | (unless (consp command) |
| 2812 | (memq (cdr coding) coding-system-list))) | 2812 | (signal 'wrong-type-argument (list #'consp command))) |
| 2813 | (signal 'wrong-type-argument (list #'symbolp coding))) | 2813 | (unless (or (null coding) |
| 2814 | (unless (or (null connection-type) (memq connection-type '(pipe pty))) | 2814 | (and (symbolp coding) (memq coding coding-system-list)) |
| 2815 | (signal 'wrong-type-argument (list #'symbolp connection-type))) | 2815 | (and (consp coding) |
| 2816 | (unless (or (null filter) (functionp filter)) | 2816 | (memq (car coding) coding-system-list) |
| 2817 | (signal 'wrong-type-argument (list #'functionp filter))) | 2817 | (memq (cdr coding) coding-system-list))) |
| 2818 | (unless (or (null sentinel) (functionp sentinel)) | 2818 | (signal 'wrong-type-argument (list #'symbolp coding))) |
| 2819 | (signal 'wrong-type-argument (list #'functionp sentinel))) | 2819 | (unless (or (null connection-type) (memq connection-type '(pipe pty))) |
| 2820 | (unless (or (null stderr) (bufferp stderr) (stringp stderr)) | 2820 | (signal 'wrong-type-argument (list #'symbolp connection-type))) |
| 2821 | (signal 'wrong-type-argument (list #'stringp stderr))) | 2821 | (unless (or (null filter) (functionp filter)) |
| 2822 | (when (and (stringp stderr) (tramp-tramp-file-p stderr) | 2822 | (signal 'wrong-type-argument (list #'functionp filter))) |
| 2823 | (not (tramp-equal-remote default-directory stderr))) | 2823 | (unless (or (null sentinel) (functionp sentinel)) |
| 2824 | (signal 'file-error (list "Wrong stderr" stderr))) | 2824 | (signal 'wrong-type-argument (list #'functionp sentinel))) |
| 2825 | 2825 | (unless (or (null stderr) (bufferp stderr) (stringp stderr)) | |
| 2826 | (let* ((buffer | 2826 | (signal 'wrong-type-argument (list #'stringp stderr))) |
| 2827 | (if buffer | 2827 | (when (and (stringp stderr) (tramp-tramp-file-p stderr) |
| 2828 | (get-buffer-create buffer) | 2828 | (not (tramp-equal-remote default-directory stderr))) |
| 2829 | ;; BUFFER can be nil. We use a temporary buffer. | 2829 | (signal 'file-error (list "Wrong stderr" stderr))) |
| 2830 | (generate-new-buffer tramp-temp-buffer-name))) | 2830 | |
| 2831 | ;; STDERR can also be a file name. | 2831 | (let* ((buffer |
| 2832 | (tmpstderr | 2832 | (if buffer |
| 2833 | (and stderr | 2833 | (get-buffer-create buffer) |
| 2834 | (if (and (stringp stderr) (tramp-tramp-file-p stderr)) | 2834 | ;; BUFFER can be nil. We use a temporary buffer. |
| 2835 | (tramp-unquote-file-local-name stderr) | 2835 | (generate-new-buffer tramp-temp-buffer-name))) |
| 2836 | (tramp-make-tramp-temp-file v)))) | 2836 | ;; STDERR can also be a file name. |
| 2837 | (remote-tmpstderr | 2837 | (tmpstderr |
| 2838 | (and tmpstderr (tramp-make-tramp-file-name v tmpstderr))) | 2838 | (and stderr |
| 2839 | (program (car command)) | 2839 | (if (and (stringp stderr) (tramp-tramp-file-p stderr)) |
| 2840 | (args (cdr command)) | 2840 | (tramp-unquote-file-local-name stderr) |
| 2841 | ;; When PROGRAM matches "*sh", and the first arg is | 2841 | (tramp-make-tramp-temp-file v)))) |
| 2842 | ;; "-c", it might be that the arguments exceed the | 2842 | (remote-tmpstderr |
| 2843 | ;; command line length. Therefore, we modify the | 2843 | (and tmpstderr (tramp-make-tramp-file-name v tmpstderr))) |
| 2844 | ;; command. | 2844 | (program (car command)) |
| 2845 | (heredoc (and (stringp program) | 2845 | (args (cdr command)) |
| 2846 | (string-match-p "sh$" program) | 2846 | ;; When PROGRAM matches "*sh", and the first arg is |
| 2847 | (string-equal "-c" (car args)) | 2847 | ;; "-c", it might be that the arguments exceed the |
| 2848 | (= (length args) 2))) | 2848 | ;; command line length. Therefore, we modify the |
| 2849 | ;; When PROGRAM is nil, we just provide a tty. | 2849 | ;; command. |
| 2850 | (args (if (not heredoc) args | 2850 | (heredoc (and (stringp program) |
| 2851 | (let ((i 250)) | 2851 | (string-match-p "sh$" program) |
| 2852 | (while (and (< i (length (cadr args))) | 2852 | (string-equal "-c" (car args)) |
| 2853 | (string-match " " (cadr args) i)) | 2853 | (= (length args) 2))) |
| 2854 | (setcdr | 2854 | ;; When PROGRAM is nil, we just provide a tty. |
| 2855 | args | 2855 | (args (if (not heredoc) args |
| 2856 | (list | 2856 | (let ((i 250)) |
| 2857 | (replace-match " \\\\\n" nil nil (cadr args)))) | 2857 | (while (and (< i (length (cadr args))) |
| 2858 | (setq i (+ i 250)))) | 2858 | (string-match " " (cadr args) i)) |
| 2859 | (cdr args))) | 2859 | (setcdr |
| 2860 | ;; Use a human-friendly prompt, for example for | 2860 | args |
| 2861 | ;; `shell'. We discard hops, if existing, that's why | 2861 | (list |
| 2862 | ;; we cannot use `file-remote-p'. | 2862 | (replace-match " \\\\\n" nil nil (cadr args)))) |
| 2863 | (prompt (format "PS1=%s %s" | 2863 | (setq i (+ i 250)))) |
| 2864 | (tramp-make-tramp-file-name v nil 'nohop) | 2864 | (cdr args))) |
| 2865 | tramp-initial-end-of-output)) | 2865 | ;; Use a human-friendly prompt, for example for |
| 2866 | ;; We use as environment the difference to toplevel | 2866 | ;; `shell'. We discard hops, if existing, that's why |
| 2867 | ;; `process-environment'. | 2867 | ;; we cannot use `file-remote-p'. |
| 2868 | env uenv | 2868 | (prompt (format "PS1=%s %s" |
| 2869 | (env (dolist (elt (cons prompt process-environment) env) | 2869 | (tramp-make-tramp-file-name v nil 'nohop) |
| 2870 | (or (member | 2870 | tramp-initial-end-of-output)) |
| 2871 | elt (default-toplevel-value 'process-environment)) | 2871 | ;; We use as environment the difference to toplevel |
| 2872 | (if (string-match-p "=" elt) | 2872 | ;; `process-environment'. |
| 2873 | (setq env (append env `(,elt))) | 2873 | env uenv |
| 2874 | (if (tramp-get-env-with-u-option v) | 2874 | (env (dolist (elt (cons prompt process-environment) env) |
| 2875 | (setq env (append `("-u" ,elt) env)) | 2875 | (or (member |
| 2876 | (setq uenv (cons elt uenv))))))) | 2876 | elt (default-toplevel-value 'process-environment)) |
| 2877 | (command | 2877 | (if (string-match-p "=" elt) |
| 2878 | (when (stringp program) | 2878 | (setq env (append env `(,elt))) |
| 2879 | (setenv-internal | 2879 | (if (tramp-get-env-with-u-option v) |
| 2880 | env "INSIDE_EMACS" | 2880 | (setq env (append `("-u" ,elt) env)) |
| 2881 | (concat (or (getenv "INSIDE_EMACS") emacs-version) | 2881 | (setq uenv (cons elt uenv))))))) |
| 2882 | ",tramp:" tramp-version) | 2882 | (command |
| 2883 | 'keep) | 2883 | (when (stringp program) |
| 2884 | (format "cd %s && %s exec %s %s env %s %s" | 2884 | (setenv-internal |
| 2885 | (tramp-shell-quote-argument localname) | 2885 | env "INSIDE_EMACS" |
| 2886 | (if uenv | 2886 | (concat (or (getenv "INSIDE_EMACS") emacs-version) |
| 2887 | (format | 2887 | ",tramp:" tramp-version) |
| 2888 | "unset %s &&" | 2888 | 'keep) |
| 2889 | (mapconcat | 2889 | (format "cd %s && %s exec %s %s env %s %s" |
| 2890 | #'tramp-shell-quote-argument uenv " ")) | 2890 | (tramp-shell-quote-argument localname) |
| 2891 | "") | 2891 | (if uenv |
| 2892 | (if heredoc (format "<<'%s'" tramp-end-of-heredoc) "") | 2892 | (format |
| 2893 | (if tmpstderr (format "2>'%s'" tmpstderr) "") | 2893 | "unset %s &&" |
| 2894 | (mapconcat #'tramp-shell-quote-argument env " ") | 2894 | (mapconcat |
| 2895 | (if heredoc | 2895 | #'tramp-shell-quote-argument uenv " ")) |
| 2896 | (format "%s\n(\n%s\n) </dev/tty\n%s" | 2896 | "") |
| 2897 | program (car args) tramp-end-of-heredoc) | 2897 | (if heredoc (format "<<'%s'" tramp-end-of-heredoc) "") |
| 2898 | (mapconcat #'tramp-shell-quote-argument | 2898 | (if tmpstderr (format "2>'%s'" tmpstderr) "") |
| 2899 | (cons program args) " "))))) | 2899 | (mapconcat #'tramp-shell-quote-argument env " ") |
| 2900 | (tramp-process-connection-type | 2900 | (if heredoc |
| 2901 | (or (null program) tramp-process-connection-type)) | 2901 | (format "%s\n(\n%s\n) </dev/tty\n%s" |
| 2902 | (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer))) | 2902 | program (car args) tramp-end-of-heredoc) |
| 2903 | (name1 name) | 2903 | (mapconcat #'tramp-shell-quote-argument |
| 2904 | (i 0) | 2904 | (cons program args) " "))))) |
| 2905 | ;; We do not want to raise an error when `make-process' | 2905 | (tramp-process-connection-type |
| 2906 | ;; has been started several times in `eshell' and | 2906 | (or (null program) tramp-process-connection-type)) |
| 2907 | ;; friends. | 2907 | (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer))) |
| 2908 | tramp-current-connection | 2908 | (name1 name) |
| 2909 | p) | 2909 | (i 0) |
| 2910 | 2910 | ;; We do not want to raise an error when | |
| 2911 | (while (get-process name1) | 2911 | ;; `make-process' has been started several times in |
| 2912 | ;; NAME must be unique as process name. | 2912 | ;; `eshell' and friends. |
| 2913 | (setq i (1+ i) | 2913 | tramp-current-connection |
| 2914 | name1 (format "%s<%d>" name i))) | 2914 | p) |
| 2915 | (setq name name1) | 2915 | |
| 2916 | ;; Set the new process properties. | 2916 | (while (get-process name1) |
| 2917 | (tramp-set-connection-property v "process-name" name) | 2917 | ;; NAME must be unique as process name. |
| 2918 | (tramp-set-connection-property v "process-buffer" buffer) | 2918 | (setq i (1+ i) |
| 2919 | 2919 | name1 (format "%s<%d>" name i))) | |
| 2920 | (with-current-buffer (tramp-get-connection-buffer v) | 2920 | (setq name name1) |
| 2921 | (unwind-protect | 2921 | ;; Set the new process properties. |
| 2922 | ;; We catch this event. Otherwise, `make-process' could | 2922 | (tramp-set-connection-property v "process-name" name) |
| 2923 | ;; be called on the local host. | 2923 | (tramp-set-connection-property v "process-buffer" buffer) |
| 2924 | (save-excursion | 2924 | |
| 2925 | (save-restriction | 2925 | (with-current-buffer (tramp-get-connection-buffer v) |
| 2926 | ;; Activate narrowing in order to save BUFFER | 2926 | (unwind-protect |
| 2927 | ;; contents. Clear also the modification time; | 2927 | ;; We catch this event. Otherwise, `make-process' |
| 2928 | ;; otherwise we might be interrupted by | 2928 | ;; could be called on the local host. |
| 2929 | ;; `verify-visited-file-modtime'. | 2929 | (save-excursion |
| 2930 | (let ((buffer-undo-list t) | 2930 | (save-restriction |
| 2931 | (inhibit-read-only t) | 2931 | ;; Activate narrowing in order to save BUFFER |
| 2932 | (mark (point-max))) | 2932 | ;; contents. Clear also the modification time; |
| 2933 | (clear-visited-file-modtime) | 2933 | ;; otherwise we might be interrupted by |
| 2934 | (narrow-to-region (point-max) (point-max)) | 2934 | ;; `verify-visited-file-modtime'. |
| 2935 | ;; We call `tramp-maybe-open-connection', in | 2935 | (let ((buffer-undo-list t) |
| 2936 | ;; order to cleanup the prompt afterwards. | 2936 | (inhibit-read-only t) |
| 2937 | (catch 'suppress | 2937 | (mark (point-max))) |
| 2938 | (tramp-maybe-open-connection v) | 2938 | (clear-visited-file-modtime) |
| 2939 | (setq p (tramp-get-connection-process v)) | ||
| 2940 | ;; Set the pid of the remote shell. This is | ||
| 2941 | ;; needed when sending signals remotely. | ||
| 2942 | (let ((pid (tramp-send-command-and-read v "echo $$"))) | ||
| 2943 | (process-put p 'remote-pid pid) | ||
| 2944 | (tramp-set-connection-property p "remote-pid" pid)) | ||
| 2945 | ;; `tramp-maybe-open-connection' and | ||
| 2946 | ;; `tramp-send-command-and-read' could have | ||
| 2947 | ;; trashed the connection buffer. Remove this. | ||
| 2948 | (widen) | ||
| 2949 | (delete-region mark (point-max)) | ||
| 2950 | (narrow-to-region (point-max) (point-max)) | 2939 | (narrow-to-region (point-max) (point-max)) |
| 2951 | ;; Now do it. | 2940 | ;; We call `tramp-maybe-open-connection', in |
| 2952 | (if command | 2941 | ;; order to cleanup the prompt afterwards. |
| 2953 | ;; Send the command. | 2942 | (catch 'suppress |
| 2954 | (tramp-send-command v command nil t) ; nooutput | 2943 | (tramp-maybe-open-connection v) |
| 2955 | ;; Check, whether a pty is associated. | 2944 | (setq p (tramp-get-connection-process v)) |
| 2956 | (unless (process-get p 'remote-tty) | 2945 | ;; Set the pid of the remote shell. This is |
| 2957 | (tramp-error | 2946 | ;; needed when sending signals remotely. |
| 2958 | v 'file-error | 2947 | (let ((pid (tramp-send-command-and-read v "echo $$"))) |
| 2959 | "pty association is not supported for `%s'" | 2948 | (process-put p 'remote-pid pid) |
| 2960 | name)))) | 2949 | (tramp-set-connection-property p "remote-pid" pid)) |
| 2961 | ;; Set sentinel and filter. | 2950 | ;; `tramp-maybe-open-connection' and |
| 2962 | (when sentinel | 2951 | ;; `tramp-send-command-and-read' could have |
| 2963 | (set-process-sentinel p sentinel)) | 2952 | ;; trashed the connection buffer. Remove this. |
| 2964 | (when filter | 2953 | (widen) |
| 2965 | (set-process-filter p filter)) | 2954 | (delete-region mark (point-max)) |
| 2966 | ;; Set query flag and process marker for this | 2955 | (narrow-to-region (point-max) (point-max)) |
| 2967 | ;; process. We ignore errors, because the | 2956 | ;; Now do it. |
| 2968 | ;; process could have finished already. | 2957 | (if command |
| 2969 | (ignore-errors | 2958 | ;; Send the command. |
| 2970 | (set-process-query-on-exit-flag p (null noquery)) | 2959 | (tramp-send-command v command nil t) ; nooutput |
| 2971 | (set-marker (process-mark p) (point))) | 2960 | ;; Check, whether a pty is associated. |
| 2972 | ;; We must flush them here already; otherwise | 2961 | (unless (process-get p 'remote-tty) |
| 2973 | ;; `rename-file', `delete-file' or | 2962 | (tramp-error |
| 2974 | ;; `insert-file-contents' will fail. | 2963 | v 'file-error |
| 2975 | (tramp-flush-connection-property v "process-name") | 2964 | "pty association is not supported for `%s'" |
| 2976 | (tramp-flush-connection-property v "process-buffer") | 2965 | name)))) |
| 2977 | ;; Copy tmpstderr file. | 2966 | ;; Set sentinel and filter. |
| 2978 | (when (and (stringp stderr) | 2967 | (when sentinel |
| 2979 | (not (tramp-tramp-file-p stderr))) | 2968 | (set-process-sentinel p sentinel)) |
| 2980 | (add-function | 2969 | (when filter |
| 2981 | :after (process-sentinel p) | 2970 | (set-process-filter p filter)) |
| 2982 | (lambda (_proc _msg) | 2971 | ;; Set query flag and process marker for this |
| 2983 | (rename-file remote-tmpstderr stderr)))) | 2972 | ;; process. We ignore errors, because the |
| 2984 | ;; Provide error buffer. This shows only | 2973 | ;; process could have finished already. |
| 2985 | ;; initial error messages; messages arriving | 2974 | (ignore-errors |
| 2986 | ;; later on will be inserted when the process is | 2975 | (set-process-query-on-exit-flag p (null noquery)) |
| 2987 | ;; deleted. The temporary file will exist until | 2976 | (set-marker (process-mark p) (point))) |
| 2988 | ;; the process is deleted. | 2977 | ;; We must flush them here already; otherwise |
| 2989 | (when (bufferp stderr) | 2978 | ;; `rename-file', `delete-file' or |
| 2990 | (with-current-buffer stderr | 2979 | ;; `insert-file-contents' will fail. |
| 2991 | (insert-file-contents-literally remote-tmpstderr)) | 2980 | (tramp-flush-connection-property v "process-name") |
| 2992 | ;; Delete tmpstderr file. | 2981 | (tramp-flush-connection-property v "process-buffer") |
| 2993 | (add-function | 2982 | ;; Copy tmpstderr file. |
| 2994 | :after (process-sentinel p) | 2983 | (when (and (stringp stderr) |
| 2995 | (lambda (_proc _msg) | 2984 | (not (tramp-tramp-file-p stderr))) |
| 2996 | (when (file-exists-p remote-tmpstderr) | 2985 | (add-function |
| 2997 | (with-current-buffer stderr | 2986 | :after (process-sentinel p) |
| 2998 | (insert-file-contents-literally | 2987 | (lambda (_proc _msg) |
| 2999 | remote-tmpstderr nil nil nil 'replace)) | 2988 | (rename-file remote-tmpstderr stderr)))) |
| 3000 | (delete-file remote-tmpstderr))))) | 2989 | ;; Provide error buffer. This shows only |
| 3001 | ;; Return process. | 2990 | ;; initial error messages; messages arriving |
| 3002 | p))) | 2991 | ;; later on will be inserted when the process |
| 2992 | ;; is deleted. The temporary file will exist | ||
| 2993 | ;; until the process is deleted. | ||
| 2994 | (when (bufferp stderr) | ||
| 2995 | (with-current-buffer stderr | ||
| 2996 | (insert-file-contents-literally remote-tmpstderr)) | ||
| 2997 | ;; Delete tmpstderr file. | ||
| 2998 | (add-function | ||
| 2999 | :after (process-sentinel p) | ||
| 3000 | (lambda (_proc _msg) | ||
| 3001 | (when (file-exists-p remote-tmpstderr) | ||
| 3002 | (with-current-buffer stderr | ||
| 3003 | (insert-file-contents-literally | ||
| 3004 | remote-tmpstderr nil nil nil 'replace)) | ||
| 3005 | (delete-file remote-tmpstderr))))) | ||
| 3006 | ;; Return process. | ||
| 3007 | p))) | ||
| 3003 | 3008 | ||
| 3004 | ;; Save exit. | 3009 | ;; Save exit. |
| 3005 | (if (string-match-p tramp-temp-buffer-name (buffer-name)) | 3010 | (if (string-match-p tramp-temp-buffer-name (buffer-name)) |
| 3006 | (ignore-errors | 3011 | (ignore-errors |
| 3007 | (set-process-buffer p nil) | 3012 | (set-process-buffer p nil) |
| 3008 | (kill-buffer (current-buffer))) | 3013 | (kill-buffer (current-buffer))) |
| 3009 | (set-buffer-modified-p bmp)) | 3014 | (set-buffer-modified-p bmp)) |
| 3010 | (tramp-flush-connection-property v "process-name") | 3015 | (tramp-flush-connection-property v "process-name") |
| 3011 | (tramp-flush-connection-property v "process-buffer")))))))) | 3016 | (tramp-flush-connection-property v "process-buffer"))))))))) |
| 3012 | 3017 | ||
| 3013 | (defun tramp-sh-get-signal-strings (vec) | 3018 | (defun tramp-sh-get-signal-strings (vec) |
| 3014 | "Strings to return by `process-file' in case of signals." | 3019 | "Strings to return by `process-file' in case of signals." |
| @@ -3646,6 +3651,14 @@ Fall back to normal file name handler if no Tramp handler exists." | |||
| 3646 | (save-match-data (apply (cdr fn) args)) | 3651 | (save-match-data (apply (cdr fn) args)) |
| 3647 | (tramp-run-real-handler operation args))) | 3652 | (tramp-run-real-handler operation args))) |
| 3648 | 3653 | ||
| 3654 | ;;;###tramp-autoload | ||
| 3655 | (defun tramp-sh-file-name-handler-p (vec) | ||
| 3656 | "Whether VEC uses a method from `tramp-sh-file-name-handler'." | ||
| 3657 | (and (assoc (tramp-file-name-method vec) tramp-methods) | ||
| 3658 | (eq (tramp-find-foreign-file-name-handler | ||
| 3659 | (tramp-make-tramp-file-name vec nil 'nohop)) | ||
| 3660 | 'tramp-sh-file-name-handler))) | ||
| 3661 | |||
| 3649 | ;; This must be the last entry, because `identity' always matches. | 3662 | ;; This must be the last entry, because `identity' always matches. |
| 3650 | ;;;###tramp-autoload | 3663 | ;;;###tramp-autoload |
| 3651 | (tramp--with-startup | 3664 | (tramp--with-startup |
| @@ -4769,6 +4782,12 @@ Goes through the list `tramp-inline-compress-commands'." | |||
| 4769 | (tramp-message | 4782 | (tramp-message |
| 4770 | vec 2 "Couldn't find an inline transfer compress command"))))) | 4783 | vec 2 "Couldn't find an inline transfer compress command"))))) |
| 4771 | 4784 | ||
| 4785 | ;;;###tramp-autoload | ||
| 4786 | (defun tramp-multi-hop-p (vec) | ||
| 4787 | "Whether the method of VEC is capable of multi-hops." | ||
| 4788 | (and (tramp-sh-file-name-handler-p vec) | ||
| 4789 | (not (tramp-get-method-parameter vec 'tramp-copy-program)))) | ||
| 4790 | |||
| 4772 | (defun tramp-compute-multi-hops (vec) | 4791 | (defun tramp-compute-multi-hops (vec) |
| 4773 | "Expands VEC according to `tramp-default-proxies-alist'." | 4792 | "Expands VEC according to `tramp-default-proxies-alist'." |
| 4774 | (let ((saved-tdpa tramp-default-proxies-alist) | 4793 | (let ((saved-tdpa tramp-default-proxies-alist) |
| @@ -4832,8 +4851,7 @@ Goes through the list `tramp-inline-compress-commands'." | |||
| 4832 | (when (cdr target-alist) | 4851 | (when (cdr target-alist) |
| 4833 | (setq choices target-alist) | 4852 | (setq choices target-alist) |
| 4834 | (while (setq item (pop choices)) | 4853 | (while (setq item (pop choices)) |
| 4835 | (when (or (not (tramp-get-method-parameter item 'tramp-login-program)) | 4854 | (unless (tramp-multi-hop-p item) |
| 4836 | (tramp-get-method-parameter item 'tramp-copy-program)) | ||
| 4837 | (setq tramp-default-proxies-alist saved-tdpa) | 4855 | (setq tramp-default-proxies-alist saved-tdpa) |
| 4838 | (tramp-user-error | 4856 | (tramp-user-error |
| 4839 | vec "Method `%s' is not supported for multi-hops." | 4857 | vec "Method `%s' is not supported for multi-hops." |
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index c169a86f915..fdf26f6b782 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el | |||
| @@ -1482,10 +1482,7 @@ default values are used." | |||
| 1482 | (tramp-user-error | 1482 | (tramp-user-error |
| 1483 | v "Method `%s' is not known." method)) | 1483 | v "Method `%s' is not known." method)) |
| 1484 | ;; Only some methods from tramp-sh.el do support multi-hops. | 1484 | ;; Only some methods from tramp-sh.el do support multi-hops. |
| 1485 | (when (and | 1485 | (unless (or (null hop) nodefault non-essential (tramp-multi-hop-p v)) |
| 1486 | hop | ||
| 1487 | (or (not (tramp-get-method-parameter v 'tramp-login-program)) | ||
| 1488 | (tramp-get-method-parameter v 'tramp-copy-program))) | ||
| 1489 | (tramp-user-error | 1486 | (tramp-user-error |
| 1490 | v "Method `%s' is not supported for multi-hops." method))))))) | 1487 | v "Method `%s' is not supported for multi-hops." method))))))) |
| 1491 | 1488 | ||
| @@ -1499,8 +1496,7 @@ See `tramp-dissect-file-name' for details." | |||
| 1499 | tramp-postfix-host-format name)) | 1496 | tramp-postfix-host-format name)) |
| 1500 | nodefault))) | 1497 | nodefault))) |
| 1501 | ;; Only some methods from tramp-sh.el do support multi-hops. | 1498 | ;; Only some methods from tramp-sh.el do support multi-hops. |
| 1502 | (when (or (not (tramp-get-method-parameter v 'tramp-login-program)) | 1499 | (unless (or nodefault non-essential (tramp-multi-hop-p v)) |
| 1503 | (tramp-get-method-parameter v 'tramp-copy-program)) | ||
| 1504 | (tramp-user-error | 1500 | (tramp-user-error |
| 1505 | v "Method `%s' is not supported for multi-hops." | 1501 | v "Method `%s' is not supported for multi-hops." |
| 1506 | (tramp-file-name-method v))) | 1502 | (tramp-file-name-method v))) |
| @@ -3519,13 +3515,10 @@ User is always nil." | |||
| 3519 | 3515 | ||
| 3520 | ;; When we shall insert only a part of the file, we | 3516 | ;; When we shall insert only a part of the file, we |
| 3521 | ;; copy this part. This works only for the shell file | 3517 | ;; copy this part. This works only for the shell file |
| 3522 | ;; name handlers. | 3518 | ;; name handlers. It doesn't work for crypted files. |
| 3523 | (when (and (or beg end) | 3519 | (when (and (or beg end) |
| 3524 | ;; Direct actions aren't possible for | 3520 | (tramp-sh-file-name-handler-p v) |
| 3525 | ;; crypted directories. | 3521 | (null tramp-crypt-enabled)) |
| 3526 | (null tramp-crypt-enabled) | ||
| 3527 | (tramp-get-method-parameter | ||
| 3528 | v 'tramp-login-program)) | ||
| 3529 | (setq remote-copy (tramp-make-tramp-temp-file v)) | 3522 | (setq remote-copy (tramp-make-tramp-temp-file v)) |
| 3530 | ;; This is defined in tramp-sh.el. Let's assume | 3523 | ;; This is defined in tramp-sh.el. Let's assume |
| 3531 | ;; this is loaded already. | 3524 | ;; this is loaded already. |
| @@ -3640,6 +3633,152 @@ User is always nil." | |||
| 3640 | (load local-copy noerror t nosuffix must-suffix) | 3633 | (load local-copy noerror t nosuffix must-suffix) |
| 3641 | (delete-file local-copy))))) | 3634 | (delete-file local-copy))))) |
| 3642 | t))) | 3635 | t))) |
| 3636 | ;; We use BUFFER also as connection buffer during setup. Because of | ||
| 3637 | ;; this, its original contents must be saved, and restored once | ||
| 3638 | ;; connection has been setup. | ||
| 3639 | (defun tramp-handle-make-process (&rest args) | ||
| 3640 | "An alternative `make-process' implementation for Tramp files." | ||
| 3641 | (when args | ||
| 3642 | (with-parsed-tramp-file-name (expand-file-name default-directory) nil | ||
| 3643 | (let ((name (plist-get args :name)) | ||
| 3644 | (buffer (plist-get args :buffer)) | ||
| 3645 | (command (plist-get args :command)) | ||
| 3646 | (coding (plist-get args :coding)) | ||
| 3647 | (noquery (plist-get args :noquery)) | ||
| 3648 | (connection-type (plist-get args :connection-type)) | ||
| 3649 | (filter (plist-get args :filter)) | ||
| 3650 | (sentinel (plist-get args :sentinel)) | ||
| 3651 | (stderr (plist-get args :stderr))) | ||
| 3652 | (unless (stringp name) | ||
| 3653 | (signal 'wrong-type-argument (list #'stringp name))) | ||
| 3654 | (unless (or (null buffer) (bufferp buffer) (stringp buffer)) | ||
| 3655 | (signal 'wrong-type-argument (list #'stringp buffer))) | ||
| 3656 | (unless (consp command) | ||
| 3657 | (signal 'wrong-type-argument (list #'consp command))) | ||
| 3658 | (unless (or (null coding) | ||
| 3659 | (and (symbolp coding) (memq coding coding-system-list)) | ||
| 3660 | (and (consp coding) | ||
| 3661 | (memq (car coding) coding-system-list) | ||
| 3662 | (memq (cdr coding) coding-system-list))) | ||
| 3663 | (signal 'wrong-type-argument (list #'symbolp coding))) | ||
| 3664 | (unless (or (null connection-type) (memq connection-type '(pipe pty))) | ||
| 3665 | (signal 'wrong-type-argument (list #'symbolp connection-type))) | ||
| 3666 | (unless (or (null filter) (functionp filter)) | ||
| 3667 | (signal 'wrong-type-argument (list #'functionp filter))) | ||
| 3668 | (unless (or (null sentinel) (functionp sentinel)) | ||
| 3669 | (signal 'wrong-type-argument (list #'functionp sentinel))) | ||
| 3670 | (unless (or (null stderr) (bufferp stderr) (stringp stderr)) | ||
| 3671 | (signal 'wrong-type-argument (list #'stringp stderr))) | ||
| 3672 | (when (and (stringp stderr) (tramp-tramp-file-p stderr) | ||
| 3673 | (not (tramp-equal-remote default-directory stderr))) | ||
| 3674 | (signal 'file-error (list "Wrong stderr" stderr))) | ||
| 3675 | |||
| 3676 | (let* ((buffer | ||
| 3677 | (if buffer | ||
| 3678 | (get-buffer-create buffer) | ||
| 3679 | ;; BUFFER can be nil. We use a temporary buffer. | ||
| 3680 | (generate-new-buffer tramp-temp-buffer-name))) | ||
| 3681 | (command (append `("cd" ,localname "&&") | ||
| 3682 | (mapcar #'tramp-shell-quote-argument command))) | ||
| 3683 | (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer))) | ||
| 3684 | (name1 name) | ||
| 3685 | (i 0) | ||
| 3686 | ;; We do not want to raise an error when `make-process' | ||
| 3687 | ;; has been started several times in `eshell' and | ||
| 3688 | ;; friends. | ||
| 3689 | tramp-current-connection | ||
| 3690 | p) | ||
| 3691 | |||
| 3692 | (while (get-process name1) | ||
| 3693 | ;; NAME must be unique as process name. | ||
| 3694 | (setq i (1+ i) | ||
| 3695 | name1 (format "%s<%d>" name i))) | ||
| 3696 | (setq name name1) | ||
| 3697 | ;; Set the new process properties. | ||
| 3698 | (tramp-set-connection-property v "process-name" name) | ||
| 3699 | (tramp-set-connection-property v "process-buffer" buffer) | ||
| 3700 | |||
| 3701 | (with-current-buffer (tramp-get-connection-buffer v) | ||
| 3702 | (unwind-protect | ||
| 3703 | (let* ((login-program | ||
| 3704 | (tramp-get-method-parameter v 'tramp-login-program)) | ||
| 3705 | (login-args | ||
| 3706 | (tramp-get-method-parameter v 'tramp-login-args)) | ||
| 3707 | (async-args | ||
| 3708 | (tramp-get-method-parameter v 'tramp-async-args)) | ||
| 3709 | ;; We don't create the temporary file. In | ||
| 3710 | ;; fact, it is just a prefix for the | ||
| 3711 | ;; ControlPath option of ssh; the real | ||
| 3712 | ;; temporary file has another name, and it is | ||
| 3713 | ;; created and protected by ssh. It is also | ||
| 3714 | ;; removed by ssh when the connection is | ||
| 3715 | ;; closed. The temporary file name is cached | ||
| 3716 | ;; in the main connection process, therefore | ||
| 3717 | ;; we cannot use `tramp-get-connection-process'. | ||
| 3718 | (tmpfile | ||
| 3719 | (when (tramp-sh-file-name-handler-p v) | ||
| 3720 | (with-tramp-connection-property | ||
| 3721 | (tramp-get-process v) "temp-file" | ||
| 3722 | (tramp-compat-make-temp-name)))) | ||
| 3723 | (options | ||
| 3724 | (when (tramp-sh-file-name-handler-p v) | ||
| 3725 | (tramp-compat-funcall | ||
| 3726 | 'tramp-ssh-controlmaster-options v))) | ||
| 3727 | spec) | ||
| 3728 | |||
| 3729 | ;; Replace `login-args' place holders. | ||
| 3730 | (setq | ||
| 3731 | spec (format-spec-make ?t tmpfile) | ||
| 3732 | options (format-spec (or options "") spec) | ||
| 3733 | spec (format-spec-make | ||
| 3734 | ?h (or host "") ?u (or user "") ?p (or port "") | ||
| 3735 | ?c options ?l "") | ||
| 3736 | ;; Add arguments for asynchronous processes. | ||
| 3737 | login-args (append async-args login-args) | ||
| 3738 | ;; Expand format spec. | ||
| 3739 | login-args | ||
| 3740 | (tramp-compat-flatten-tree | ||
| 3741 | (mapcar | ||
| 3742 | (lambda (x) | ||
| 3743 | (setq x (mapcar (lambda (y) (format-spec y spec)) x)) | ||
| 3744 | (unless (member "" x) x)) | ||
| 3745 | login-args)) | ||
| 3746 | ;; Split ControlMaster options. | ||
| 3747 | login-args | ||
| 3748 | (tramp-compat-flatten-tree | ||
| 3749 | (mapcar (lambda (x) (split-string x " ")) login-args)) | ||
| 3750 | p (apply | ||
| 3751 | #'start-process | ||
| 3752 | name buffer login-program (append login-args command))) | ||
| 3753 | |||
| 3754 | (tramp-message v 6 "%s" (string-join (process-command p) " ")) | ||
| 3755 | ;; Set sentinel and filter. | ||
| 3756 | (when sentinel | ||
| 3757 | (set-process-sentinel p sentinel)) | ||
| 3758 | (when filter | ||
| 3759 | (set-process-filter p filter)) | ||
| 3760 | ;; Set query flag and process marker for this | ||
| 3761 | ;; process. We ignore errors, because the | ||
| 3762 | ;; process could have finished already. | ||
| 3763 | (ignore-errors | ||
| 3764 | (set-process-query-on-exit-flag p (null noquery)) | ||
| 3765 | (set-marker (process-mark p) (point))) | ||
| 3766 | ;; We must flush them here already; otherwise | ||
| 3767 | ;; `rename-file', `delete-file' or | ||
| 3768 | ;; `insert-file-contents' will fail. | ||
| 3769 | (tramp-flush-connection-property v "process-name") | ||
| 3770 | (tramp-flush-connection-property v "process-buffer") | ||
| 3771 | ;; Return process. | ||
| 3772 | p) | ||
| 3773 | |||
| 3774 | ;; Save exit. | ||
| 3775 | (if (string-match-p tramp-temp-buffer-name (buffer-name)) | ||
| 3776 | (ignore-errors | ||
| 3777 | (set-process-buffer p nil) | ||
| 3778 | (kill-buffer (current-buffer))) | ||
| 3779 | (set-buffer-modified-p bmp)) | ||
| 3780 | (tramp-flush-connection-property v "process-name") | ||
| 3781 | (tramp-flush-connection-property v "process-buffer")))))))) | ||
| 3643 | 3782 | ||
| 3644 | (defun tramp-handle-make-symbolic-link | 3783 | (defun tramp-handle-make-symbolic-link |
| 3645 | (target linkname &optional ok-if-already-exists) | 3784 | (target linkname &optional ok-if-already-exists) |
| @@ -3676,8 +3815,8 @@ support symbolic links." | |||
| 3676 | (current-buffer)) | 3815 | (current-buffer)) |
| 3677 | (t (get-buffer-create | 3816 | (t (get-buffer-create |
| 3678 | (if asynchronous | 3817 | (if asynchronous |
| 3679 | "*Async Shell Command*" | 3818 | shell-command-buffer-name-async |
| 3680 | "*Shell Command Output*"))))) | 3819 | shell-command-buffer-name))))) |
| 3681 | (error-buffer | 3820 | (error-buffer |
| 3682 | (cond | 3821 | (cond |
| 3683 | ((bufferp error-buffer) error-buffer) | 3822 | ((bufferp error-buffer) error-buffer) |
| @@ -4706,7 +4845,7 @@ This handles also chrooted environments, which are not regarded as local." | |||
| 4706 | ;; The method shall be applied to one of the shell file name | 4845 | ;; The method shall be applied to one of the shell file name |
| 4707 | ;; handlers. `tramp-local-host-p' is also called for "smb" and | 4846 | ;; handlers. `tramp-local-host-p' is also called for "smb" and |
| 4708 | ;; alike, where it must fail. | 4847 | ;; alike, where it must fail. |
| 4709 | (tramp-get-method-parameter vec 'tramp-login-program) | 4848 | (tramp-sh-file-name-handler-p vec) |
| 4710 | ;; Direct actions aren't possible for crypted directories. | 4849 | ;; Direct actions aren't possible for crypted directories. |
| 4711 | (null tramp-crypt-enabled) | 4850 | (null tramp-crypt-enabled) |
| 4712 | ;; The local temp directory must be writable for the other user. | 4851 | ;; The local temp directory must be writable for the other user. |
diff --git a/lisp/outline.el b/lisp/outline.el index 28ea8a86e6f..6158ed594e9 100644 --- a/lisp/outline.el +++ b/lisp/outline.el | |||
| @@ -289,12 +289,19 @@ Turning on outline mode calls the value of `text-mode-hook' and then of | |||
| 289 | (list (list nil (concat "^\\(?:" outline-regexp "\\).*$") 0))) | 289 | (list (list nil (concat "^\\(?:" outline-regexp "\\).*$") 0))) |
| 290 | (add-hook 'change-major-mode-hook 'outline-show-all nil t)) | 290 | (add-hook 'change-major-mode-hook 'outline-show-all nil t)) |
| 291 | 291 | ||
| 292 | (defvar outline-minor-mode-map) | ||
| 293 | |||
| 292 | (defcustom outline-minor-mode-prefix "\C-c@" | 294 | (defcustom outline-minor-mode-prefix "\C-c@" |
| 293 | "Prefix key to use for Outline commands in Outline minor mode. | 295 | "Prefix key to use for Outline commands in Outline minor mode. |
| 294 | The value of this variable is checked as part of loading Outline mode. | 296 | The value of this variable is checked as part of loading Outline mode. |
| 295 | After that, changing the prefix key requires manipulating keymaps." | 297 | After that, changing the prefix key requires manipulating keymaps." |
| 296 | :type 'string | 298 | :type 'key-sequence |
| 297 | :group 'outlines) | 299 | :group 'outlines |
| 300 | :initialize 'custom-initialize-default | ||
| 301 | :set (lambda (sym val) | ||
| 302 | (define-key outline-minor-mode-map outline-minor-mode-prefix nil) | ||
| 303 | (define-key outline-minor-mode-map val outline-mode-prefix-map) | ||
| 304 | (set-default sym val))) | ||
| 298 | 305 | ||
| 299 | ;;;###autoload | 306 | ;;;###autoload |
| 300 | (define-minor-mode outline-minor-mode | 307 | (define-minor-mode outline-minor-mode |
diff --git a/lisp/play/snake.el b/lisp/play/snake.el index d7c0683a05f..70d80c464fc 100644 --- a/lisp/play/snake.el +++ b/lisp/play/snake.el | |||
| @@ -192,6 +192,7 @@ and then start moving it leftwards.") | |||
| 192 | (defvar snake-null-map | 192 | (defvar snake-null-map |
| 193 | (let ((map (make-sparse-keymap 'snake-null-map))) | 193 | (let ((map (make-sparse-keymap 'snake-null-map))) |
| 194 | (define-key map "n" 'snake-start-game) | 194 | (define-key map "n" 'snake-start-game) |
| 195 | (define-key map "q" 'quit-window) | ||
| 195 | map) | 196 | map) |
| 196 | "Keymap for finished Snake games.") | 197 | "Keymap for finished Snake games.") |
| 197 | 198 | ||
diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el index cdbb59a5add..6122caf5189 100644 --- a/lisp/progmodes/cperl-mode.el +++ b/lisp/progmodes/cperl-mode.el | |||
| @@ -3560,19 +3560,18 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', | |||
| 3560 | "\\(\\`\n?\\|^\n\\)=" ; POD | 3560 | "\\(\\`\n?\\|^\n\\)=" ; POD |
| 3561 | "\\|" | 3561 | "\\|" |
| 3562 | ;; One extra () before this: | 3562 | ;; One extra () before this: |
| 3563 | "<<~?" ; HERE-DOC | 3563 | "<<\\(~?\\)" ; HERE-DOC, indented-p = capture 2 |
| 3564 | "\\(" ; 1 + 1 | 3564 | "\\(" ; 2 + 1 |
| 3565 | ;; First variant "BLAH" or just ``. | 3565 | ;; First variant "BLAH" or just ``. |
| 3566 | "[ \t]*" ; Yes, whitespace is allowed! | 3566 | "[ \t]*" ; Yes, whitespace is allowed! |
| 3567 | "\\([\"'`]\\)" ; 2 + 1 = 3 | 3567 | "\\([\"'`]\\)" ; 3 + 1 = 4 |
| 3568 | "\\([^\"'`\n]*\\)" ; 3 + 1 | 3568 | "\\([^\"'`\n]*\\)" ; 4 + 1 |
| 3569 | "\\3" | 3569 | "\\4" |
| 3570 | "\\|" | 3570 | "\\|" |
| 3571 | ;; Second variant: Identifier or \ID (same as 'ID') or empty | 3571 | ;; Second variant: Identifier or \ID (same as 'ID') or empty |
| 3572 | "\\\\?\\(\\([a-zA-Z_][a-zA-Z_0-9]*\\)?\\)" ; 4 + 1, 5 + 1 | 3572 | "\\\\?\\(\\([a-zA-Z_][a-zA-Z_0-9]*\\)?\\)" ; 5 + 1, 6 + 1 |
| 3573 | ;; Do not have <<= or << 30 or <<30 or << $blah. | 3573 | ;; Do not have <<= or << 30 or <<30 or << $blah. |
| 3574 | ;; "\\([^= \t0-9$@%&]\\|[ \t]+[^ \t\n0-9$@%&]\\)" ; 6 + 1 | 3574 | ;; "\\([^= \t0-9$@%&]\\|[ \t]+[^ \t\n0-9$@%&]\\)" ; 6 + 1 |
| 3575 | "\\(\\)" ; To preserve count of pars :-( 6 + 1 | ||
| 3576 | "\\)" | 3575 | "\\)" |
| 3577 | "\\|" | 3576 | "\\|" |
| 3578 | ;; 1+6 extra () before this: | 3577 | ;; 1+6 extra () before this: |
| @@ -3762,11 +3761,11 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', | |||
| 3762 | ;; ;; "\\([^= \t0-9$@%&]\\|[ \t]+[^ \t\n0-9$@%&]\\)" ; 6 + 1 | 3761 | ;; ;; "\\([^= \t0-9$@%&]\\|[ \t]+[^ \t\n0-9$@%&]\\)" ; 6 + 1 |
| 3763 | ;; "\\(\\)" ; To preserve count of pars :-( 6 + 1 | 3762 | ;; "\\(\\)" ; To preserve count of pars :-( 6 + 1 |
| 3764 | ;; "\\)" | 3763 | ;; "\\)" |
| 3765 | ((match-beginning 2) ; 1 + 1 | 3764 | ((match-beginning 3) ; 2 + 1 |
| 3766 | (setq b (point) | 3765 | (setq b (point) |
| 3767 | tb (match-beginning 0) | 3766 | tb (match-beginning 0) |
| 3768 | c (and ; not HERE-DOC | 3767 | c (and ; not HERE-DOC |
| 3769 | (match-beginning 5) | 3768 | (match-beginning 6) |
| 3770 | (save-match-data | 3769 | (save-match-data |
| 3771 | (or (looking-at "[ \t]*(") ; << function_call() | 3770 | (or (looking-at "[ \t]*(") ; << function_call() |
| 3772 | (save-excursion ; 1 << func_name, or $foo << 10 | 3771 | (save-excursion ; 1 << func_name, or $foo << 10 |
| @@ -3793,17 +3792,17 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', | |||
| 3793 | (looking-at "\\(printf?\\|say\\|system\\|exec\\|sort\\)\\>"))) | 3792 | (looking-at "\\(printf?\\|say\\|system\\|exec\\|sort\\)\\>"))) |
| 3794 | (error t))))))) | 3793 | (error t))))))) |
| 3795 | (error nil))) ; func(<<EOF) | 3794 | (error nil))) ; func(<<EOF) |
| 3796 | (and (not (match-beginning 6)) ; Empty | 3795 | (and (not (match-beginning 7)) ; Empty |
| 3797 | (looking-at | 3796 | (looking-at |
| 3798 | "[ \t]*[=0-9$@%&(]")))))) | 3797 | "[ \t]*[=0-9$@%&(]")))))) |
| 3799 | (if c ; Not here-doc | 3798 | (if c ; Not here-doc |
| 3800 | nil ; Skip it. | 3799 | nil ; Skip it. |
| 3801 | (setq c (match-end 2)) ; 1 + 1 | 3800 | (setq c (match-end 3)) ; 2 + 1 |
| 3802 | (if (match-beginning 5) ;4 + 1 | 3801 | (if (match-beginning 6) ;6 + 1 |
| 3803 | (setq b1 (match-beginning 5) ; 4 + 1 | 3802 | (setq b1 (match-beginning 6) ; 5 + 1 |
| 3804 | e1 (match-end 5)) ; 4 + 1 | 3803 | e1 (match-end 6)) ; 5 + 1 |
| 3805 | (setq b1 (match-beginning 4) ; 3 + 1 | 3804 | (setq b1 (match-beginning 5) ; 4 + 1 |
| 3806 | e1 (match-end 4))) ; 3 + 1 | 3805 | e1 (match-end 5))) ; 4 + 1 |
| 3807 | (setq tag (buffer-substring b1 e1) | 3806 | (setq tag (buffer-substring b1 e1) |
| 3808 | qtag (regexp-quote tag)) | 3807 | qtag (regexp-quote tag)) |
| 3809 | (cond (cperl-pod-here-fontify | 3808 | (cond (cperl-pod-here-fontify |
| @@ -3818,8 +3817,10 @@ the sections using `cperl-pod-head-face', `cperl-pod-face', | |||
| 3818 | (setq b (point)) | 3817 | (setq b (point)) |
| 3819 | ;; We do not search to max, since we may be called from | 3818 | ;; We do not search to max, since we may be called from |
| 3820 | ;; some hook of fontification, and max is random | 3819 | ;; some hook of fontification, and max is random |
| 3821 | (or (and (re-search-forward (concat "^[ \t]*" qtag "$") | 3820 | (or (and (re-search-forward |
| 3822 | stop-point 'toend) | 3821 | (concat "^" (when (equal (match-string 2) "~") "[ \t]*") |
| 3822 | qtag "$") | ||
| 3823 | stop-point 'toend) | ||
| 3823 | ;;;(eq (following-char) ?\n) ; XXXX WHY??? | 3824 | ;;;(eq (following-char) ?\n) ; XXXX WHY??? |
| 3824 | ) | 3825 | ) |
| 3825 | (progn ; Pretend we matched at the end | 3826 | (progn ; Pretend we matched at the end |
| @@ -5752,7 +5753,7 @@ indentation and initial hashes. Behaves usually outside of comment." | |||
| 5752 | (if (eq (char-after (match-beginning 2)) ?%) | 5753 | (if (eq (char-after (match-beginning 2)) ?%) |
| 5753 | 'cperl-hash-face | 5754 | 'cperl-hash-face |
| 5754 | 'cperl-array-face) | 5755 | 'cperl-array-face) |
| 5755 | t) ; arrays and hashes | 5756 | nil) ; arrays and hashes |
| 5756 | ("\\(\\([$@]+\\)[a-zA-Z_:][a-zA-Z0-9_:]*\\)[ \t]*\\([[{]\\)" | 5757 | ("\\(\\([$@]+\\)[a-zA-Z_:][a-zA-Z0-9_:]*\\)[ \t]*\\([[{]\\)" |
| 5757 | 1 | 5758 | 1 |
| 5758 | (if (= (- (match-end 2) (match-beginning 2)) 1) | 5759 | (if (= (- (match-end 2) (match-beginning 2)) 1) |
| @@ -6499,9 +6500,10 @@ If optional argument ALL is `recursive', will process Perl files | |||
| 6499 | in subdirectories too." | 6500 | in subdirectories too." |
| 6500 | (interactive) | 6501 | (interactive) |
| 6501 | (let ((cmd "etags") | 6502 | (let ((cmd "etags") |
| 6502 | (args '("-l" "none" "-r" | 6503 | (args `("-l" "none" "-r" |
| 6503 | ;; 1=fullname 2=package? 3=name 4=proto? 5=attrs? (VERY APPROX!) | 6504 | ;; 1=fullname 2=package? 3=name 4=proto? 5=attrs? (VERY APPROX!) |
| 6504 | "/\\<" cperl-sub-regexp "[ \\t]+\\(\\([a-zA-Z0-9:_]*::\\)?\\([a-zA-Z0-9_]+\\)\\)[ \\t]*\\(([^()]*)[ \t]*\\)?\\([ \t]*:[^#{;]*\\)?\\([{#]\\|$\\)/\\3/" | 6505 | ,(concat |
| 6506 | "/\\<" cperl-sub-regexp "[ \\t]+\\(\\([a-zA-Z0-9:_]*::\\)?\\([a-zA-Z0-9_]+\\)\\)[ \\t]*\\(([^()]*)[ \t]*\\)?\\([ \t]*:[^#{;]*\\)?\\([{#]\\|$\\)/\\3/") | ||
| 6505 | "-r" | 6507 | "-r" |
| 6506 | "/\\<package[ \\t]+\\(\\([a-zA-Z0-9:_]*::\\)?\\([a-zA-Z0-9_]+\\)\\)[ \\t]*\\([#;]\\|$\\)/\\1/" | 6508 | "/\\<package[ \\t]+\\(\\([a-zA-Z0-9:_]*::\\)?\\([a-zA-Z0-9_]+\\)\\)[ \\t]*\\([#;]\\|$\\)/\\1/" |
| 6507 | "-r" | 6509 | "-r" |
| @@ -6786,6 +6788,7 @@ Use as | |||
| 6786 | (or topdir | 6788 | (or topdir |
| 6787 | (setq topdir default-directory)) | 6789 | (setq topdir default-directory)) |
| 6788 | (let ((tags-file-name "TAGS") | 6790 | (let ((tags-file-name "TAGS") |
| 6791 | (inhibit-read-only t) | ||
| 6789 | (case-fold-search nil) | 6792 | (case-fold-search nil) |
| 6790 | xs rel) | 6793 | xs rel) |
| 6791 | (save-excursion | 6794 | (save-excursion |
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 51b9347bb93..b6161351f0b 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el | |||
| @@ -1166,7 +1166,9 @@ Save the result in `project-list-file' if the list of projects has changed." | |||
| 1166 | (project--ensure-read-project-list) | 1166 | (project--ensure-read-project-list) |
| 1167 | (let ((dir (project-root pr))) | 1167 | (let ((dir (project-root pr))) |
| 1168 | (unless (equal (caar project--list) dir) | 1168 | (unless (equal (caar project--list) dir) |
| 1169 | (setq project--list (assoc-delete-all dir project--list)) | 1169 | (dolist (ent project--list) |
| 1170 | (when (equal dir (car ent)) | ||
| 1171 | (setq project--list (delq ent project--list)))) | ||
| 1170 | (push (list dir) project--list) | 1172 | (push (list dir) project--list) |
| 1171 | (project--write-project-list)))) | 1173 | (project--write-project-list)))) |
| 1172 | 1174 | ||
| @@ -1176,8 +1178,8 @@ If the directory was in the list before the removal, save the | |||
| 1176 | result in `project-list-file'. Announce the project's removal | 1178 | result in `project-list-file'. Announce the project's removal |
| 1177 | from the list." | 1179 | from the list." |
| 1178 | (project--ensure-read-project-list) | 1180 | (project--ensure-read-project-list) |
| 1179 | (when (assoc pr-dir project--list) | 1181 | (when-let ((ent (assoc pr-dir project--list))) |
| 1180 | (setq project--list (assoc-delete-all pr-dir project--list)) | 1182 | (setq project--list (delq ent project--list)) |
| 1181 | (message "Project `%s' not found; removed from list" pr-dir) | 1183 | (message "Project `%s' not found; removed from list" pr-dir) |
| 1182 | (project--write-project-list))) | 1184 | (project--write-project-list))) |
| 1183 | 1185 | ||
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index 044d7820ee3..5a47594878e 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el | |||
| @@ -838,7 +838,7 @@ See `sh-feature'.") | |||
| 838 | font-lock-variable-name-face)) | 838 | font-lock-variable-name-face)) |
| 839 | 839 | ||
| 840 | (rc sh-append es) | 840 | (rc sh-append es) |
| 841 | (bash sh-append sh ("\\$(\\(\\sw+\\)" (1 'sh-quoted-exec t) )) | 841 | (bash sh-append sh ("\\$(\\([^)\n]+\\)" (1 'sh-quoted-exec t) )) |
| 842 | (sh sh-append shell | 842 | (sh sh-append shell |
| 843 | ;; Variable names. | 843 | ;; Variable names. |
| 844 | ("\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\)" 2 | 844 | ("\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\)" 2 |
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el index c86fc59ac16..a70b5ed60d6 100644 --- a/lisp/progmodes/sql.el +++ b/lisp/progmodes/sql.el | |||
| @@ -1508,6 +1508,22 @@ Based on `comint-mode-map'.") | |||
| 1508 | table) | 1508 | table) |
| 1509 | "Syntax table used in `sql-mode' and `sql-interactive-mode'.") | 1509 | "Syntax table used in `sql-mode' and `sql-interactive-mode'.") |
| 1510 | 1510 | ||
| 1511 | ;;; Syntax Properties | ||
| 1512 | |||
| 1513 | ;; `sql--syntax-propertize-escaped-apostrophe', as follows, was | ||
| 1514 | ;; (analysed and) adapted from `pascal--syntax-propertize' in | ||
| 1515 | ;; pascal.el because basic syntax parsing cannot handle the SQL '' | ||
| 1516 | ;; construct within strings. | ||
| 1517 | |||
| 1518 | (defconst sql--syntax-propertize-escaped-apostrophe | ||
| 1519 | (syntax-propertize-rules | ||
| 1520 | ("''" | ||
| 1521 | (0 | ||
| 1522 | (if (save-excursion (nth 3 (syntax-ppss (match-beginning 0)))) | ||
| 1523 | (string-to-syntax ".") | ||
| 1524 | (forward-char -1) | ||
| 1525 | nil))))) | ||
| 1526 | |||
| 1511 | ;; Font lock support | 1527 | ;; Font lock support |
| 1512 | 1528 | ||
| 1513 | (defvar sql-mode-font-lock-object-name | 1529 | (defvar sql-mode-font-lock-object-name |
| @@ -4210,6 +4226,10 @@ must tell Emacs. Here's how to do that in your init file: | |||
| 4210 | (setq-local abbrev-all-caps 1) | 4226 | (setq-local abbrev-all-caps 1) |
| 4211 | ;; Contains the name of database objects | 4227 | ;; Contains the name of database objects |
| 4212 | (set (make-local-variable 'sql-contains-names) t) | 4228 | (set (make-local-variable 'sql-contains-names) t) |
| 4229 | ;; Activate punctuation syntax table property for | ||
| 4230 | ;; escaped apostrophes within strings: | ||
| 4231 | (setq-local syntax-propertize-function | ||
| 4232 | sql--syntax-propertize-escaped-apostrophe) | ||
| 4213 | ;; Set syntax and font-face highlighting | 4233 | ;; Set syntax and font-face highlighting |
| 4214 | ;; Catch changes to sql-product and highlight accordingly | 4234 | ;; Catch changes to sql-product and highlight accordingly |
| 4215 | (sql-set-product (or sql-product 'ansi)) ; Fixes bug#13591 | 4235 | (sql-set-product (or sql-product 'ansi)) ; Fixes bug#13591 |
diff --git a/lisp/recentf.el b/lisp/recentf.el index 27918a9739c..877edd4be1f 100644 --- a/lisp/recentf.el +++ b/lisp/recentf.el | |||
| @@ -1289,7 +1289,8 @@ Write data into the file specified by `recentf-save-file'." | |||
| 1289 | (insert "\n\n;; Local Variables:\n" | 1289 | (insert "\n\n;; Local Variables:\n" |
| 1290 | (format ";; coding: %s\n" recentf-save-file-coding-system) | 1290 | (format ";; coding: %s\n" recentf-save-file-coding-system) |
| 1291 | ";; End:\n") | 1291 | ";; End:\n") |
| 1292 | (write-file (expand-file-name recentf-save-file)) | 1292 | (write-region (point-min) (point-max) |
| 1293 | (expand-file-name recentf-save-file)) | ||
| 1293 | (when recentf-save-file-modes | 1294 | (when recentf-save-file-modes |
| 1294 | (set-file-modes recentf-save-file recentf-save-file-modes)) | 1295 | (set-file-modes recentf-save-file recentf-save-file-modes)) |
| 1295 | nil) | 1296 | nil) |
diff --git a/lisp/saveplace.el b/lisp/saveplace.el index 46738ab03dc..d420bfb4e9f 100644 --- a/lisp/saveplace.el +++ b/lisp/saveplace.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; saveplace.el --- automatically save place in files | 1 | ;;; saveplace.el --- automatically save place in files -*- lexical-binding:t -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 1993-1994, 2001-2020 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 1993-1994, 2001-2020 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -42,7 +42,6 @@ | |||
| 42 | "Automatically save place in files." | 42 | "Automatically save place in files." |
| 43 | :group 'data) | 43 | :group 'data) |
| 44 | 44 | ||
| 45 | |||
| 46 | (defvar save-place-alist nil | 45 | (defvar save-place-alist nil |
| 47 | "Alist of saved places to go back to when revisiting files. | 46 | "Alist of saved places to go back to when revisiting files. |
| 48 | Each element looks like (FILENAME . POSITION); | 47 | Each element looks like (FILENAME . POSITION); |
| @@ -175,10 +174,11 @@ file: | |||
| 175 | (declare-function dired-get-filename "dired" (&optional localp no-error-if-not-filep)) | 174 | (declare-function dired-get-filename "dired" (&optional localp no-error-if-not-filep)) |
| 176 | 175 | ||
| 177 | (defun save-place-to-alist () | 176 | (defun save-place-to-alist () |
| 178 | ;; put filename and point in a cons box and then cons that onto the | 177 | "Add current buffer filename and position to `save-place-alist'. |
| 179 | ;; front of the save-place-alist, if save-place-mode is non-nil. | 178 | Put filename and point in a cons box and then cons that onto the |
| 180 | ;; Otherwise, just delete that file from the alist. | 179 | front of the `save-place-alist', if `save-place-mode' is non-nil. |
| 181 | ;; first check to make sure alist has been loaded in from the master | 180 | Otherwise, just delete that file from the alist." |
| 181 | ;; First check to make sure alist has been loaded in from the master | ||
| 182 | ;; file. If not, do so, then feel free to modify the alist. It | 182 | ;; file. If not, do so, then feel free to modify the alist. It |
| 183 | ;; will be saved again when Emacs is killed. | 183 | ;; will be saved again when Emacs is killed. |
| 184 | (or save-place-loaded (load-save-place-alist-from-file)) | 184 | (or save-place-loaded (load-save-place-alist-from-file)) |
diff --git a/lisp/scroll-lock.el b/lisp/scroll-lock.el index 3a6d9d36429..f20ea1bcc87 100644 --- a/lisp/scroll-lock.el +++ b/lisp/scroll-lock.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; scroll-lock.el --- Scroll lock scrolling. | 1 | ;;; scroll-lock.el --- Scroll lock scrolling. -*- lexical-binding:t -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2005-2020 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2005-2020 Free Software Foundation, Inc. |
| 4 | 4 | ||
diff --git a/lisp/simple.el b/lisp/simple.el index 2f92238e640..6c9584aaa39 100644 --- a/lisp/simple.el +++ b/lisp/simple.el | |||
| @@ -3369,6 +3369,14 @@ which is defined in the `warnings' library.\n") | |||
| 3369 | (setq buffer-undo-list nil) | 3369 | (setq buffer-undo-list nil) |
| 3370 | t)) | 3370 | t)) |
| 3371 | 3371 | ||
| 3372 | ;;;; Shell commands | ||
| 3373 | |||
| 3374 | (defconst shell-command-buffer-name "*Shell Command Output*" | ||
| 3375 | "Name of the output buffer for shell commands.") | ||
| 3376 | |||
| 3377 | (defconst shell-command-buffer-name-async "*Async Shell Command*" | ||
| 3378 | "Name of the output buffer for asynchronous shell commands.") | ||
| 3379 | |||
| 3372 | (defvar shell-command-history nil | 3380 | (defvar shell-command-history nil |
| 3373 | "History list for some commands that read shell commands. | 3381 | "History list for some commands that read shell commands. |
| 3374 | 3382 | ||
| @@ -3433,7 +3441,7 @@ to `shell-command-history'." | |||
| 3433 | (defcustom async-shell-command-buffer 'confirm-new-buffer | 3441 | (defcustom async-shell-command-buffer 'confirm-new-buffer |
| 3434 | "What to do when the output buffer is used by another shell command. | 3442 | "What to do when the output buffer is used by another shell command. |
| 3435 | This option specifies how to resolve the conflict where a new command | 3443 | This option specifies how to resolve the conflict where a new command |
| 3436 | wants to direct its output to the buffer `*Async Shell Command*', | 3444 | wants to direct its output to the buffer `shell-command-buffer-name-async', |
| 3437 | but this buffer is already taken by another running shell command. | 3445 | but this buffer is already taken by another running shell command. |
| 3438 | 3446 | ||
| 3439 | The value `confirm-kill-process' is used to ask for confirmation before | 3447 | The value `confirm-kill-process' is used to ask for confirmation before |
| @@ -3585,14 +3593,14 @@ whose `car' is BUFFER." | |||
| 3585 | Like `shell-command', but adds `&' at the end of COMMAND | 3593 | Like `shell-command', but adds `&' at the end of COMMAND |
| 3586 | to execute it asynchronously. | 3594 | to execute it asynchronously. |
| 3587 | 3595 | ||
| 3588 | The output appears in the buffer `*Async Shell Command*'. | 3596 | The output appears in the buffer `shell-command-buffer-name-async'. |
| 3589 | That buffer is in shell mode. | 3597 | That buffer is in shell mode. |
| 3590 | 3598 | ||
| 3591 | You can configure `async-shell-command-buffer' to specify what to do | 3599 | You can configure `async-shell-command-buffer' to specify what to do |
| 3592 | when the `*Async Shell Command*' buffer is already taken by another | 3600 | when the `shell-command-buffer-name-async' buffer is already taken by another |
| 3593 | running shell command. To run COMMAND without displaying the output | 3601 | running shell command. To run COMMAND without displaying the output |
| 3594 | in a window you can configure `display-buffer-alist' to use the action | 3602 | in a window you can configure `display-buffer-alist' to use the action |
| 3595 | `display-buffer-no-window' for the buffer `*Async Shell Command*'. | 3603 | `display-buffer-no-window' for the buffer `shell-command-buffer-name-async'. |
| 3596 | 3604 | ||
| 3597 | In Elisp, you will often be better served by calling `start-process' | 3605 | In Elisp, you will often be better served by calling `start-process' |
| 3598 | directly, since it offers more control and does not impose the use of | 3606 | directly, since it offers more control and does not impose the use of |
| @@ -3628,12 +3636,12 @@ If `shell-command-prompt-show-cwd' is non-nil, show the current | |||
| 3628 | directory in the prompt. | 3636 | directory in the prompt. |
| 3629 | 3637 | ||
| 3630 | If COMMAND ends in `&', execute it asynchronously. | 3638 | If COMMAND ends in `&', execute it asynchronously. |
| 3631 | The output appears in the buffer `*Async Shell Command*'. | 3639 | The output appears in the buffer `shell-command-buffer-name-async'. |
| 3632 | That buffer is in shell mode. You can also use | 3640 | That buffer is in shell mode. You can also use |
| 3633 | `async-shell-command' that automatically adds `&'. | 3641 | `async-shell-command' that automatically adds `&'. |
| 3634 | 3642 | ||
| 3635 | Otherwise, COMMAND is executed synchronously. The output appears in | 3643 | Otherwise, COMMAND is executed synchronously. The output appears in |
| 3636 | the buffer `*Shell Command Output*'. If the output is short enough to | 3644 | the buffer `shell-command-buffer-name'. If the output is short enough to |
| 3637 | display in the echo area (which is determined by the variables | 3645 | display in the echo area (which is determined by the variables |
| 3638 | `resize-mini-windows' and `max-mini-window-height'), it is shown | 3646 | `resize-mini-windows' and `max-mini-window-height'), it is shown |
| 3639 | there, but it is nonetheless available in buffer `*Shell Command | 3647 | there, but it is nonetheless available in buffer `*Shell Command |
| @@ -3756,7 +3764,7 @@ impose the use of a shell (with its need to quote arguments)." | |||
| 3756 | (if (string-match "[ \t]*&[ \t]*\\'" command) | 3764 | (if (string-match "[ \t]*&[ \t]*\\'" command) |
| 3757 | ;; Command ending with ampersand means asynchronous. | 3765 | ;; Command ending with ampersand means asynchronous. |
| 3758 | (let* ((buffer (get-buffer-create | 3766 | (let* ((buffer (get-buffer-create |
| 3759 | (or output-buffer "*Async Shell Command*"))) | 3767 | (or output-buffer shell-command-buffer-name-async))) |
| 3760 | (bname (buffer-name buffer)) | 3768 | (bname (buffer-name buffer)) |
| 3761 | (proc (get-buffer-process buffer)) | 3769 | (proc (get-buffer-process buffer)) |
| 3762 | (directory default-directory)) | 3770 | (directory default-directory)) |
| @@ -3908,7 +3916,7 @@ and are used only if a pop-up buffer is displayed." | |||
| 3908 | error-buffer display-error-buffer | 3916 | error-buffer display-error-buffer |
| 3909 | region-noncontiguous-p) | 3917 | region-noncontiguous-p) |
| 3910 | "Execute string COMMAND in inferior shell with region as input. | 3918 | "Execute string COMMAND in inferior shell with region as input. |
| 3911 | Normally display output (if any) in temp buffer `*Shell Command Output*'; | 3919 | Normally display output (if any) in temp buffer `shell-command-buffer-name'; |
| 3912 | Prefix arg means replace the region with it. Return the exit code of | 3920 | Prefix arg means replace the region with it. Return the exit code of |
| 3913 | COMMAND. | 3921 | COMMAND. |
| 3914 | 3922 | ||
| @@ -3927,7 +3935,7 @@ in the echo area or in a buffer. | |||
| 3927 | If the output is short enough to display in the echo area | 3935 | If the output is short enough to display in the echo area |
| 3928 | \(determined by the variable `max-mini-window-height' if | 3936 | \(determined by the variable `max-mini-window-height' if |
| 3929 | `resize-mini-windows' is non-nil), it is shown there. | 3937 | `resize-mini-windows' is non-nil), it is shown there. |
| 3930 | Otherwise it is displayed in the buffer `*Shell Command Output*'. | 3938 | Otherwise it is displayed in the buffer `shell-command-buffer-name'. |
| 3931 | The output is available in that buffer in both cases. | 3939 | The output is available in that buffer in both cases. |
| 3932 | 3940 | ||
| 3933 | If there is output and an error, a message about the error | 3941 | If there is output and an error, a message about the error |
| @@ -3937,7 +3945,7 @@ Optional fourth arg OUTPUT-BUFFER specifies where to put the | |||
| 3937 | command's output. If the value is a buffer or buffer name, | 3945 | command's output. If the value is a buffer or buffer name, |
| 3938 | erase that buffer and insert the output there; a non-nil value of | 3946 | erase that buffer and insert the output there; a non-nil value of |
| 3939 | `shell-command-dont-erase-buffer' prevent to erase the buffer. | 3947 | `shell-command-dont-erase-buffer' prevent to erase the buffer. |
| 3940 | If the value is nil, use the buffer `*Shell Command Output*'. | 3948 | If the value is nil, use the buffer `shell-command-buffer-name'. |
| 3941 | Any other non-nil value means to insert the output in the | 3949 | Any other non-nil value means to insert the output in the |
| 3942 | current buffer after START. | 3950 | current buffer after START. |
| 3943 | 3951 | ||
| @@ -4006,7 +4014,7 @@ characters." | |||
| 4006 | (funcall region-insert-function output)) | 4014 | (funcall region-insert-function output)) |
| 4007 | (t | 4015 | (t |
| 4008 | (let ((buffer (get-buffer-create | 4016 | (let ((buffer (get-buffer-create |
| 4009 | (or output-buffer "*Shell Command Output*")))) | 4017 | (or output-buffer shell-command-buffer-name)))) |
| 4010 | (with-current-buffer buffer | 4018 | (with-current-buffer buffer |
| 4011 | (erase-buffer) | 4019 | (erase-buffer) |
| 4012 | (funcall region-insert-function output)) | 4020 | (funcall region-insert-function output)) |
| @@ -4025,7 +4033,7 @@ characters." | |||
| 4025 | (list t error-file) | 4033 | (list t error-file) |
| 4026 | t))) | 4034 | t))) |
| 4027 | ;; It is rude to delete a buffer that the command is not using. | 4035 | ;; It is rude to delete a buffer that the command is not using. |
| 4028 | ;; (let ((shell-buffer (get-buffer "*Shell Command Output*"))) | 4036 | ;; (let ((shell-buffer (get-buffer shell-command-buffer-name))) |
| 4029 | ;; (and shell-buffer (not (eq shell-buffer (current-buffer))) | 4037 | ;; (and shell-buffer (not (eq shell-buffer (current-buffer))) |
| 4030 | ;; (kill-buffer shell-buffer))) | 4038 | ;; (kill-buffer shell-buffer))) |
| 4031 | ;; Don't muck with mark unless REPLACE says we should. | 4039 | ;; Don't muck with mark unless REPLACE says we should. |
| @@ -4033,12 +4041,13 @@ characters." | |||
| 4033 | ;; No prefix argument: put the output in a temp buffer, | 4041 | ;; No prefix argument: put the output in a temp buffer, |
| 4034 | ;; replacing its entire contents. | 4042 | ;; replacing its entire contents. |
| 4035 | (let ((buffer (get-buffer-create | 4043 | (let ((buffer (get-buffer-create |
| 4036 | (or output-buffer "*Shell Command Output*")))) | 4044 | (or output-buffer shell-command-buffer-name)))) |
| 4037 | (set-buffer-major-mode buffer) ; Enable globalized modes (bug#38111) | 4045 | (set-buffer-major-mode buffer) ; Enable globalized modes (bug#38111) |
| 4038 | (unwind-protect | 4046 | (unwind-protect |
| 4039 | (if (and (eq buffer (current-buffer)) | 4047 | (if (and (eq buffer (current-buffer)) |
| 4040 | (or (memq shell-command-dont-erase-buffer '(nil erase)) | 4048 | (or (memq shell-command-dont-erase-buffer '(nil erase)) |
| 4041 | (and (not (eq buffer (get-buffer "*Shell Command Output*"))) | 4049 | (and (not (eq buffer (get-buffer |
| 4050 | shell-command-buffer-name))) | ||
| 4042 | (not (region-active-p))))) | 4051 | (not (region-active-p))))) |
| 4043 | ;; If the input is the same buffer as the output, | 4052 | ;; If the input is the same buffer as the output, |
| 4044 | ;; delete everything but the specified region, | 4053 | ;; delete everything but the specified region, |
diff --git a/lisp/skeleton.el b/lisp/skeleton.el index 8c694c128b5..ea4e5dbc227 100644 --- a/lisp/skeleton.el +++ b/lisp/skeleton.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; skeleton.el --- Lisp language extension for writing statement skeletons | 1 | ;;; skeleton.el --- Lisp language extension for writing statement skeletons -*- lexical-binding: t; -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 1993-1996, 2001-2020 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 1993-1996, 2001-2020 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -135,7 +135,8 @@ A prefix argument of -1 says to wrap around region, even if not highlighted. | |||
| 135 | A prefix argument of zero says to wrap around zero words---that is, nothing. | 135 | A prefix argument of zero says to wrap around zero words---that is, nothing. |
| 136 | This is a way of overriding the use of a highlighted region.") | 136 | This is a way of overriding the use of a highlighted region.") |
| 137 | (interactive "*P\nP") | 137 | (interactive "*P\nP") |
| 138 | (skeleton-proxy-new ',skeleton str arg)))) | 138 | (atomic-change-group |
| 139 | (skeleton-proxy-new ',skeleton str arg))))) | ||
| 139 | 140 | ||
| 140 | ;;;###autoload | 141 | ;;;###autoload |
| 141 | (defun skeleton-proxy-new (skeleton &optional str arg) | 142 | (defun skeleton-proxy-new (skeleton &optional str arg) |
| @@ -154,8 +155,7 @@ of `str' whereas the skeleton's interactor is then ignored." | |||
| 154 | (prefix-numeric-value (or arg | 155 | (prefix-numeric-value (or arg |
| 155 | current-prefix-arg)) | 156 | current-prefix-arg)) |
| 156 | (and skeleton-autowrap | 157 | (and skeleton-autowrap |
| 157 | (or (eq last-command 'mouse-drag-region) | 158 | (use-region-p) |
| 158 | (and transient-mark-mode mark-active)) | ||
| 159 | ;; Deactivate the mark, in case one of the | 159 | ;; Deactivate the mark, in case one of the |
| 160 | ;; elements of the skeleton is sensitive | 160 | ;; elements of the skeleton is sensitive |
| 161 | ;; to such situations (e.g. it is itself a | 161 | ;; to such situations (e.g. it is itself a |
| @@ -258,23 +258,25 @@ available: | |||
| 258 | (goto-char (car skeleton-regions)) | 258 | (goto-char (car skeleton-regions)) |
| 259 | (setq skeleton-regions (cdr skeleton-regions))) | 259 | (setq skeleton-regions (cdr skeleton-regions))) |
| 260 | (let ((beg (point)) | 260 | (let ((beg (point)) |
| 261 | skeleton-modified skeleton-point resume: help input v1 v2) | 261 | skeleton-modified skeleton-point) ;; resume: |
| 262 | (setq skeleton-positions nil) | 262 | (with-suppressed-warnings ((lexical help input v1 v2)) |
| 263 | (unwind-protect | 263 | (dlet (help input v1 v2) |
| 264 | (cl-progv | 264 | (setq skeleton-positions nil) |
| 265 | (mapcar #'car skeleton-further-elements) | 265 | (unwind-protect |
| 266 | (mapcar (lambda (x) (eval (cadr x))) skeleton-further-elements) | 266 | (cl-progv |
| 267 | (skeleton-internal-list skeleton str)) | 267 | (mapcar #'car skeleton-further-elements) |
| 268 | (or (eolp) (not skeleton-end-newline) (newline-and-indent)) | 268 | (mapcar (lambda (x) (eval (cadr x) t)) skeleton-further-elements) |
| 269 | (run-hooks 'skeleton-end-hook) | 269 | (skeleton-internal-list skeleton str)) |
| 270 | (sit-for 0) | 270 | (or (eolp) (not skeleton-end-newline) (newline-and-indent)) |
| 271 | (or (not (eq (window-buffer) (current-buffer))) | 271 | (run-hooks 'skeleton-end-hook) |
| 272 | (pos-visible-in-window-p beg) | 272 | (sit-for 0) |
| 273 | (progn | 273 | (or (not (eq (window-buffer) (current-buffer))) |
| 274 | (goto-char beg) | 274 | (pos-visible-in-window-p beg) |
| 275 | (recenter 0))) | 275 | (progn |
| 276 | (if skeleton-point | 276 | (goto-char beg) |
| 277 | (goto-char skeleton-point)))))) | 277 | (recenter 0))) |
| 278 | (if skeleton-point | ||
| 279 | (goto-char skeleton-point)))))))) | ||
| 278 | 280 | ||
| 279 | (defun skeleton-read (prompt &optional initial-input recursive) | 281 | (defun skeleton-read (prompt &optional initial-input recursive) |
| 280 | "Function for reading a string from the minibuffer within skeletons. | 282 | "Function for reading a string from the minibuffer within skeletons. |
| @@ -327,36 +329,39 @@ automatically, and you are prompted to fill in the variable parts."))) | |||
| 327 | (signal 'quit t) | 329 | (signal 'quit t) |
| 328 | prompt)) | 330 | prompt)) |
| 329 | 331 | ||
| 330 | (defun skeleton-internal-list (skeleton-il &optional str recursive) | 332 | (defun skeleton-internal-list (skeleton &optional str recursive) |
| 331 | (let* ((start (line-beginning-position)) | 333 | (let* ((start (line-beginning-position)) |
| 332 | (column (current-column)) | 334 | (column (current-column)) |
| 333 | (line (buffer-substring start (line-end-position))) | 335 | (line (buffer-substring start (line-end-position))) |
| 334 | opoint) | 336 | (skeleton-il skeleton) |
| 335 | (or str | 337 | opoint) |
| 336 | (setq str `(setq str | 338 | (with-suppressed-warnings ((lexical str)) |
| 337 | (skeleton-read ',(car skeleton-il) nil ,recursive)))) | 339 | (dlet ((str (or str |
| 338 | (when (and (eq (cadr skeleton-il) '\n) (not recursive) | 340 | `(setq str |
| 339 | (save-excursion (skip-chars-backward " \t") (bolp))) | 341 | (skeleton-read ',(car skeleton-il) |
| 340 | (setq skeleton-il (cons nil (cons '> (cddr skeleton-il))))) | 342 | nil ,recursive))))) |
| 341 | (while (setq skeleton-modified (eq opoint (point)) | 343 | (when (and (eq (cadr skeleton-il) '\n) (not recursive) |
| 342 | opoint (point) | 344 | (save-excursion (skip-chars-backward " \t") (bolp))) |
| 343 | skeleton-il (cdr skeleton-il)) | 345 | (setq skeleton-il (cons nil (cons '> (cddr skeleton-il))))) |
| 344 | (condition-case quit | 346 | (while (setq skeleton-modified (eq opoint (point)) |
| 345 | (skeleton-internal-1 (car skeleton-il) nil recursive) | 347 | opoint (point) |
| 346 | (quit | 348 | skeleton-il (cdr skeleton-il)) |
| 347 | (if (eq (cdr quit) 'recursive) | 349 | (condition-case quit |
| 348 | (setq recursive 'quit | 350 | (skeleton-internal-1 (car skeleton-il) nil recursive) |
| 349 | skeleton-il (memq 'resume: skeleton-il)) | 351 | (quit |
| 350 | ;; Remove the subskeleton as far as it has been shown | 352 | (if (eq (cdr quit) 'recursive) |
| 351 | ;; the subskeleton shouldn't have deleted outside current line. | 353 | (setq recursive 'quit |
| 352 | (end-of-line) | 354 | skeleton-il (memq 'resume: skeleton-il)) |
| 353 | (delete-region start (point)) | 355 | ;; Remove the subskeleton as far as it has been shown |
| 354 | (insert line) | 356 | ;; the subskeleton shouldn't have deleted outside current line. |
| 355 | (move-to-column column) | 357 | (end-of-line) |
| 356 | (if (cdr quit) | 358 | (delete-region start (point)) |
| 357 | (setq skeleton-il () | 359 | (insert line) |
| 358 | recursive nil) | 360 | (move-to-column column) |
| 359 | (signal 'quit 'recursive))))))) | 361 | (if (cdr quit) |
| 362 | (setq skeleton-il () | ||
| 363 | recursive nil) | ||
| 364 | (signal 'quit 'recursive))))))))) | ||
| 360 | ;; maybe continue loop or go on to next outer resume: section | 365 | ;; maybe continue loop or go on to next outer resume: section |
| 361 | (if (eq recursive 'quit) | 366 | (if (eq recursive 'quit) |
| 362 | (signal 'quit 'recursive) | 367 | (signal 'quit 'recursive) |
diff --git a/lisp/so-long.el b/lisp/so-long.el index 6b05f4821b1..f2c078ba841 100644 --- a/lisp/so-long.el +++ b/lisp/so-long.el | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | ;; compacted into the smallest file size possible, which often entails removing | 38 | ;; compacted into the smallest file size possible, which often entails removing |
| 39 | ;; newlines should they not be strictly necessary). This can result in lines | 39 | ;; newlines should they not be strictly necessary). This can result in lines |
| 40 | ;; which are many thousands of characters long, and most programming modes | 40 | ;; which are many thousands of characters long, and most programming modes |
| 41 | ;; simply aren't optimized (remotely) for this scenario, so performance can | 41 | ;; simply aren't optimised (remotely) for this scenario, so performance can |
| 42 | ;; suffer significantly. | 42 | ;; suffer significantly. |
| 43 | ;; | 43 | ;; |
| 44 | ;; When such files are detected, the command `so-long' is automatically called, | 44 | ;; When such files are detected, the command `so-long' is automatically called, |
| @@ -69,7 +69,7 @@ | |||
| 69 | ;; the long lines. In such circumstances you may find that `longlines-mode' is | 69 | ;; the long lines. In such circumstances you may find that `longlines-mode' is |
| 70 | ;; the most helpful facility. | 70 | ;; the most helpful facility. |
| 71 | ;; | 71 | ;; |
| 72 | ;; Note also that the mitigation is automatically triggered when visiting a | 72 | ;; Note also that the mitigations are automatically triggered when visiting a |
| 73 | ;; file. The library does not automatically detect if long lines are inserted | 73 | ;; file. The library does not automatically detect if long lines are inserted |
| 74 | ;; into an existing buffer (although the `so-long' command can be invoked | 74 | ;; into an existing buffer (although the `so-long' command can be invoked |
| 75 | ;; manually in such situations). | 75 | ;; manually in such situations). |
| @@ -90,7 +90,7 @@ | |||
| 90 | ;; * Overview of modes and commands | 90 | ;; * Overview of modes and commands |
| 91 | ;; -------------------------------- | 91 | ;; -------------------------------- |
| 92 | ;; - `global-so-long-mode' - A global minor mode which enables the automated | 92 | ;; - `global-so-long-mode' - A global minor mode which enables the automated |
| 93 | ;; behavior, causing the user's preferred action to be invoked whenever a | 93 | ;; behaviour, causing the user's preferred action to be invoked whenever a |
| 94 | ;; newly-visited file contains excessively long lines. | 94 | ;; newly-visited file contains excessively long lines. |
| 95 | ;; - `so-long-mode' - A major mode, and the default action. | 95 | ;; - `so-long-mode' - A major mode, and the default action. |
| 96 | ;; - `so-long-minor-mode' - A minor mode version of the major mode, and an | 96 | ;; - `so-long-minor-mode' - A minor mode version of the major mode, and an |
| @@ -111,7 +111,7 @@ | |||
| 111 | ;; | 111 | ;; |
| 112 | ;; On rare occasions you may choose to manually invoke the `so-long' command, | 112 | ;; On rare occasions you may choose to manually invoke the `so-long' command, |
| 113 | ;; which invokes your preferred `so-long-action' (exactly as the automatic | 113 | ;; which invokes your preferred `so-long-action' (exactly as the automatic |
| 114 | ;; behavior would do if it had detected long lines). You might use this if a | 114 | ;; behaviour would do if it had detected long lines). You might use this if a |
| 115 | ;; problematic file did not meet your configured criteria, and you wished to | 115 | ;; problematic file did not meet your configured criteria, and you wished to |
| 116 | ;; trigger the performance improvements manually. | 116 | ;; trigger the performance improvements manually. |
| 117 | ;; | 117 | ;; |
| @@ -120,7 +120,7 @@ | |||
| 120 | ;; available to `so-long' but, like any other mode, they can be invoked directly | 120 | ;; available to `so-long' but, like any other mode, they can be invoked directly |
| 121 | ;; if you have a need to do that (see also "Other ways of using so-long" below). | 121 | ;; if you have a need to do that (see also "Other ways of using so-long" below). |
| 122 | ;; | 122 | ;; |
| 123 | ;; If the behavior ever triggers when you did not want it to, you can use the | 123 | ;; If the behaviour ever triggers when you did not want it to, you can use the |
| 124 | ;; `so-long-revert' command to restore the buffer to its original state. | 124 | ;; `so-long-revert' command to restore the buffer to its original state. |
| 125 | 125 | ||
| 126 | ;; * Basic configuration | 126 | ;; * Basic configuration |
| @@ -199,7 +199,7 @@ | |||
| 199 | ;; | 199 | ;; |
| 200 | ;; Note that `so-long-minor-modes' is not useful for other global minor modes | 200 | ;; Note that `so-long-minor-modes' is not useful for other global minor modes |
| 201 | ;; (as distinguished from globalized minor modes), but in some cases it will be | 201 | ;; (as distinguished from globalized minor modes), but in some cases it will be |
| 202 | ;; possible to inhibit or otherwise counter-act the behavior of a global mode | 202 | ;; possible to inhibit or otherwise counter-act the behaviour of a global mode |
| 203 | ;; by overriding variables, or by employing hooks (see below). You would need | 203 | ;; by overriding variables, or by employing hooks (see below). You would need |
| 204 | ;; to inspect the code for a given global mode (on a case by case basis) to | 204 | ;; to inspect the code for a given global mode (on a case by case basis) to |
| 205 | ;; determine whether it's possible to inhibit it for a single buffer -- and if | 205 | ;; determine whether it's possible to inhibit it for a single buffer -- and if |
| @@ -211,7 +211,7 @@ | |||
| 211 | ;; If `so-long-action' is set to either `so-long-mode' or `so-long-minor-mode', | 211 | ;; If `so-long-action' is set to either `so-long-mode' or `so-long-minor-mode', |
| 212 | ;; the buffer-local value for each variable in the list is set to the associated | 212 | ;; the buffer-local value for each variable in the list is set to the associated |
| 213 | ;; value in the alist. Use this to enforce values which will improve | 213 | ;; value in the alist. Use this to enforce values which will improve |
| 214 | ;; performance or otherwise avoid undesirable behaviors. If `so-long-revert' | 214 | ;; performance or otherwise avoid undesirable behaviours. If `so-long-revert' |
| 215 | ;; is called, then the original values are restored. | 215 | ;; is called, then the original values are restored. |
| 216 | 216 | ||
| 217 | ;; * Hooks | 217 | ;; * Hooks |
| @@ -325,7 +325,7 @@ | |||
| 325 | ;; meaning you would need to add to `safe-local-variable-values' in order to | 325 | ;; meaning you would need to add to `safe-local-variable-values' in order to |
| 326 | ;; avoid being queried about them. | 326 | ;; avoid being queried about them. |
| 327 | ;; | 327 | ;; |
| 328 | ;; Finally, the `so-long-predicate' user option enables the automated behavior | 328 | ;; Finally, the `so-long-predicate' user option enables the automated behaviour |
| 329 | ;; to be determined by a custom function, if greater control is needed. | 329 | ;; to be determined by a custom function, if greater control is needed. |
| 330 | 330 | ||
| 331 | ;; * Implementation notes | 331 | ;; * Implementation notes |
| @@ -342,7 +342,7 @@ | |||
| 342 | 342 | ||
| 343 | ;; * Caveats | 343 | ;; * Caveats |
| 344 | ;; --------- | 344 | ;; --------- |
| 345 | ;; The variables affecting the automated behavior of this library (such as | 345 | ;; The variables affecting the automated behaviour of this library (such as |
| 346 | ;; `so-long-action') can be used as file- or dir-local values in Emacs 26+, but | 346 | ;; `so-long-action') can be used as file- or dir-local values in Emacs 26+, but |
| 347 | ;; not in previous versions of Emacs. This is on account of improvements made | 347 | ;; not in previous versions of Emacs. This is on account of improvements made |
| 348 | ;; to `normal-mode' in 26.1, which altered the execution order with respect to | 348 | ;; to `normal-mode' in 26.1, which altered the execution order with respect to |
| @@ -386,7 +386,7 @@ | |||
| 386 | ;; - Added sgml-mode and nxml-mode to `so-long-target-modes'. | 386 | ;; - Added sgml-mode and nxml-mode to `so-long-target-modes'. |
| 387 | ;; 0.7.4 - Refactored the handling of `whitespace-mode'. | 387 | ;; 0.7.4 - Refactored the handling of `whitespace-mode'. |
| 388 | ;; 0.7.3 - Added customize group `so-long' with user options. | 388 | ;; 0.7.3 - Added customize group `so-long' with user options. |
| 389 | ;; - Added `so-long-original-values' to generalize the storage and | 389 | ;; - Added `so-long-original-values' to generalise the storage and |
| 390 | ;; restoration of values from the original mode upon `so-long-revert'. | 390 | ;; restoration of values from the original mode upon `so-long-revert'. |
| 391 | ;; - Added `so-long-revert-hook'. | 391 | ;; - Added `so-long-revert-hook'. |
| 392 | ;; 0.7.2 - Remember the original major mode even with M-x `so-long-mode'. | 392 | ;; 0.7.2 - Remember the original major mode even with M-x `so-long-mode'. |
| @@ -399,7 +399,7 @@ | |||
| 399 | ;; 0.6 - Added `so-long-minor-modes' and `so-long-hook'. | 399 | ;; 0.6 - Added `so-long-minor-modes' and `so-long-hook'. |
| 400 | ;; 0.5 - Renamed library to "so-long.el". | 400 | ;; 0.5 - Renamed library to "so-long.el". |
| 401 | ;; - Added explicit `so-long-enable' command to activate our advice. | 401 | ;; - Added explicit `so-long-enable' command to activate our advice. |
| 402 | ;; 0.4 - Amended/documented behavior with file-local 'mode' variables. | 402 | ;; 0.4 - Amended/documented behaviour with file-local 'mode' variables. |
| 403 | ;; 0.3 - Defer to a file-local 'mode' variable. | 403 | ;; 0.3 - Defer to a file-local 'mode' variable. |
| 404 | ;; 0.2 - Initial release to EmacsWiki. | 404 | ;; 0.2 - Initial release to EmacsWiki. |
| 405 | ;; 0.1 - Experimental. | 405 | ;; 0.1 - Experimental. |
| @@ -421,7 +421,7 @@ | |||
| 421 | Has no effect if `global-so-long-mode' is not enabled.") | 421 | Has no effect if `global-so-long-mode' is not enabled.") |
| 422 | 422 | ||
| 423 | (defvar-local so-long--active nil ; internal use | 423 | (defvar-local so-long--active nil ; internal use |
| 424 | "Non-nil when `so-long' mitigation is in effect.") | 424 | "Non-nil when `so-long' mitigations are in effect.") |
| 425 | 425 | ||
| 426 | (defvar so-long--set-auto-mode nil ; internal use | 426 | (defvar so-long--set-auto-mode nil ; internal use |
| 427 | "Non-nil while `set-auto-mode' is executing.") | 427 | "Non-nil while `set-auto-mode' is executing.") |
| @@ -500,7 +500,7 @@ files would prevent Emacs from handling them correctly." | |||
| 500 | (defcustom so-long-invisible-buffer-function #'so-long-deferred | 500 | (defcustom so-long-invisible-buffer-function #'so-long-deferred |
| 501 | "Function called in place of `so-long' when the buffer is not displayed. | 501 | "Function called in place of `so-long' when the buffer is not displayed. |
| 502 | 502 | ||
| 503 | This affects the behavior of `global-so-long-mode'. | 503 | This affects the behaviour of `global-so-long-mode'. |
| 504 | 504 | ||
| 505 | We treat invisible buffers differently from displayed buffers because, in | 505 | We treat invisible buffers differently from displayed buffers because, in |
| 506 | cases where a library is using a buffer for behind-the-scenes processing, | 506 | cases where a library is using a buffer for behind-the-scenes processing, |
| @@ -548,7 +548,7 @@ Defaults to `so-long-detected-long-line-p'." | |||
| 548 | (defun so-long--action-type () | 548 | (defun so-long--action-type () |
| 549 | "Generate a :type for `so-long-action' based on `so-long-action-alist'." | 549 | "Generate a :type for `so-long-action' based on `so-long-action-alist'." |
| 550 | ;; :type seemingly cannot be a form to be evaluated on demand, so we | 550 | ;; :type seemingly cannot be a form to be evaluated on demand, so we |
| 551 | ;; endeavor to keep it up-to-date with `so-long-action-alist' by | 551 | ;; endeavour to keep it up-to-date with `so-long-action-alist' by |
| 552 | ;; calling this from `so-long--action-alist-setter'. | 552 | ;; calling this from `so-long--action-alist-setter'. |
| 553 | `(radio ,@(mapcar (lambda (x) (list 'const :tag (cadr x) (car x))) | 553 | `(radio ,@(mapcar (lambda (x) (list 'const :tag (cadr x) (car x))) |
| 554 | (assq-delete-all nil so-long-action-alist)) | 554 | (assq-delete-all nil so-long-action-alist)) |
| @@ -609,7 +609,7 @@ will be automatically processed; but custom actions can also do these things. | |||
| 609 | The value `longlines-mode' causes that minor mode to be enabled. See | 609 | The value `longlines-mode' causes that minor mode to be enabled. See |
| 610 | longlines.el for more details. | 610 | longlines.el for more details. |
| 611 | 611 | ||
| 612 | Each action likewise determines the behavior of `so-long-revert'. | 612 | Each action likewise determines the behaviour of `so-long-revert'. |
| 613 | 613 | ||
| 614 | If the value is nil, or not defined in `so-long-action-alist', then no action | 614 | If the value is nil, or not defined in `so-long-action-alist', then no action |
| 615 | will be taken." | 615 | will be taken." |
| @@ -740,7 +740,7 @@ was established." | |||
| 740 | ) | 740 | ) |
| 741 | ;; It's not clear to me whether all of these would be problematic, but they | 741 | ;; It's not clear to me whether all of these would be problematic, but they |
| 742 | ;; seemed like reasonable targets. Some are certainly excessive in smaller | 742 | ;; seemed like reasonable targets. Some are certainly excessive in smaller |
| 743 | ;; buffers of minified code, but we should be aiming to maximize performance | 743 | ;; buffers of minified code, but we should be aiming to maximise performance |
| 744 | ;; by default, so that Emacs is as responsive as we can manage in even very | 744 | ;; by default, so that Emacs is as responsive as we can manage in even very |
| 745 | ;; large buffers of minified code. | 745 | ;; large buffers of minified code. |
| 746 | "List of buffer-local minor modes to explicitly disable. | 746 | "List of buffer-local minor modes to explicitly disable. |
| @@ -756,7 +756,7 @@ By default this happens if `so-long-action' is set to either `so-long-mode' | |||
| 756 | or `so-long-minor-mode'. If `so-long-revert' is subsequently invoked, then the | 756 | or `so-long-minor-mode'. If `so-long-revert' is subsequently invoked, then the |
| 757 | disabled modes are re-enabled by calling them with the numeric argument 1. | 757 | disabled modes are re-enabled by calling them with the numeric argument 1. |
| 758 | 758 | ||
| 759 | `so-long-hook' can be used where more custom behavior is desired. | 759 | `so-long-hook' can be used where more custom behaviour is desired. |
| 760 | 760 | ||
| 761 | Please submit bug reports to recommend additional modes for this list, whether | 761 | Please submit bug reports to recommend additional modes for this list, whether |
| 762 | they are in Emacs core, GNU ELPA, or elsewhere." | 762 | they are in Emacs core, GNU ELPA, or elsewhere." |
| @@ -781,9 +781,20 @@ If `so-long-revert' is subsequently invoked, then the variables are restored | |||
| 781 | to their original states. | 781 | to their original states. |
| 782 | 782 | ||
| 783 | The combination of `line-move-visual' (enabled) and `truncate-lines' (disabled) | 783 | The combination of `line-move-visual' (enabled) and `truncate-lines' (disabled) |
| 784 | is important for maximizing responsiveness when moving vertically within an | 784 | is important for maximising responsiveness when moving vertically within an |
| 785 | extremely long line, as otherwise the full length of the line may need to be | 785 | extremely long line, as otherwise the full length of the line may need to be |
| 786 | scanned to find the next position." | 786 | scanned to find the next position. |
| 787 | |||
| 788 | Bidirectional text display -- especially handling the large quantities of | ||
| 789 | nested parentheses which are liable to occur in minified programming code -- | ||
| 790 | can be very expensive for extremely long lines, and so this support is disabled | ||
| 791 | by default (insofar as is supported; in particular `bidi-inhibit-bpa' is not | ||
| 792 | available in Emacs versions < 27). For more information refer to info node | ||
| 793 | `(emacs) Bidirectional Editing' and info node `(elisp) Bidirectional Display'. | ||
| 794 | |||
| 795 | Buffers are made read-only by default to prevent potentially-slow editing from | ||
| 796 | occurring inadvertantly, as buffers with excessively long lines are likely not | ||
| 797 | intended to be edited manually." | ||
| 787 | :type '(alist :key-type (variable :tag "Variable") | 798 | :type '(alist :key-type (variable :tag "Variable") |
| 788 | :value-type (sexp :tag "Value")) | 799 | :value-type (sexp :tag "Value")) |
| 789 | :options '((bidi-inhibit-bpa boolean) | 800 | :options '((bidi-inhibit-bpa boolean) |
| @@ -822,18 +833,18 @@ If nil, no mode line indicator will be displayed." | |||
| 822 | 833 | ||
| 823 | (defface so-long-mode-line-active | 834 | (defface so-long-mode-line-active |
| 824 | '((t :inherit mode-line-emphasis)) | 835 | '((t :inherit mode-line-emphasis)) |
| 825 | "Face for `so-long-mode-line-info' when mitigation is active." | 836 | "Face for `so-long-mode-line-info' when mitigations are active." |
| 826 | :package-version '(so-long . "1.0")) | 837 | :package-version '(so-long . "1.0")) |
| 827 | 838 | ||
| 828 | (defface so-long-mode-line-inactive | 839 | (defface so-long-mode-line-inactive |
| 829 | '((t :inherit mode-line-inactive)) | 840 | '((t :inherit mode-line-inactive)) |
| 830 | "Face for `so-long-mode-line-info' when mitigation has been reverted." | 841 | "Face for `so-long-mode-line-info' when mitigations have been reverted." |
| 831 | :package-version '(so-long . "1.0")) | 842 | :package-version '(so-long . "1.0")) |
| 832 | 843 | ||
| 833 | ;; Modes that go slowly and line lengths excessive | 844 | ;; Modes that go slowly and line lengths excessive |
| 834 | ;; Font-lock performance becoming oppressive | 845 | ;; Font-lock performance becoming oppressive |
| 835 | ;; All of my CPU tied up with strings | 846 | ;; All of my CPU tied up with strings |
| 836 | ;; These are a few of my least-favorite things | 847 | ;; These are a few of my least-favourite things |
| 837 | 848 | ||
| 838 | (defvar-local so-long-original-values nil | 849 | (defvar-local so-long-original-values nil |
| 839 | "Alist holding the buffer's original `major-mode' value, and other data. | 850 | "Alist holding the buffer's original `major-mode' value, and other data. |
| @@ -985,7 +996,7 @@ Displayed as part of `mode-line-misc-info'. | |||
| 985 | 996 | ||
| 986 | `so-long-mode-line-label' defines the text to be displayed (if any). | 997 | `so-long-mode-line-label' defines the text to be displayed (if any). |
| 987 | 998 | ||
| 988 | Face `so-long-mode-line-active' is used while mitigation is active, and | 999 | Face `so-long-mode-line-active' is used while mitigations are active, and |
| 989 | `so-long-mode-line-inactive' is used if `so-long-revert' is called. | 1000 | `so-long-mode-line-inactive' is used if `so-long-revert' is called. |
| 990 | 1001 | ||
| 991 | Not displayed when `so-long-mode' is enabled, as the major mode construct | 1002 | Not displayed when `so-long-mode' is enabled, as the major mode construct |
| @@ -1038,7 +1049,9 @@ This is the default value of `so-long-predicate'." | |||
| 1038 | (let ((count 0) start) | 1049 | (let ((count 0) start) |
| 1039 | (save-excursion | 1050 | (save-excursion |
| 1040 | (goto-char (point-min)) | 1051 | (goto-char (point-min)) |
| 1041 | (when so-long-skip-leading-comments | 1052 | (when (and so-long-skip-leading-comments |
| 1053 | (or comment-use-syntax ;; Refer to `comment-forward'. | ||
| 1054 | (and comment-start-skip comment-end-skip))) | ||
| 1042 | ;; Skip the shebang line, if any. This is not necessarily comment | 1055 | ;; Skip the shebang line, if any. This is not necessarily comment |
| 1043 | ;; syntax, so we need to treat it specially. | 1056 | ;; syntax, so we need to treat it specially. |
| 1044 | (when (looking-at "#!") | 1057 | (when (looking-at "#!") |
| @@ -1131,7 +1144,7 @@ This minor mode is a standard `so-long-action' option." | |||
| 1131 | (if so-long-minor-mode ;; We are enabling the mode. | 1144 | (if so-long-minor-mode ;; We are enabling the mode. |
| 1132 | (progn | 1145 | (progn |
| 1133 | ;; Housekeeping. `so-long-minor-mode' might be invoked directly rather | 1146 | ;; Housekeeping. `so-long-minor-mode' might be invoked directly rather |
| 1134 | ;; than via `so-long', so replicate the necessary behaviors. The minor | 1147 | ;; than via `so-long', so replicate the necessary behaviours. The minor |
| 1135 | ;; mode also cares about whether `so-long' was already active, as we do | 1148 | ;; mode also cares about whether `so-long' was already active, as we do |
| 1136 | ;; not want to remember values which were potentially overridden already. | 1149 | ;; not want to remember values which were potentially overridden already. |
| 1137 | (unless (or so-long--calling so-long--active) | 1150 | (unless (or so-long--calling so-long--active) |
| @@ -1203,9 +1216,9 @@ values), despite potential performance issues, type \\[so-long-revert]. | |||
| 1203 | 1216 | ||
| 1204 | Use \\[so-long-commentary] for more information. | 1217 | Use \\[so-long-commentary] for more information. |
| 1205 | 1218 | ||
| 1206 | Use \\[so-long-customize] to configure the behavior." | 1219 | Use \\[so-long-customize] to configure the behaviour." |
| 1207 | ;; Housekeeping. `so-long-mode' might be invoked directly rather than via | 1220 | ;; Housekeeping. `so-long-mode' might be invoked directly rather than via |
| 1208 | ;; `so-long', so replicate the necessary behaviors. We could use this same | 1221 | ;; `so-long', so replicate the necessary behaviours. We could use this same |
| 1209 | ;; test in `so-long-after-change-major-mode' to run `so-long-hook', but that's | 1222 | ;; test in `so-long-after-change-major-mode' to run `so-long-hook', but that's |
| 1210 | ;; not so obviously the right thing to do, so I've omitted it for now. | 1223 | ;; not so obviously the right thing to do, so I've omitted it for now. |
| 1211 | (unless so-long--calling | 1224 | (unless so-long--calling |
| @@ -1251,7 +1264,7 @@ Use \\[so-long-customize] to configure the behavior." | |||
| 1251 | This advice acts before `so-long-mode', with the previous mode still active." | 1264 | This advice acts before `so-long-mode', with the previous mode still active." |
| 1252 | (unless (derived-mode-p 'so-long-mode) | 1265 | (unless (derived-mode-p 'so-long-mode) |
| 1253 | ;; Housekeeping. `so-long-mode' might be invoked directly rather than | 1266 | ;; Housekeeping. `so-long-mode' might be invoked directly rather than |
| 1254 | ;; via `so-long', so replicate the necessary behaviors. | 1267 | ;; via `so-long', so replicate the necessary behaviours. |
| 1255 | (unless so-long--calling | 1268 | (unless so-long--calling |
| 1256 | (so-long-remember-all :reset)) | 1269 | (so-long-remember-all :reset)) |
| 1257 | ;; Remember the original major mode, regardless. | 1270 | ;; Remember the original major mode, regardless. |
| @@ -1336,7 +1349,7 @@ This is the `so-long-revert-function' for `so-long-mode'." | |||
| 1336 | ;; Emacs 26+ has already called `hack-local-variables' (during | 1349 | ;; Emacs 26+ has already called `hack-local-variables' (during |
| 1337 | ;; `run-mode-hooks'; provided there was a `buffer-file-name'), but for older | 1350 | ;; `run-mode-hooks'; provided there was a `buffer-file-name'), but for older |
| 1338 | ;; versions we need to call it here. In Emacs 26+ the revised 'HANDLE-MODE' | 1351 | ;; versions we need to call it here. In Emacs 26+ the revised 'HANDLE-MODE' |
| 1339 | ;; argument is set to `no-mode' (being the non-nil-and-non-t behavior), | 1352 | ;; argument is set to `no-mode' (being the non-nil-and-non-t behaviour), |
| 1340 | ;; which we mimic here by binding `so-long--hack-local-variables-no-mode', | 1353 | ;; which we mimic here by binding `so-long--hack-local-variables-no-mode', |
| 1341 | ;; in order to prevent a local 'mode' variable from clobbering the major | 1354 | ;; in order to prevent a local 'mode' variable from clobbering the major |
| 1342 | ;; mode we have just called. | 1355 | ;; mode we have just called. |
| @@ -1373,7 +1386,7 @@ because we do not want to downgrade the major mode in that scenario." | |||
| 1373 | ;; Act only if `so-long-mode' would be enabled by the current action. | 1386 | ;; Act only if `so-long-mode' would be enabled by the current action. |
| 1374 | (when (and (symbolp (so-long-function)) | 1387 | (when (and (symbolp (so-long-function)) |
| 1375 | (provided-mode-derived-p (so-long-function) 'so-long-mode)) | 1388 | (provided-mode-derived-p (so-long-function) 'so-long-mode)) |
| 1376 | ;; Downgrade from `so-long-mode' to the `so-long-minor-mode' behavior. | 1389 | ;; Downgrade from `so-long-mode' to the `so-long-minor-mode' behaviour. |
| 1377 | (setq so-long-function 'turn-on-so-long-minor-mode | 1390 | (setq so-long-function 'turn-on-so-long-minor-mode |
| 1378 | so-long-revert-function 'turn-off-so-long-minor-mode)))) | 1391 | so-long-revert-function 'turn-off-so-long-minor-mode)))) |
| 1379 | 1392 | ||
| @@ -1393,7 +1406,7 @@ and cannot be conveniently intercepted, so we are forced to replicate it here. | |||
| 1393 | 1406 | ||
| 1394 | This special-case code will ultimately be removed from Emacs, as it exists to | 1407 | This special-case code will ultimately be removed from Emacs, as it exists to |
| 1395 | deal with a deprecated feature; but until then we need to replicate it in order | 1408 | deal with a deprecated feature; but until then we need to replicate it in order |
| 1396 | to inhibit our own behavior in the presence of a header comment `mode' | 1409 | to inhibit our own behaviour in the presence of a header comment `mode' |
| 1397 | declaration. | 1410 | declaration. |
| 1398 | 1411 | ||
| 1399 | If a file-local mode is detected in the header comment, then we call the | 1412 | If a file-local mode is detected in the header comment, then we call the |
| @@ -1528,7 +1541,7 @@ by testing the value against `major-mode'; but as we may have changed the | |||
| 1528 | major mode to `so-long-mode' by this point, that protection is insufficient | 1541 | major mode to `so-long-mode' by this point, that protection is insufficient |
| 1529 | and so we need to perform our own test. | 1542 | and so we need to perform our own test. |
| 1530 | 1543 | ||
| 1531 | We likewise need to support an equivalent of the `no-mode' behavior in 26.1+ | 1544 | We likewise need to support an equivalent of the `no-mode' behaviour in 26.1+ |
| 1532 | to ensure that `so-long-mode-revert' will not restore a file-local mode again | 1545 | to ensure that `so-long-mode-revert' will not restore a file-local mode again |
| 1533 | after it has already reverted to the original mode. | 1546 | after it has already reverted to the original mode. |
| 1534 | 1547 | ||
| @@ -1661,7 +1674,7 @@ Equivalent to calling (global-so-long-mode 0)" | |||
| 1661 | 1674 | ||
| 1662 | ;;;###autoload | 1675 | ;;;###autoload |
| 1663 | (define-minor-mode global-so-long-mode | 1676 | (define-minor-mode global-so-long-mode |
| 1664 | "Toggle automated performance mitigation for files with long lines. | 1677 | "Toggle automated performance mitigations for files with long lines. |
| 1665 | 1678 | ||
| 1666 | Many Emacs modes struggle with buffers which contain excessively long lines, | 1679 | Many Emacs modes struggle with buffers which contain excessively long lines, |
| 1667 | and may consequently cause unacceptable performance issues. | 1680 | and may consequently cause unacceptable performance issues. |
| @@ -1675,7 +1688,7 @@ When such files are detected by `so-long-predicate', we invoke the selected | |||
| 1675 | 1688 | ||
| 1676 | Use \\[so-long-commentary] for more information. | 1689 | Use \\[so-long-commentary] for more information. |
| 1677 | 1690 | ||
| 1678 | Use \\[so-long-customize] to configure the behavior." | 1691 | Use \\[so-long-customize] to configure the behaviour." |
| 1679 | :global t | 1692 | :global t |
| 1680 | :group 'so-long | 1693 | :group 'so-long |
| 1681 | (if global-so-long-mode | 1694 | (if global-so-long-mode |
| @@ -1810,9 +1823,10 @@ If it appears in `%s', you should remove it." | |||
| 1810 | ;; Update to version 1.0 from earlier versions: | 1823 | ;; Update to version 1.0 from earlier versions: |
| 1811 | (when (version< so-long-version "1.0") | 1824 | (when (version< so-long-version "1.0") |
| 1812 | (remove-hook 'change-major-mode-hook 'so-long-change-major-mode) | 1825 | (remove-hook 'change-major-mode-hook 'so-long-change-major-mode) |
| 1813 | (require 'advice) | 1826 | (eval-and-compile (require 'advice)) ;; Both macros and functions. |
| 1814 | (declare-function ad-find-advice "advice") | 1827 | (declare-function ad-find-advice "advice") |
| 1815 | (declare-function ad-remove-advice "advice") | 1828 | (declare-function ad-remove-advice "advice") |
| 1829 | (declare-function ad-activate "advice") | ||
| 1816 | (when (ad-find-advice 'hack-local-variables 'after 'so-long--file-local-mode) | 1830 | (when (ad-find-advice 'hack-local-variables 'after 'so-long--file-local-mode) |
| 1817 | (ad-remove-advice 'hack-local-variables 'after 'so-long--file-local-mode) | 1831 | (ad-remove-advice 'hack-local-variables 'after 'so-long--file-local-mode) |
| 1818 | (ad-activate 'hack-local-variables)) | 1832 | (ad-activate 'hack-local-variables)) |
| @@ -1864,8 +1878,8 @@ If it appears in `%s', you should remove it." | |||
| 1864 | ; LocalWords: noerror selectable mapc sgml nxml hl flydiff defs arg Phil Sainty | 1878 | ; LocalWords: noerror selectable mapc sgml nxml hl flydiff defs arg Phil Sainty |
| 1865 | ; LocalWords: defadvice nadvice whitespace ie bos eos eobp origmode un Un setq | 1879 | ; LocalWords: defadvice nadvice whitespace ie bos eos eobp origmode un Un setq |
| 1866 | ; LocalWords: docstring auf Wiedersehen longlines alist autoload Refactored Inc | 1880 | ; LocalWords: docstring auf Wiedersehen longlines alist autoload Refactored Inc |
| 1867 | ; LocalWords: MERCHANTABILITY RET REGEXP VAR ELPA WS EmacsWiki eval | 1881 | ; LocalWords: MERCHANTABILITY RET REGEXP VAR ELPA WS mitigations EmacsWiki eval |
| 1868 | ; LocalWords: rx filename filenames | 1882 | ; LocalWords: rx filename filenames bidi bpa |
| 1869 | 1883 | ||
| 1870 | ;; So long, farewell, auf Wiedersehen, goodbye | 1884 | ;; So long, farewell, auf Wiedersehen, goodbye |
| 1871 | ;; You have to go, this code is minified | 1885 | ;; You have to go, this code is minified |
diff --git a/lisp/subr.el b/lisp/subr.el index 2ef28b1ce6a..0ae636b68b4 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -888,6 +888,10 @@ side-effects, and the argument LIST is not modified." | |||
| 888 | 888 | ||
| 889 | ;;;; Keymap support. | 889 | ;;;; Keymap support. |
| 890 | 890 | ||
| 891 | ;; Declare before first use of `save-match-data', | ||
| 892 | ;; where it is used internally. | ||
| 893 | (defvar save-match-data-internal) | ||
| 894 | |||
| 891 | (defun kbd (keys) | 895 | (defun kbd (keys) |
| 892 | "Convert KEYS to the internal Emacs key representation. | 896 | "Convert KEYS to the internal Emacs key representation. |
| 893 | KEYS should be a string in the format returned by commands such | 897 | KEYS should be a string in the format returned by commands such |
| @@ -4110,8 +4114,6 @@ MODES is as for `set-default-file-modes'." | |||
| 4110 | 4114 | ||
| 4111 | ;;; Matching and match data. | 4115 | ;;; Matching and match data. |
| 4112 | 4116 | ||
| 4113 | (defvar save-match-data-internal) | ||
| 4114 | |||
| 4115 | ;; We use save-match-data-internal as the local variable because | 4117 | ;; We use save-match-data-internal as the local variable because |
| 4116 | ;; that works ok in practice (people should not use that variable elsewhere). | 4118 | ;; that works ok in practice (people should not use that variable elsewhere). |
| 4117 | ;; We used to use an uninterned symbol; the compiler handles that properly | 4119 | ;; We used to use an uninterned symbol; the compiler handles that properly |
diff --git a/lisp/tar-mode.el b/lisp/tar-mode.el index 73978ffc4a7..5cf09f9055e 100644 --- a/lisp/tar-mode.el +++ b/lisp/tar-mode.el | |||
| @@ -922,6 +922,56 @@ actually appear on disk when you save the tar-file's buffer." | |||
| 922 | (setq buffer-undo-list nil)))) | 922 | (setq buffer-undo-list nil)))) |
| 923 | buffer)) | 923 | buffer)) |
| 924 | 924 | ||
| 925 | (defun tar-goto-file (file) | ||
| 926 | "Go to FILE in the current buffer. | ||
| 927 | FILE should be a relative file name. If FILE can't be found, | ||
| 928 | return nil. Otherwise point is returned." | ||
| 929 | (let ((start (point)) | ||
| 930 | found) | ||
| 931 | (goto-char (point-min)) | ||
| 932 | (while (and (not found) | ||
| 933 | (not (eobp))) | ||
| 934 | (forward-line 1) | ||
| 935 | (when-let ((descriptor (ignore-errors (tar-get-descriptor)))) | ||
| 936 | (when (equal (tar-header-name descriptor) file) | ||
| 937 | (setq found t)))) | ||
| 938 | (if (not found) | ||
| 939 | (progn | ||
| 940 | (goto-char start) | ||
| 941 | nil) | ||
| 942 | (point)))) | ||
| 943 | |||
| 944 | (defun tar-next-file-displayer (file regexp n) | ||
| 945 | "Return a closure to display the next file after FILE that matches REGEXP." | ||
| 946 | (let ((short (replace-regexp-in-string "\\`.*!" "" file)) | ||
| 947 | next) | ||
| 948 | ;; The tar buffer chops off leading "./", so do the same | ||
| 949 | ;; here. | ||
| 950 | (setq short (replace-regexp-in-string "\\`\\./" "" file)) | ||
| 951 | (tar-goto-file short) | ||
| 952 | (while (and (not next) | ||
| 953 | ;; Stop if we reach the end/start of the buffer. | ||
| 954 | (if (> n 0) | ||
| 955 | (not (eobp)) | ||
| 956 | (not (save-excursion | ||
| 957 | (beginning-of-line) | ||
| 958 | (bobp))))) | ||
| 959 | (tar-next-line n) | ||
| 960 | (when-let ((descriptor (ignore-errors (tar-get-descriptor)))) | ||
| 961 | (let ((candidate (tar-header-name descriptor)) | ||
| 962 | (buffer (current-buffer))) | ||
| 963 | (when (and candidate | ||
| 964 | (string-match-p regexp candidate)) | ||
| 965 | (setq next (lambda () | ||
| 966 | (kill-buffer (current-buffer)) | ||
| 967 | (switch-to-buffer buffer) | ||
| 968 | (tar-extract))))))) | ||
| 969 | (unless next | ||
| 970 | ;; If we didn't find a next/prev file, then restore | ||
| 971 | ;; point. | ||
| 972 | (tar-goto-file short)) | ||
| 973 | next)) | ||
| 974 | |||
| 925 | (defun tar-extract (&optional other-window-p) | 975 | (defun tar-extract (&optional other-window-p) |
| 926 | "In Tar mode, extract this entry of the tar file into its own buffer." | 976 | "In Tar mode, extract this entry of the tar file into its own buffer." |
| 927 | (interactive) | 977 | (interactive) |
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el index 2cd99787e8a..cc5879880c8 100644 --- a/lisp/textmodes/css-mode.el +++ b/lisp/textmodes/css-mode.el | |||
| @@ -67,7 +67,7 @@ | |||
| 67 | 67 | ||
| 68 | (defconst scss-at-ids | 68 | (defconst scss-at-ids |
| 69 | '("at-root" "content" "debug" "each" "else" "else if" "error" "extend" | 69 | '("at-root" "content" "debug" "each" "else" "else if" "error" "extend" |
| 70 | "for" "function" "if" "import" "include" "mixin" "return" "warn" | 70 | "for" "function" "if" "import" "include" "mixin" "return" "use" "warn" |
| 71 | "while") | 71 | "while") |
| 72 | "Additional identifiers that appear in the form @foo in SCSS.") | 72 | "Additional identifiers that appear in the form @foo in SCSS.") |
| 73 | 73 | ||
diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el index b5ff6a69671..1672dce4f23 100644 --- a/lisp/textmodes/sgml-mode.el +++ b/lisp/textmodes/sgml-mode.el | |||
| @@ -1806,6 +1806,7 @@ This takes effect when first loading the library.") | |||
| 1806 | (define-key map "\C-c\C-cc" 'html-checkboxes) | 1806 | (define-key map "\C-c\C-cc" 'html-checkboxes) |
| 1807 | (define-key map "\C-c\C-cl" 'html-list-item) | 1807 | (define-key map "\C-c\C-cl" 'html-list-item) |
| 1808 | (define-key map "\C-c\C-ch" 'html-href-anchor) | 1808 | (define-key map "\C-c\C-ch" 'html-href-anchor) |
| 1809 | (define-key map "\C-c\C-cf" 'html-href-anchor-file) | ||
| 1809 | (define-key map "\C-c\C-cn" 'html-name-anchor) | 1810 | (define-key map "\C-c\C-cn" 'html-name-anchor) |
| 1810 | (define-key map "\C-c\C-c#" 'html-id-anchor) | 1811 | (define-key map "\C-c\C-c#" 'html-id-anchor) |
| 1811 | (define-key map "\C-c\C-ci" 'html-image) | 1812 | (define-key map "\C-c\C-ci" 'html-image) |
| @@ -1818,6 +1819,7 @@ This takes effect when first loading the library.") | |||
| 1818 | (define-key map "\C-cc" 'html-checkboxes) | 1819 | (define-key map "\C-cc" 'html-checkboxes) |
| 1819 | (define-key map "\C-cl" 'html-list-item) | 1820 | (define-key map "\C-cl" 'html-list-item) |
| 1820 | (define-key map "\C-ch" 'html-href-anchor) | 1821 | (define-key map "\C-ch" 'html-href-anchor) |
| 1822 | (define-key map "\C-cf" 'html-href-anchor-file) | ||
| 1821 | (define-key map "\C-cn" 'html-name-anchor) | 1823 | (define-key map "\C-cn" 'html-name-anchor) |
| 1822 | (define-key map "\C-c#" 'html-id-anchor) | 1824 | (define-key map "\C-c#" 'html-id-anchor) |
| 1823 | (define-key map "\C-ci" 'html-image) | 1825 | (define-key map "\C-ci" 'html-image) |
| @@ -1845,7 +1847,8 @@ This takes effect when first loading the library.") | |||
| 1845 | (define-key menu-map "\n" '("Line Break" . html-line)) | 1847 | (define-key menu-map "\n" '("Line Break" . html-line)) |
| 1846 | (define-key menu-map "\r" '("Paragraph" . html-paragraph)) | 1848 | (define-key menu-map "\r" '("Paragraph" . html-paragraph)) |
| 1847 | (define-key menu-map "i" '("Image" . html-image)) | 1849 | (define-key menu-map "i" '("Image" . html-image)) |
| 1848 | (define-key menu-map "h" '("Href Anchor" . html-href-anchor)) | 1850 | (define-key menu-map "h" '("Href Anchor URL" . html-href-anchor)) |
| 1851 | (define-key menu-map "f" '("Href Anchor File" . html-href-anchor-file)) | ||
| 1849 | (define-key menu-map "n" '("Name Anchor" . html-name-anchor)) | 1852 | (define-key menu-map "n" '("Name Anchor" . html-name-anchor)) |
| 1850 | (define-key menu-map "#" '("ID Anchor" . html-id-anchor)) | 1853 | (define-key menu-map "#" '("ID Anchor" . html-id-anchor)) |
| 1851 | map) | 1854 | map) |
| @@ -2453,6 +2456,11 @@ HTML Autoview mode is a buffer-local minor mode for use with | |||
| 2453 | ;; '(setq input "http:") | 2456 | ;; '(setq input "http:") |
| 2454 | "<a href=\"" str "\">" _ "</a>") | 2457 | "<a href=\"" str "\">" _ "</a>") |
| 2455 | 2458 | ||
| 2459 | (define-skeleton html-href-anchor-file | ||
| 2460 | "HTML anchor tag with href attribute (from a local file)." | ||
| 2461 | (file-relative-name (read-file-name "File name: ") default-directory) | ||
| 2462 | "<a href=\"" str "\">" _ "</a>") | ||
| 2463 | |||
| 2456 | (define-skeleton html-name-anchor | 2464 | (define-skeleton html-name-anchor |
| 2457 | "HTML anchor tag with name attribute." | 2465 | "HTML anchor tag with name attribute." |
| 2458 | "Name: " | 2466 | "Name: " |
diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el index 1a15df33e50..483a2c9bd83 100644 --- a/lisp/thingatpt.el +++ b/lisp/thingatpt.el | |||
| @@ -334,7 +334,7 @@ the bounds of a possible ill-formed URI (one lacking a scheme)." | |||
| 334 | ;; may contain parentheses but may not contain spaces (RFC3986). | 334 | ;; may contain parentheses but may not contain spaces (RFC3986). |
| 335 | (let* ((allowed-chars "--:=&?$+@-Z_[:alpha:]~#,%;*()!'") | 335 | (let* ((allowed-chars "--:=&?$+@-Z_[:alpha:]~#,%;*()!'") |
| 336 | (skip-before "^[0-9a-zA-Z]") | 336 | (skip-before "^[0-9a-zA-Z]") |
| 337 | (skip-after ":;.,!?") | 337 | (skip-after ":;.,!?'") |
| 338 | (pt (point)) | 338 | (pt (point)) |
| 339 | (beg (save-excursion | 339 | (beg (save-excursion |
| 340 | (skip-chars-backward allowed-chars) | 340 | (skip-chars-backward allowed-chars) |
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el index 95ced7b8d09..cb0657e70a0 100644 --- a/lisp/vc/vc-hg.el +++ b/lisp/vc/vc-hg.el | |||
| @@ -186,6 +186,16 @@ highlighting the Log View buffer." | |||
| 186 | :group 'vc-hg | 186 | :group 'vc-hg |
| 187 | :version "24.5") | 187 | :version "24.5") |
| 188 | 188 | ||
| 189 | (defcustom vc-hg-create-bookmark t | ||
| 190 | "This controls whether `vc-create-tag' will create a bookmark or branch. | ||
| 191 | If nil, named branch will be created. | ||
| 192 | If t, bookmark will be created. | ||
| 193 | If `ask', you will be prompted for a branch type." | ||
| 194 | :type '(choice (const :tag "No" nil) | ||
| 195 | (const :tag "Yes" t) | ||
| 196 | (const :tag "Ask" ask)) | ||
| 197 | :version "28.1") | ||
| 198 | |||
| 189 | 199 | ||
| 190 | ;; Clear up the cache to force vc-call to check again and discover | 200 | ;; Clear up the cache to force vc-call to check again and discover |
| 191 | ;; new functions when we reload this file. | 201 | ;; new functions when we reload this file. |
| @@ -625,10 +635,18 @@ Optional arg REVISION is a revision to annotate from." | |||
| 625 | ;;; Tag system | 635 | ;;; Tag system |
| 626 | 636 | ||
| 627 | (defun vc-hg-create-tag (dir name branchp) | 637 | (defun vc-hg-create-tag (dir name branchp) |
| 628 | "Attach the tag NAME to the state of the working copy." | 638 | "Create tag NAME in repo in DIR. Create branch if BRANCHP. |
| 639 | Variable `vc-hg-create-bookmark' controls what kind of branch will be created." | ||
| 629 | (let ((default-directory dir)) | 640 | (let ((default-directory dir)) |
| 630 | (and (vc-hg-command nil 0 nil "status") | 641 | (vc-hg-command nil 0 nil |
| 631 | (vc-hg-command nil 0 nil (if branchp "bookmark" "tag") name)))) | 642 | (if branchp |
| 643 | (if (if (eq vc-hg-create-bookmark 'ask) | ||
| 644 | (yes-or-no-p "Create bookmark instead of branch? ") | ||
| 645 | vc-hg-create-bookmark) | ||
| 646 | "bookmark" | ||
| 647 | "branch") | ||
| 648 | "tag") | ||
| 649 | name))) | ||
| 632 | 650 | ||
| 633 | (defun vc-hg-retrieve-tag (dir name _update) | 651 | (defun vc-hg-retrieve-tag (dir name _update) |
| 634 | "Retrieve the version tagged by NAME of all registered files at or below DIR." | 652 | "Retrieve the version tagged by NAME of all registered files at or below DIR." |
| @@ -1366,25 +1384,28 @@ REV is the revision to check out into WORKFILE." | |||
| 1366 | (vc-run-delayed | 1384 | (vc-run-delayed |
| 1367 | (vc-hg-after-dir-status update-function))) | 1385 | (vc-hg-after-dir-status update-function))) |
| 1368 | 1386 | ||
| 1369 | (defun vc-hg-dir-extra-header (name &rest commands) | ||
| 1370 | (concat (propertize name 'face 'font-lock-type-face) | ||
| 1371 | (propertize | ||
| 1372 | (with-temp-buffer | ||
| 1373 | (apply 'vc-hg-command (current-buffer) 0 nil commands) | ||
| 1374 | (buffer-substring-no-properties (point-min) (1- (point-max)))) | ||
| 1375 | 'face 'font-lock-variable-name-face))) | ||
| 1376 | |||
| 1377 | (defun vc-hg-dir-extra-headers (dir) | 1387 | (defun vc-hg-dir-extra-headers (dir) |
| 1378 | "Generate extra status headers for a Mercurial tree." | 1388 | "Generate extra status headers for a repository in DIR. |
| 1389 | This runs the command \"hg summary\"." | ||
| 1379 | (let ((default-directory dir)) | 1390 | (let ((default-directory dir)) |
| 1380 | (concat | 1391 | (with-temp-buffer |
| 1381 | (vc-hg-dir-extra-header "Root : " "root") "\n" | 1392 | (vc-hg-command t 0 nil "summary") |
| 1382 | (vc-hg-dir-extra-header "Branch : " "id" "-b") "\n" | 1393 | (goto-char (point-min)) |
| 1383 | (vc-hg-dir-extra-header "Tags : " "id" "-t") ; "\n" | 1394 | (mapconcat |
| 1384 | ;; these change after each commit | 1395 | #'identity |
| 1385 | ;; (vc-hg-dir-extra-header "Local num : " "id" "-n") "\n" | 1396 | (let (result) |
| 1386 | ;; (vc-hg-dir-extra-header "Global id : " "id" "-i") | 1397 | (while (not (eobp)) |
| 1387 | ))) | 1398 | (push |
| 1399 | (let ((entry (if (looking-at "\\([^ ].*\\): \\(.*\\)") | ||
| 1400 | (cons (capitalize (match-string 1)) (match-string 2)) | ||
| 1401 | (cons "" (buffer-substring (point) (line-end-position)))))) | ||
| 1402 | (concat | ||
| 1403 | (propertize (format "%-11s: " (car entry)) 'face 'font-lock-type-face) | ||
| 1404 | (propertize (cdr entry) 'face 'font-lock-variable-name-face))) | ||
| 1405 | result) | ||
| 1406 | (forward-line)) | ||
| 1407 | (nreverse result)) | ||
| 1408 | "\n")))) | ||
| 1388 | 1409 | ||
| 1389 | (defun vc-hg-log-incoming (buffer remote-location) | 1410 | (defun vc-hg-log-incoming (buffer remote-location) |
| 1390 | (vc-setup-buffer buffer) | 1411 | (vc-setup-buffer buffer) |
diff --git a/lisp/wdired.el b/lisp/wdired.el index 768b8f597b4..b98becfafe7 100644 --- a/lisp/wdired.el +++ b/lisp/wdired.el | |||
| @@ -609,7 +609,10 @@ Optional arguments are ignored." | |||
| 609 | (defun wdired--restore-dired-filename-prop (beg end _len) | 609 | (defun wdired--restore-dired-filename-prop (beg end _len) |
| 610 | (save-match-data | 610 | (save-match-data |
| 611 | (save-excursion | 611 | (save-excursion |
| 612 | (let ((lep (line-end-position))) | 612 | (let ((lep (line-end-position)) |
| 613 | (used-F (dired-check-switches | ||
| 614 | dired-actual-switches | ||
| 615 | "F" "classify"))) | ||
| 613 | (beginning-of-line) | 616 | (beginning-of-line) |
| 614 | (when (re-search-forward | 617 | (when (re-search-forward |
| 615 | directory-listing-before-filename-regexp lep t) | 618 | directory-listing-before-filename-regexp lep t) |
| @@ -623,13 +626,17 @@ Optional arguments are ignored." | |||
| 623 | (and (re-search-backward | 626 | (and (re-search-backward |
| 624 | dired-permission-flags-regexp nil t) | 627 | dired-permission-flags-regexp nil t) |
| 625 | (looking-at "l") | 628 | (looking-at "l") |
| 626 | (search-forward " -> " lep t)) | 629 | ;; macOS and Ultrix adds "@" to the end |
| 630 | ;; of symlinks when using -F. | ||
| 631 | (if (and used-F | ||
| 632 | dired-ls-F-marks-symlinks) | ||
| 633 | (re-search-forward "@? -> " lep t) | ||
| 634 | (search-forward " -> " lep t))) | ||
| 627 | ;; When dired-listing-switches includes "F" | 635 | ;; When dired-listing-switches includes "F" |
| 628 | ;; or "classify", don't treat appended | 636 | ;; or "classify", don't treat appended |
| 629 | ;; indicator characters as part of the file | 637 | ;; indicator characters as part of the file |
| 630 | ;; name (bug#34915). | 638 | ;; name (bug#34915). |
| 631 | (and (dired-check-switches dired-actual-switches | 639 | (and used-F |
| 632 | "F" "classify") | ||
| 633 | (re-search-forward "[*/@|=>]$" lep t))) | 640 | (re-search-forward "[*/@|=>]$" lep t))) |
| 634 | (goto-char (match-beginning 0)) | 641 | (goto-char (match-beginning 0)) |
| 635 | lep)) | 642 | lep)) |
diff --git a/lisp/whitespace.el b/lisp/whitespace.el index 47434bf3d2e..42c4b61daff 100644 --- a/lisp/whitespace.el +++ b/lisp/whitespace.el | |||
| @@ -283,7 +283,8 @@ | |||
| 283 | '(face | 283 | '(face |
| 284 | tabs spaces trailing lines space-before-tab newline | 284 | tabs spaces trailing lines space-before-tab newline |
| 285 | indentation empty space-after-tab | 285 | indentation empty space-after-tab |
| 286 | space-mark tab-mark newline-mark) | 286 | space-mark tab-mark newline-mark |
| 287 | missing-newline-at-eof) | ||
| 287 | "Specify which kind of blank is visualized. | 288 | "Specify which kind of blank is visualized. |
| 288 | 289 | ||
| 289 | It's a list containing some or all of the following values: | 290 | It's a list containing some or all of the following values: |
| @@ -326,6 +327,11 @@ It's a list containing some or all of the following values: | |||
| 326 | It has effect only if `face' (see above) | 327 | It has effect only if `face' (see above) |
| 327 | is present in `whitespace-style'. | 328 | is present in `whitespace-style'. |
| 328 | 329 | ||
| 330 | missing-newline-at-eof Missing newline at the end of the file is | ||
| 331 | visualized via faces. | ||
| 332 | It has effect only if `face' (see above) | ||
| 333 | is present in `whitespace-style'. | ||
| 334 | |||
| 329 | empty empty lines at beginning and/or end of buffer | 335 | empty empty lines at beginning and/or end of buffer |
| 330 | are visualized via faces. | 336 | are visualized via faces. |
| 331 | It has effect only if `face' (see above) | 337 | It has effect only if `face' (see above) |
| @@ -586,6 +592,10 @@ line. Used when `whitespace-style' includes the value `indentation'.") | |||
| 586 | "Face used to visualize big indentation." | 592 | "Face used to visualize big indentation." |
| 587 | :group 'whitespace) | 593 | :group 'whitespace) |
| 588 | 594 | ||
| 595 | (defface whitespace-missing-newline-at-eof | ||
| 596 | '((((class mono)) :inverse-video t :weight bold :underline t) | ||
| 597 | (t :background "#d0d040" :foreground "black")) | ||
| 598 | "Face used to visualize missing newline at the end of the file.") | ||
| 589 | 599 | ||
| 590 | (defvar whitespace-empty 'whitespace-empty | 600 | (defvar whitespace-empty 'whitespace-empty |
| 591 | "Symbol face used to visualize empty lines at beginning and/or end of buffer. | 601 | "Symbol face used to visualize empty lines at beginning and/or end of buffer. |
| @@ -1700,6 +1710,8 @@ cleaning up these problems." | |||
| 1700 | (whitespace-space-after-tab-regexp 'tab)) | 1710 | (whitespace-space-after-tab-regexp 'tab)) |
| 1701 | ((eq (car option) 'space-after-tab::space) | 1711 | ((eq (car option) 'space-after-tab::space) |
| 1702 | (whitespace-space-after-tab-regexp 'space)) | 1712 | (whitespace-space-after-tab-regexp 'space)) |
| 1713 | ((eq (car option) 'missing-newline-at-eof) | ||
| 1714 | "[^\n]\\'") | ||
| 1703 | (t | 1715 | (t |
| 1704 | (cdr option))))) | 1716 | (cdr option))))) |
| 1705 | (when (re-search-forward regexp rend t) | 1717 | (when (re-search-forward regexp rend t) |
| @@ -2122,7 +2134,16 @@ resultant list will be returned." | |||
| 2122 | ((memq 'space-after-tab::space whitespace-active-style) | 2134 | ((memq 'space-after-tab::space whitespace-active-style) |
| 2123 | ;; Show SPACEs after TAB (TABs). | 2135 | ;; Show SPACEs after TAB (TABs). |
| 2124 | (whitespace-space-after-tab-regexp 'space))) | 2136 | (whitespace-space-after-tab-regexp 'space))) |
| 2125 | 1 whitespace-space-after-tab t))))) | 2137 | 1 whitespace-space-after-tab t))) |
| 2138 | ,@(when (memq 'missing-newline-at-eof whitespace-active-style) | ||
| 2139 | ;; Show missing newline. | ||
| 2140 | `(("[^\n]\\'" 0 | ||
| 2141 | ;; Don't mark the end of the buffer is point is there -- | ||
| 2142 | ;; it probably means that the user is typing something | ||
| 2143 | ;; at the end of the buffer. | ||
| 2144 | (and (/= whitespace-point (point-max)) | ||
| 2145 | 'whitespace-missing-newline-at-eof) | ||
| 2146 | t))))) | ||
| 2126 | (font-lock-add-keywords nil whitespace-font-lock-keywords t) | 2147 | (font-lock-add-keywords nil whitespace-font-lock-keywords t) |
| 2127 | (font-lock-flush))) | 2148 | (font-lock-flush))) |
| 2128 | 2149 | ||
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el index 284fd1d6cbd..ea7e266e0d0 100644 --- a/lisp/wid-edit.el +++ b/lisp/wid-edit.el | |||
| @@ -577,6 +577,63 @@ respectively." | |||
| 577 | (if (and widget (funcall function widget maparg)) | 577 | (if (and widget (funcall function widget maparg)) |
| 578 | (setq overlays nil))))) | 578 | (setq overlays nil))))) |
| 579 | 579 | ||
| 580 | (defun widget-describe (&optional widget-or-pos) | ||
| 581 | "Describe the widget at point. | ||
| 582 | Displays a buffer with information about the widget (e.g., its actions) as well | ||
| 583 | as a link to browse all the properties of the widget. | ||
| 584 | |||
| 585 | This command resolves the indirection of widgets running the action of its | ||
| 586 | parents, so the real action executed can be known. | ||
| 587 | |||
| 588 | When called from Lisp, pass WIDGET-OR-POS as the widget to describe, | ||
| 589 | or a buffer position where a widget is present. If WIDGET-OR-POS is nil, | ||
| 590 | the widget at point is the widget to describe." | ||
| 591 | (interactive "d") | ||
| 592 | (require 'wid-browse) ; The widget-browse widget. | ||
| 593 | (let ((widget (if (widgetp widget-or-pos) | ||
| 594 | widget-or-pos | ||
| 595 | (widget-at widget-or-pos))) | ||
| 596 | props) | ||
| 597 | (when widget | ||
| 598 | (help-setup-xref (list #'widget-describe widget) | ||
| 599 | (called-interactively-p 'interactive)) | ||
| 600 | (setq props (list (cons 'action (widget--resolve-parent-action widget)) | ||
| 601 | (cons 'mouse-down-action | ||
| 602 | (widget-get widget :mouse-down-action)))) | ||
| 603 | (with-help-window (help-buffer) | ||
| 604 | (with-current-buffer (help-buffer) | ||
| 605 | (widget-insert "This widget's type is ") | ||
| 606 | (widget-create 'widget-browse :format "%[%v%]\n%d" | ||
| 607 | :doc (get (car widget) 'widget-documentation) | ||
| 608 | :help-echo "Browse this widget's properties" | ||
| 609 | widget) | ||
| 610 | (dolist (action '(action mouse-down-action)) | ||
| 611 | (let ((name (symbol-name action)) | ||
| 612 | (val (alist-get action props))) | ||
| 613 | (when (functionp val) | ||
| 614 | (widget-insert "\n\n" (propertize (capitalize name) 'face 'bold) | ||
| 615 | "'\nThe " name " of this widget is") | ||
| 616 | (if (symbolp val) | ||
| 617 | (progn (widget-insert " ") | ||
| 618 | (widget-create 'function-link :value val | ||
| 619 | :button-prefix "" :button-suffix "" | ||
| 620 | :help-echo "Describe this function")) | ||
| 621 | (widget-insert "\n") | ||
| 622 | (princ val))))))) | ||
| 623 | (widget-setup) | ||
| 624 | t))) | ||
| 625 | |||
| 626 | (defun widget--resolve-parent-action (widget) | ||
| 627 | "Resolve the real action of WIDGET up its inheritance chain. | ||
| 628 | Follow the WIDGET's parents, until its :action is no longer | ||
| 629 | `widget-parent-action', and return its value." | ||
| 630 | (let ((action (widget-get widget :action)) | ||
| 631 | (parent (widget-get widget :parent))) | ||
| 632 | (while (eq action 'widget-parent-action) | ||
| 633 | (setq parent (widget-get parent :parent) | ||
| 634 | action (widget-get parent :action))) | ||
| 635 | action)) | ||
| 636 | |||
| 580 | ;;; Images. | 637 | ;;; Images. |
| 581 | 638 | ||
| 582 | (defcustom widget-image-directory (file-name-as-directory | 639 | (defcustom widget-image-directory (file-name-as-directory |
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el index b22af5cc770..1d49f462531 100644 --- a/lisp/x-dnd.el +++ b/lisp/x-dnd.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; x-dnd.el --- drag and drop support for X | 1 | ;;; x-dnd.el --- drag and drop support for X -*- lexical-binding: t; -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2004-2020 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2004-2020 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -32,7 +32,7 @@ | |||
| 32 | (require 'dnd) | 32 | (require 'dnd) |
| 33 | 33 | ||
| 34 | ;;; Customizable variables | 34 | ;;; Customizable variables |
| 35 | (defcustom x-dnd-test-function 'x-dnd-default-test-function | 35 | (defcustom x-dnd-test-function #'x-dnd-default-test-function |
| 36 | "The function drag and drop uses to determine if to accept or reject a drop. | 36 | "The function drag and drop uses to determine if to accept or reject a drop. |
| 37 | The function takes three arguments, WINDOW, ACTION and TYPES. | 37 | The function takes three arguments, WINDOW, ACTION and TYPES. |
| 38 | WINDOW is where the mouse is when the function is called. WINDOW may be a | 38 | WINDOW is where the mouse is when the function is called. WINDOW may be a |