diff --git a/CHANGELOG.org b/CHANGELOG.org index f135c35..d2b6484 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -1,4 +1,30 @@ * Release 0.200.x +** 0.200.13 (2018/01/25) +*** Fixes +- Remove =ess-R-object-popup= from =ess= layer (thanks to NGaffney) +- Remove =wolfram-mode= package from =extra-langs= (thanks to bennofs) +- Import =info+.el= as local package +- Import =help-fns+.el= as local package +- Import =hide-comnt.el= as local package +- core: fix not found packages with =dotspacemacs-install-packages= all +** 0.200.12 (2018/01/23) +*** Fixes +- Use HTTPS instead of HTTP for ORG ELPA repository (thanks to aaronjensen) +** 0.200.11 (2018/01/22) +*** Fixes +- Fix =helm= display function (thanks to jackkamm) +- Fix =anaconda-mode= variable names in Python layer (thanks to nixmaniack) +- Fix typo in =helm-cscope-find-calling-this-function= (thanks to dubnde) +- Use =org=mime= package from MELPA (thanks to jackkamm) +- Replace broken =helm-spotify= package by =helm-spotify-plus= (thanks to leezu) +- Update =Quelpa= library +- Backport up to date list of themes in core and themes-megapack layer. +- Fix =pyim= package name in Chinese layer (thanks to James Wang) +** 0.200.10 (2017/11/01) +*** Fixes +- Fix error: (void-variable helm-bookmark-map) when selecting a candidate from + a Helm buffer (thanks to bmag) +- Fix window number assignation for Neotree buffer window (thanks to duianto) ** 0.200.9 (2017/04/06) *** Fixes - Fix theme loading with terminal Emacs (thanks to wang0z) diff --git a/core/core-configuration-layer.el b/core/core-configuration-layer.el index 4eb089d..4e373e5 100644 --- a/core/core-configuration-layer.el +++ b/core/core-configuration-layer.el @@ -336,13 +336,7 @@ The returned list has a `package-archives' compliant format." apath (concat (if (and dotspacemacs-elpa-https - (not spacemacs-insecure) - ;; for now org ELPA repository does - ;; not support HTTPS - ;; TODO when org ELPA repo support - ;; HTTPS remove the check - ;; `(not (equal "org" aname))' - (not (equal "org" aname))) + (not spacemacs-insecure)) "https://" "http://") apath))))) @@ -1034,12 +1028,15 @@ return both used and unused packages." packages (lambda (x) (let ((pkg (configuration-layer/get-package x))) - (and (not (memq (oref pkg :location) '(built-in site local))) - (not (stringp (oref pkg :location))) - (or (null usedp) - (and (not (null (oref pkg :owners))) - (not (oref pkg :excluded)) - (cfgl-package-enabledp pkg t)))))))) + (if pkg + (and (not (memq (oref pkg :location) '(built-in site local))) + (not (stringp (oref pkg :location))) + (or (null usedp) + (and (not (null (oref pkg :owners))) + (not (oref pkg :excluded)) + (cfgl-package-enabledp pkg t)))) + (spacemacs-buffer/warning "Cannot find package for %s" x) + nil))))) (defun configuration-layer//get-private-layer-dir (name) "Return an absolute path to the private configuration layer string NAME." @@ -2180,7 +2177,7 @@ Original code from dochang at https://github.com/dochang/elpa-clone" (configuration-layer/make-all-packages 'no-discover) (let (package-archive-contents (package-archives '(("melpa" . "https://melpa.org/packages/") - ("org" . "http://orgmode.org/elpa/") + ("org" . "https://orgmode.org/elpa/") ("gnu" . "https://elpa.gnu.org/packages/")))) (package-refresh-contents) (package-read-all-archive-contents) diff --git a/core/core-spacemacs-buffer.el b/core/core-spacemacs-buffer.el index ae62c19..b0e46ce 100644 --- a/core/core-spacemacs-buffer.el +++ b/core/core-spacemacs-buffer.el @@ -13,7 +13,7 @@ ;; ;;; Code: -(defconst spacemacs-buffer-version-info "0.200.9" +(defconst spacemacs-buffer-version-info "0.200.13" "Current version used to display addition release information.") (defconst spacemacs-buffer-name "*spacemacs*" diff --git a/core/core-themes-support.el b/core/core-themes-support.el index 7647917..b404c1c 100644 --- a/core/core-themes-support.el +++ b/core/core-themes-support.el @@ -26,7 +26,7 @@ (defconst spacemacs-theme-name-to-package '( - (alect-black-alt . alect-themes) + (alect-black-alt . alect-themes) (alect-black . alect-themes) (alect-dark-alt . alect-themes) (alect-dark . alect-themes) @@ -62,9 +62,15 @@ (base16-bespin . base16-theme) (base16-brewer . base16-theme) (base16-bright . base16-theme) + (base16-brushtrees . base16-theme) + (base16-brushtrees-dark . base16-theme) (base16-chalk . base16-theme) + (base16-circus . base16-theme) + (base16-classic-dark . base16-theme) + (base16-classic-light . base16-theme) (base16-codeschool . base16-theme) (base16-cupcake . base16-theme) + (base16-cupertino . base16-theme) (base16-darktooth . base16-theme) (base16-default-dark . base16-theme) (base16-default-light . base16-theme) @@ -77,32 +83,47 @@ (base16-google-light . base16-theme) (base16-grayscale-dark . base16-theme) (base16-grayscale-light . base16-theme) - (base16-green-screen . base16-theme) - (base16-harmonic16-dark . base16-theme) - (base16-harmonic16-light . base16-theme) + (base16-greenscreen . base16-theme) + (base16-gruvbox-dark-hard . base16-theme) + (base16-gruvbox-dark-medium . base16-theme) + (base16-gruvbox-dark-pale . base16-theme) + (base16-gruvbox-dark-soft . base16-theme) + (base16-gruvbox-light-hard . base16-theme) + (base16-gruvbox-light-medium . base16-theme) + (base16-gruvbox-light-soft . base16-theme) + (base16-harmonic-dark . base16-theme) + (base16-harmonic-light . base16-theme) (base16-hopscotch . base16-theme) - (base16-ir-black . base16-theme) + (base16-irblack . base16-theme) (base16-isotope . base16-theme) (base16-london-tube . base16-theme) (base16-macintosh . base16-theme) (base16-marrakesh . base16-theme) (base16-materia . base16-theme) + (base16-material-darker . base16-theme) + (base16-material-lighter . base16-theme) + (base16-material-palenight . base16-theme) + (base16-material . base16-theme) + (base16-mellow-purple . base16-theme) (base16-mexico-light . base16-theme) (base16-mocha . base16-theme) (base16-monokai . base16-theme) + (base16-nord . base16-theme) (base16-ocean . base16-theme) (base16-oceanicnext . base16-theme) (base16-onedark . base16-theme) + (base16-one-light . base16-theme) (base16-paraiso . base16-theme) (base16-phd . base16-theme) (base16-pico . base16-theme) (base16-pop . base16-theme) + (base16-porple . base16-theme) (base16-railscasts . base16-theme) (base16-rebecca . base16-theme) (base16-seti . base16-theme) (base16-seti-ui . base16-theme) (base16-shapeshifter . base16-theme) - (base16-solar-flare . base16-theme) + (base16-solarflare . base16-theme) (base16-solarized-dark . base16-theme) (base16-solarized-light . base16-theme) (base16-spacemacs . base16-theme) @@ -115,6 +136,8 @@ (base16-unikitty-dark . base16-theme) (base16-unikitty-light . base16-theme) (base16-woodland . base16-theme) + (base16-xcode-dusk . base16-theme) + (base16-zenburn . base16-theme) (sanityinc-solarized-dark . color-theme-sanityinc-solarized) (sanityinc-solarized-light . color-theme-sanityinc-solarized) (sanityinc-tomorrow-blue . color-theme-sanityinc-tomorrow) @@ -122,8 +145,19 @@ (sanityinc-tomorrow-day . color-theme-sanityinc-tomorrow) (sanityinc-tomorrow-eighties . color-theme-sanityinc-tomorrow) (sanityinc-tomorrow-night . color-theme-sanityinc-tomorrow) - (doom-one . doom-themes) (doom-molokai . doom-themes) + (doom-mono-dark . doom-themes) + (doom-mono-light . doom-themes) + (doom-nova . doom-themes) + (doom-one . doom-themes) + (doom-one-light . doom-themes) + (doom-peacock . doom-themes) + (doom-spacegrey . doom-themes) + (doom-tomorrow-day . doom-themes) + (doom-tomorrow-night . doom-themes) + (doom-tron . doom-themes) + (doom-vibrant . doom-themes) + (doom-x . doom-themes) (solarized-light . solarized-theme) (solarized-dark . solarized-theme) (spacemacs-light . spacemacs-theme) @@ -160,6 +194,12 @@ (tao-yang . tao-theme) (farmhouse-light . farmhouse-theme) (farmhouse-dark . farmhouse-theme) + (gruvbox-dark-soft . gruvbox-theme) + (gruvbox-dark-medium . gruvbox-theme) + (gruvbox-dark-hard . gruvbox-theme) + (gruvbox-light-soft . gruvbox-theme) + (gruvbox-light-medium . gruvbox-theme) + (gruvbox-light-hard . gruvbox-theme) ) "alist matching a theme name with its package name, required when package name does not match theme name + `-theme' suffix.") diff --git a/core/info/release-notes/0.200.10.txt b/core/info/release-notes/0.200.10.txt new file mode 100644 index 0000000..d51f85f --- /dev/null +++ b/core/info/release-notes/0.200.10.txt @@ -0,0 +1,4 @@ + HOT FIX RELEASE + +- Fix Helm error when selecting a candidate from a Helm buffer (thanks to bmag) +- Fix window number assignation for Neotree buffer window (thanks to duianto) diff --git a/core/info/release-notes/0.200.11.txt b/core/info/release-notes/0.200.11.txt new file mode 100644 index 0000000..6a7a75b --- /dev/null +++ b/core/info/release-notes/0.200.11.txt @@ -0,0 +1,11 @@ + HOT FIX RELEASE + +- Use HTTPS instead of HTTP for ORG ELPA repository (thanks to aaronjensen) +- Fix =helm= display function (thanks to jackkamm) +- Fix =anaconda-mode= variable names in Python layer (thanks to nixmaniack) +- Fix typo in =helm-cscope-find-calling-this-function= (thanks to dubnde) +- Use =org=mime= package from MELPA (thanks to jackkamm) +- Replace broken =helm-spotify= package by =helm-spotify-plus= (thanks to leezu) +- Update =Quelpa= library +- Backport up to date list of themes in core and themes-megapack layer. +- Fix =pyim= package name in Chinese layer (thanks to James Wang) diff --git a/core/info/release-notes/0.200.13.txt b/core/info/release-notes/0.200.13.txt new file mode 100644 index 0000000..4d0ba08 --- /dev/null +++ b/core/info/release-notes/0.200.13.txt @@ -0,0 +1,7 @@ + MELPA HOT FIX RELEASE + +- Fixes removed packages from MELPA. + +Essentially Emacs WIKI packages are concerned. They have been imported as local +packages from Emacsmirror GitHub organization (thanks to tarsius for maintaining +it) diff --git a/core/libs/quelpa.el b/core/libs/quelpa.el index f2c55dd..e61d29c 100644 --- a/core/libs/quelpa.el +++ b/core/libs/quelpa.el @@ -1,6 +1,6 @@ ;;; quelpa.el --- Emacs Lisp packages built directly from source -;; Copyright 2014-2015, Steckerhalter +;; Copyright 2014-2017, Steckerhalter ;; Copyright 2014-2015, Vasilij Schneidermann ;; Author: steckerhalter @@ -139,6 +139,13 @@ If nil the update is disabled and the repo is only updated on :group 'quelpa :type 'string) +(defcustom quelpa-self-upgrade-p t + "If non-nil upgrade quelpa itself when doing a + `quelpa-upgrade', otherwise only upgrade the packages in the + quelpa cache." + :group 'quelpa + :type 'boolean) + (defvar quelpa-initialized-p nil "Non-nil when quelpa has been initialized.") @@ -241,15 +248,18 @@ Return nil if the package is already installed and should not be upgraded." (unless (or (and (assq name package-alist) (not quelpa-upgrade-p)) (and (not config) (quelpa-message t "no recipe found for package `%s'" name))) - (let ((version (condition-case err - (package-build-checkout name config dir) - (error (quelpa-message t - "failed to checkout `%s': `%s'" - name - (error-message-string err)) - nil)))) - (when (quelpa-version>-p name version) - version))))) + (if (member (plist-get config :fetcher) '(wiki bzr cvs darcs fossil svn)) + (user-error + "The `%s' fetcher is not supported anymore. +It has been removed from the `package-build' library: cannot install `%s'" + (plist-get config :fetcher) + name) + (let ((version (condition-case err + (package-build-checkout name config dir) + (error "failed to checkout `%s': `%s'" + name (error-message-string err))))) + (when (quelpa-version>-p name version) + version)))))) (defun quelpa-build-package (rcp) "Build a package from the given recipe RCP. @@ -342,7 +352,7 @@ and return TIME-STAMP, otherwise return OLD-TIME-STAMP." new-stamp-info new-content-hash (time-stamp - (replace-regexp-in-string "\\.0" "." (format-time-string "%Y%m%d.%H%M%S"))) + (replace-regexp-in-string "\\.0+" "." (format-time-string "%Y%m%d.%H%M%S"))) (stamp-file (concat (expand-file-name (symbol-name name) dir) ".stamp")) (old-stamp-info (package-build--read-from-file stamp-file)) (old-content-hash (cdr old-stamp-info)) @@ -351,7 +361,7 @@ and return TIME-STAMP, otherwise return OLD-TIME-STAMP." (version (plist-get config :version))) (if (not (file-exists-p file-path)) - (error (quelpa-message t "`%s' does not exist" file-path)) + (error "`%s' does not exist" file-path) (if (eq type 'directory) (setq files (quelpa-expand-source-file-list file-path config) hashes (mapcar @@ -412,7 +422,7 @@ attribute with an URL like \"http://domain.tld/path/to/file.el\"." (local-path (expand-file-name remote-file-name dir)) (mm-attachment-file-modes (default-file-modes))) (unless (string= (file-name-extension url) "el") - (error (quelpa-message t "<%s> does not end in .el" url))) + (error "<%s> does not end in .el" url)) (unless (file-directory-p dir) (make-directory dir)) (url-copy-file url local-path t) @@ -476,8 +486,7 @@ If there is an error and no existing checkout return nil." 'package-build `(:url ,quelpa-melpa-repo-url :files ("*")) quelpa-melpa-dir) - (error (quelpa-message t "failed to checkout melpa git repo: `%s'" (error-message-string err)) - (file-exists-p (expand-file-name ".git" quelpa-melpa-dir)))))) + (error "failed to checkout melpa git repo: `%s'" (error-message-string err))))) (defun quelpa-get-melpa-recipe (name) "Read recipe with NAME for melpa git checkout. @@ -570,7 +579,8 @@ install them." (requires (package-desc-reqs pkg-desc))) (when requires (mapc (lambda (req) - (unless (equal 'emacs (car req)) + (unless (or (equal 'emacs (car req)) + (package-installed-p (car req) (cadr req))) (quelpa-package-install (car req)))) requires)) (quelpa-package-install-file file))))) @@ -578,10 +588,13 @@ install them." (defun quelpa-interactive-candidate () "Query the user for a recipe and return the name." (when (quelpa-setup-p) - (let ((recipes (directory-files - (expand-file-name "recipes" quelpa-melpa-dir) + (let ((recipes (cl-loop + for store in quelpa-melpa-recipe-stores + if (stringp store) ;; this regexp matches all files except dotfiles - nil "^[^.].+$"))) + append (directory-files store nil "^[^.].+$") + else if (listp store) + append store))) (intern (completing-read "Choose MELPA recipe: " recipes nil t))))) @@ -616,7 +629,8 @@ the `quelpa' command has been run in the current Emacs session." (interactive) (when (quelpa-setup-p) (let ((quelpa-upgrade-p t)) - (quelpa-self-upgrade) + (when quelpa-self-upgrade-p + (quelpa-self-upgrade)) (setq quelpa-cache (cl-remove-if-not #'package-installed-p quelpa-cache :key #'car)) (mapc (lambda (item) diff --git a/init.el b/init.el index 8fe3870..e2aaff1 100644 --- a/init.el +++ b/init.el @@ -16,7 +16,7 @@ ;; lower value in your dotfile (function `dotspacemacs/user-config') (setq gc-cons-threshold 100000000) -(defconst spacemacs-version "0.200.9" "Spacemacs version.") +(defconst spacemacs-version "0.200.13" "Spacemacs version.") (defconst spacemacs-emacs-min-version "24.4" "Minimal version of Emacs.") (if (not (version<= spacemacs-emacs-min-version emacs-version)) diff --git a/layers/+completion/helm/packages.el b/layers/+completion/helm/packages.el index 275c2a0..09ab54e 100644 --- a/layers/+completion/helm/packages.el +++ b/layers/+completion/helm/packages.el @@ -127,7 +127,6 @@ (helm-locate-set-command) (setq helm-locate-fuzzy-match (string-match "locate" helm-locate-command)) ;; alter helm-bookmark key bindings to be simpler - ;; TODO check if there is a more elegant solution to setup these bindings (defun simpler-helm-bookmark-keybindings () (define-key helm-bookmark-map (kbd "C-d") 'helm-bookmark-run-delete) (define-key helm-bookmark-map (kbd "C-e") 'helm-bookmark-run-edit) @@ -136,7 +135,8 @@ (define-key helm-bookmark-map (kbd "C-o") 'helm-bookmark-run-jump-other-window) (define-key helm-bookmark-map (kbd "C-/") 'helm-bookmark-help)) - (add-hook 'helm-mode-hook 'simpler-helm-bookmark-keybindings) + (with-eval-after-load 'helm-bookmark + (simpler-helm-bookmark-keybindings)) (with-eval-after-load 'helm-mode ; required (spacemacs|hide-lighter helm-mode))))) diff --git a/layers/+distributions/spacemacs-base/local/help-fns+/help-fns+.el b/layers/+distributions/spacemacs-base/local/help-fns+/help-fns+.el new file mode 100644 index 0000000..5b4cc07 --- /dev/null +++ b/layers/+distributions/spacemacs-base/local/help-fns+/help-fns+.el @@ -0,0 +1,2918 @@ +;;; help-fns+.el --- Extensions to `help-fns.el'. +;; +;; Filename: help-fns+.el +;; Description: Extensions to `help-fns.el'. +;; Author: Drew Adams +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 2007-2017, Drew Adams, all rights reserved. +;; Created: Sat Sep 01 11:01:42 2007 +;; Version: 0 +;; Package-Requires: () +;; Last-Updated: Thu Feb 23 07:33:32 2017 (-0800) +;; By: dradams +;; Update #: 2226 +;; URL: https://www.emacswiki.org/emacs/download/help-fns%2b.el +;; Doc URL: http://emacswiki.org/HelpPlus +;; Keywords: help, faces, characters, packages, description +;; Compatibility: GNU Emacs: 22.x, 23.x, 24.x, 25.x +;; +;; Features that might be required by this library: +;; +;; `button', `cl', `cl-lib', `gv', `help-fns', `help-mode', `info', +;; `macroexp', `naked', `wid-edit', `wid-edit+'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Extensions to `help-fns.el'. Also includes a redefinition of +;; `describe-face', which is from `faces.el'. +;; +;; Note: As of Emacs 24.4, byte-compiling this file in one Emacs +;; version and using the compiled file in another Emacs version +;; does not work. +;; +;; +;; Keys bound here: +;; +;; `C-h B' `describe-buffer' +;; `C-h c' `describe-command' (replaces `describe-key-briefly') +;; `C-h o' `describe-option' +;; `C-h C-c' `describe-key-briefly' (replaces `C-h c') +;; `C-h C-o' `describe-option-of-type' +;; `C-h M-c' `describe-copying' (replaces `C-h C-c') +;; `C-h M-f' `describe-file' +;; `C-h M-k' `describe-keymap' +;; `C-h M-l' `find-function-on-key' +;; +;; Commands defined here: +;; +;; `describe-buffer', `describe-command', `describe-file', +;; `describe-keymap', `describe-option', `describe-option-of-type'. +;; +;; User options defined here: +;; +;; `help-cross-reference-manuals' (Emacs 23.2+). +;; +;; Faces defined here: +;; +;; `describe-variable-value' (Emacs 24+). +;; +;; Non-interactive functions defined here: +;; +;; `describe-mode-1', `help-all-exif-data', +;; `help-commands-to-key-buttons', `help-custom-type', +;; `help-documentation', `help-documentation-property' (Emacs 23+), +;; `help-key-button-string', `help-remove-duplicates', +;; `help-substitute-command-keys', `help-value-satisfies-type-p', +;; `help-var-inherits-type-p', `help-var-is-of-type-p', +;; `help-var-matches-type-p', `help-var-val-satisfies-type-p', +;; `Info-first-index-occurrence' (Emacs 23.2+), +;; `Info-indexed-find-file' (Emacs 23.2+), `Info-indexed-find-node' +;; (Emacs 23.2+), `Info-index-entries-across-manuals' (Emacs +;; 23.2+), `Info-index-occurrences' (Emacs 23.2+), +;; `Info-make-manuals-xref' (Emacs 23.2+). +;; +;; Internal variables defined here: +;; +;; `Info-indexed-file' (Emacs 23.2+), `Info-indexed-nodes' (Emacs +;; 23.2+), `variable-name-history'. +;; +;; +;; ***** NOTE: The following command defined in `faces.el' +;; has been REDEFINED HERE: +;; +;; `describe-face'. +;; +;; +;; ***** NOTE: The following command defined in `help.el' +;; has been REDEFINED HERE: +;; +;; `describe-mode'. +;; +;; +;; ***** NOTE: The following functions defined in `help-fns.el' +;; have been REDEFINED HERE: +;; +;; `describe-function', `describe-function-1', `describe-variable', +;; `help-fns--key-bindings', `help-fns--signature', +;; +;; +;; ***** NOTE: The following command defined in `package.el' +;; has been REDEFINED HERE: +;; +;; `describe-package'. +;; +;; +;; Put this in your initialization file (`~/.emacs'): +;; +;; (require 'help-fns+) +;; +;; Acknowledgement: Passing text properties on doc strings to the +;; *Help* buffer is an idea from Johan bockgard. He sent it on +;; 2007-01-24 to emacs-devel@gnu.org, Subject +;; "display-completion-list should not strip text properties". +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change Log: +;; +;; 2016/09/17 dadams +;; describe-function: Fix Emacs bug #24221: let FUNCTION be anonymous. +;; 2015/12/15 dadams +;; describe-file: Remove `' around file name in title. +;; 2015/09/09 dadams +;; describe-variable: Fixed test order for non-"" VARDOC, so it does not become t. +;; 2015/09/08 dadams +;; describe-keymap: Added optional arg SEARCH-SYMBOLS-P. Follow alias chain of symbol, and describe last one. +;; describe-variable: Pick up doc from alias, if help-documentation-property returns "". +;; 2015/08/30 dadams +;; describe-function-1: Typo: auto-do-load -> autoload-do-load. +;; 2015/08/22 dadams +;; describe-keymap: +;; Allow arg to be a keymap (not a keymap variable), when not interactive. Suggestion by erjoalgo. +;; 2015/08/13 dadams +;; describe-variable: +;; PREDICATE arg to completing-read needs to use original buffer, not minibuffer, when test boundp. +;; Fixes Emacs BUG #21252. +;; 2015/08/02 dadams +;; Updated for Emacs 25 +;; help-fns--signature: +;; Added arg RAW. Return DOC if FUNCTION is a keymap. Use help--make-usage-docstring. +;; Use help--docstring-quote. Insert "`X", not "(\` X)", when documenting `X. Use substitute-command-keys +;; on args to help-highlight-arguments. +;; describe-function-1: +;; Use indirect-function if subr (SIG-KEY). Moved autoloads forward). Use help-fns-short-filename. +;; Use auto-do-load. But do NOT use curly quotes - e.g., no extra substitute-command-name calls. +;; 2015/04/03 dadams +;; Use char-before in place of looking-back, for chars before. See Emacs bug #17284. +;; 2015/03/26 dadams +;; describe-package: Fix guard to use emacs-minor-version 3, not 24. Thx to Roshan Shariff. +;; 2015/03/23 dadams +;; describe-variable (Emacs 24+): Fix terpri's so appearance is better. Fill region for global value. +;; 2014/11/29 dadams +;; Info-make-manuals-xref: Control number of newlines before. +;; describe-function-1: Use same def for Emacs 25. +;; describe-variable-value: Changed the default colors. +;; describe-variable: Use face describe-variable-value always. Fill region for value always. +;; Control number of newlines before and after Value:, and after manuals xref. +;; 2014/11/12 dadams +;; describe-package: +;; Added version for Emacs 24.4+ - Use package-alist, package--builtins, or package-archive-contents. +;; 2014/11/08 dadams +;; describe-mode-1: Show major-mode and mode-function also, on a separate line (Emacs bug #18992), filling. +;; 2014/08/10 dadams +;; describe-command: Bind completion-annotate-function for use with Icicles. +;; 2014/05/11 dadams +;; help-substitute-command-keys: Bug: \= was not being removed - C-h f replace-regexp showed \=\N, not \N. +;; Small loop for \=: changed \\\\=$ to \\\\=. +;; Main loop, when escaped (\=) and odd: Skip the \=: concat before \= with after \=. +;; 2014/05/04 dadams +;; Use called-interactively only for Emacs 23.2+, since we pass it an arg. +;; 2014/05/02 dadams +;; describe-package: Updated for Emacs 24.4 - defstruct package-desc. +;; 2014/04/21 dadams +;; with-selected-frame: Updated for Emacs 24.4. +;; describe-face: Updated for Emacs 24.4: Try face-at-point for read-face-name default. +;; describe-file, describe-keymap, describe-function: +;; Updated for Emacs 24.4: Use with-help-window, not with-output-to-temp-buffer. See bug #17109. +;; describe-function-1: Created version for Emacs 24.4+ +;; help-key-button-string: Do not quote :type. +;; describe-buffer, describe-mode-1, describe-function: Use called-interactively, if available. +;; Removed autoload cookie for describe-function, describe-keymap (but why?). +;; 2014/03/06 dadams +;; describe-variable: Fixed typo in regexp: [n] -> [\n]. +;; 2014/01/04 dadams +;; Added: describe-variable-value. +;; describe-variable (Emacs 24+): Highlight the value with face describe-variable-value. +;; 2013/08/06 dadams +;; describe-function: Ensure arg is a defined function before calling describe-function-1 (for Emacs 24+). +;; 2013/07/01 dadams +;; Revert the filling part of yesterday's update. +;; 2013/06/30 dadams +;; describe-variable for Emacs 24+: +;; Update for vanilla Emacs 24.4. Update for Emacs bug #14754: fill printed value so no long lines. +;; 2013/06/16 dadams +;; describe-(variable|option(-of-type)): Fixed for dumb variable-at-point, which returns 0 for no var. +;; 2013/04/29 dadams +;; describe-(function|command|variable|option|option-of-type): +;; Provide default only if symbol is of the right type. Put default in prompt. +;; 2013/02/08 dadams +;; describe-variable: Updated wrt Emacs 24 build of 2013-01-30. +;; 2012/11/18 dadams +;; describe-(variable|function): Add completion-candidate annotation: (option|comand). +;; 2012/10/28 dadams +;; help-fns--key-bindings: Fixed: forgot to mapconcat over keys. +;; 2012/10/26 dadams +;; Added: help-fns--key-bindings, help-fns--signature, +;; Added Emacs 24.3+ version of describe-function-1. Updated version for 23.2-24.2. +;; help-substitute-command-keys: Fix for \= when no match for \[, \<, \{ past it. +;; 2012/09/24 dadams +;; describe-file: Added optional arg NO-ERROR-P. +;; 2012/09/22 dadams +;; Info-index-occurrences, Info-first-index-occurrence: +;; Replace Info-directory call by short version. Better Searching msg. +;; 2012/09/21 dadams +;; Renamed Info-any-index-occurrences-p to Info-first-index-occurrence. +;; Info-any-index-occurrences-p: Return the first successful lookup, not t. +;; Info-index-entries-across-manuals, Info-index-occurrences, Info-any-index-occurrences-p: +;; Added optional arg INDEX-NODES. +;; Adjust calls to those fns accordingly, e.g., in define-button-type for help-info-manual-lookup +;; and help-insert-xref-button in Info-make-manuals-xref. +;; 2012/07/20 dadams +;; Added: describe-buffer, describe-mode-1. Bound describe-buffer to C-h B. +;; describe-mode: Redefined to use describe-mode-1. +;; 2012/07/03 dadams +;; Info-make-manuals-xref, Info-index-entries-across-manuals, Info-index-occurrences, +;; Info-any-index-occurrences-p: +;; Added optional arg NOMSG. +;; describe-(function|variable|file|package): No message if not interactive-p. +;; describe-function-1: pass MSGP to Info-make-manuals-xref (i.e. msg always). +;; describe-(mode|variable|face|keymap|package): Pass proper NOMSG arg to Info-make-manuals-xref. +;; 2012/01/11 dadams +;; describe-variable: Remove * from beginning of doc string. +;; 2011/11/25 dadams +;; Reverted yesterday's change and added IMPORTANT note to Commentary. +;; 2011/11/24 dadams +;; Added Emacs 24 version of with-help-window. They changed the signature of help-window-setup. +;; 2011/10/14 dadams +;; describe-mode: Call help-documentation while in mode's buffer, in case no \\<...>. +;; 2011/10/08 dadams +;; Info-make-manuals-xref: Do nothing if OBJECT is not a string or a symbol (e.g. is a keymap). +;; 2011/10/07 dadams +;; Added soft require of naked.el. +;; help-substitute-command-keys, describe-function-1: Use naked-key-description if available. +;; 2011/08/22 dadams +;; describe-variable (Emacs 23+): Added terpri after Value: (for multiline value). +;; 2011/07/25 dadams +;; describe-mode: +;; Put call to help-documentation inside let for maj: else major-mode gets changed to help-mode. +;; 2011/06/26 dadams +;; Added: help-commands-to-key-buttons, help-documentation(-property), +;; help-key-button-string, help-substitute-command-keys (Emacs 23+). +;; describe-(mode|variable|function-1|keymap) for Emacs 23+: +;; Use help-documentation (with insert and button arg), instead of documentation (with princ). +;; 2011/06/22 dadams +;; Info-make-manuals-xref: Added optional arg MANUALS. +;; 2011/06/20 dadams +;; Info(-any)-index-occurrences(-p): Fix pattern: remove arbitrary prefix [^\n]*. +;; Added, for Emacs 24+: describe-package. +;; 2011/06/14 dadams +;; Added, for Emacs 23.2+: describe-mode. +;; Info-make-manuals-xref: Added optional arg NO-NEWLINES-AFTER-P. +;; 2011/06/13 dadams +;; Added: Info-any-index-occurrences-p. +;; Info-make-manuals-xref: Use Info-any-index-occurrences-p, not Info-index-occurrences. +;; 2011/06/11 dadams +;; Added, for Emacs 23.2+: +;; describe-face, describe-function-1, help-cross-reference-manuals, Info-indexed-find-file, +;; Info-indexed-find-node, Info-index-entries-across-manuals, Info-index-occurrences, +;; Info-make-manuals-xref, Info-indexed-file, Info-indexed-nodes. +;; describe-keymap: Emacs 23.2+: Added link to manuals. +;; describe-variable: Updated Emacs 23 version, per vanilla. +;; Emacs 23.2+: Added link to manuals. +;; Require info.el for Emacs 23.2+. +;; 2011/04/25 dadams +;; describe-file: Incorporate autofile bookmark description. Added optional arg. +;; 2011/03/31 dadams +;; help-var-(matches|inherits)-type-p: Wrap string-match with save-match-data. +;; 2011/03/17 dadams +;; describe-file: Added clickable thumbnail image to the help for an image file. +;; 2011/03/02 dadams +;; Added: help-all-exif-data +;; describe-file: Show all EXIF data, using help-all-exif-data. +;; 2011/02/22 dadams +;; describe-file: Show also EXIF data for an image file. +;; 2011/01/04 dadams +;; Removed autoload cookies from non def* sexps and define-key. +;; 2010/02/12 dadams +;; Added variable-name-history. +;; 2009/08/30 dadams +;; describe-keymap: Don't print nil if the map has no doc. +;; 2009/05/26 dadams +;; describe-variable: Updated wrt latest Emacs 23: +;; Added file-name-non-directory; removed substitute-command-keys. +;; 2008/09/13 dadams +;; Updated for latest Emacs 23 CVS. +;; describe-variable: Create separate version for Emacs 23. +;; describe-function-1: No longer needed for Emacs 23, since my patch added. +;; Added: with-selected-frame, with-help-window, at least temporarily. +;; Require wid-edit.el. +;; 2008/09/02 dadams +;; describe-function-1, describe-variable: +;; Emacs 23 uses find-lisp-object-file-name. Thx to Per Nordlow. +;; 2008/08/19 dadams +;; describe-keymap: Use insert instead of princ for map part. Thx to Chong Yidong. +;; 2008/05/20 dadams +;; describe-function: Different prompt if prefix arg. +;; 2008/03/02 dadams +;; Moved describe-file here from misc-cmds.el. Bound to C-h M-f. +;; Require cl.el at compile time. +;; 2008/02/01 dadams +;; Bound M-l to find-function-on-key. +;; 2008/01/03 dadams +;; Added: describe-function-1. The redefinition fills overlong lines. +;; 2007/12/25 dadams +;; help-var-inherits-type-p: +;; Recheck var-type match after set var-type to its car. +;; Handle string (regexp) TYPES elements. +;; help-value-satisfies-type-p: Skip type check for string type (regexp). +;; help-var-is-of-type-p: Doc string. Use help-var-matches-type-p. +;; Added: help-var-matches-type-p. +;; 2007/12/24 dadams +;; help-var-inherits-type-p: Recheck type match after set var-type to its car. +;; Added: help-custom-type. +;; 2007/12/23 dadams +;; help-var-is-of-type-p: +;; Added MODE arg. Use help-var-inherits-type-p, help-var-val-satisfies-type-p. +;; Redefined as MODE choice, not just a simple or. Treat more cases. +;; Added: help-var-inherits-type-p, help-var-val-satisfies-type-p, +;; help-value-satisfies-type-p. +;; describe-option-of-type: Prefix arg means use mode inherit-or-value. +;; 2007/12/22 dadams +;; help-var-is-of-type-p: +;; Check supertypes also. Use both :validate and :match. +;; Wrap type check in condition-case. Use widget-put instead of plist-put. +;; Added soft require of wid-edit+.el. +;; 2007/12/21 dadams +;; help-var-is-of-type-p: Use :validate, not :match, for the test. +;; 2007/12/20 dadams +;; Moved describe-option-of-type to C-h C-o. +;; 2007/12/15 dadams +;; Bound C-h c to describe-command and C-h C-c to describe-key-briefly. +;; 2007/12/07 dadams +;; describe-option-of-type: +;; Call describe-variable with nil buffer. Use "nil" as default value. +;; 2007/12/06 dadams +;; describe-option-of-type: +;; If nil type, all defcustom vars are candidates. Use custom-variable-p. +;; Specific error if no such custom type. +;; 2007/12/04 dadams +;; Added: describe-option-of-type, help-remove-duplicates, help-var-is-of-type-p. +;; Bound o to describe-option, M-o to describe-option-of-type, +;; C-c to describe-command, M-c to describe-copying. +;; 2007/11/28 dadams +;; Renamed describe-bindings-in-map to describe-keymap. Added keymap's doc string. +;; 2007/11/22 dadams +;; Added: describe-bindings-in-map. Bound to C-h M-k. +;; 2007/11/01 dadams +;; Corrected require typo: help-mode -> help-fns. +;; 2007/10/18 dadams +;; Created. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 2, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + + +(require 'help-fns) + +(require 'wid-edit+ nil t) ;; (no error if not found): + ;; redefined color widget (for help-var-is-of-type-p) +(require 'wid-edit) ;; widget-convert + +(require 'naked nil t) ;; (no error if not found): naked-key-description + +(when (or (> emacs-major-version 23) (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (require 'info)) ;; Info-virtual-files + +(eval-when-compile (require 'cl)) ;; case, gentemp + + +;; Quiet the byte-compiler. +(defvar advertised-signature-table) +(defvar dir-local-variables-alist) +(defvar dir-locals-file) +(defvar file-local-variables-alist) +(defvar icicle-mode) ; In `icicles-mode.el' +(defvar icicle-pre-minibuffer-buffer) ; In `icicles-var.el' +(defvar Info-indexed-nodes) ; In `info.el' +(defvar help-cross-reference-manuals) ; For Emacs < 23.2 +(defvar help-enable-auto-load) ; For Emacs < 24.3 +(defvar package-alist) +(defvar package-archive-contents) +(defvar package--builtins) +(defvar package--initialized) + +;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar variable-name-history () "Minibuffer history for variable names.") + +(define-key help-map "B" 'describe-buffer) +(define-key help-map "c" 'describe-command) +(define-key help-map "o" 'describe-option) +(define-key help-map "\C-c" 'describe-key-briefly) +(define-key help-map "\C-o" 'describe-option-of-type) +(define-key help-map "\M-c" 'describe-copying) +(define-key help-map "\M-f" 'describe-file) +(define-key help-map "\M-k" 'describe-keymap) +(define-key help-map "\M-l" 'find-function-on-key) + + +;; Need Emacs 23 for version of `make-text-button' that accepts a string. +(when (> emacs-major-version 22) + (defun help-documentation (function &optional raw add-help-buttons) + "Same as `documentation', but optionally adds buttons for help. +Non-nil optional arg ADD-HELP-BUTTONS does that, adding buttons to key +descriptions, which link to the key's command help." + (let ((raw-doc (documentation function 'RAW))) + (if raw raw-doc (help-substitute-command-keys raw-doc add-help-buttons)))) + + (defun help-documentation-property (symbol prop &optional raw add-help-buttons) + "Same as `documentation-property', but optionally adds buttons for help. +Non-nil optional arg ADD-HELP-BUTTONS does that, adding buttons to key +descriptions, which link to the key's command help." + (let ((raw-doc (documentation-property symbol prop 'RAW))) + (if raw raw-doc (help-substitute-command-keys raw-doc add-help-buttons)))) + + (defun help-commands-to-key-buttons (string) + "Like `substitute-command-keys', but adds buttons for help on keys. + Key descriptions become links to help about their commands." + (help-substitute-command-keys string 'ADD-HELP-BUTTONS)) + + (defun help-substitute-command-keys (string &optional add-help-buttons) + "Same as `substitute-command-keys', but optionally adds buttons for help. +Non-nil optional arg ADD-HELP-BUTTONS does that, adding buttons to key +descriptions, which link to the key's command help." + + ;; REPEAT: + ;; Search for first occurrence of any of the patterns: \[...], \{...}, or \<...>. + ;; Handle escaping via \=, if present before the pattern or if there is no pattern match. + ;; If pattern is a keymap (\<...>): use it from then on. + ;; If pattern is a command (\[...]): (a) substitute its key description, (b) put a button on it. + ;; If pattern is a bindings spec (\{...}): just substitute the usual text. + (with-syntax-table emacs-lisp-mode-syntax-table + (let* ((strg (copy-sequence string)) + (len-strg (length strg)) + (ii 0) + (jj 0) + (newstrg "") + (re-command "\\\\\\[\\(\\(\\sw\\|\\s_\\)+\\)\\]") + (re-keymap "\\\\<\\(\\(\\sw\\|\\s_\\)+\\)>") + (re-bindings "\\\\{\\(\\(\\sw\\|\\s_\\)+\\)}") + (re-any (concat "\\(" re-command "\\|" re-keymap "\\|" re-bindings "\\)")) + (keymap (or overriding-terminal-local-map overriding-local-map)) + (msg nil) + key bindings ma mc mk mb) + (while (< ii len-strg) + (setq key nil + bindings () + strg (substring strg ii)) + + (save-match-data ; ANY + (setq ma (string-match re-any strg)) + (cond ((not ma) ; No \[...], \{...}, or \<...>, but we need to handle \= + (setq jj 0 + newstrg (concat newstrg (replace-regexp-in-string + "\\\\=\\(.\\)" "\\1" strg nil nil nil jj))) + (when (match-beginning 1) (setq jj (match-beginning 1))) + (setq ii len-strg)) + (t + (let ((escaped nil) + (odd nil)) + (save-match-data + (let ((ma/= ma)) + (setq ii ma) + (while (string-match "\\\\=" (substring strg 0 ma/=)) + (setq odd (not odd) + ma/= (match-beginning 0)) + (when odd (setq ii (- ii 2) + escaped ma/=))))) + (if (not escaped) + (setq ii ma + jj (match-end 0) + ma (match-string-no-properties 0 strg) + newstrg (concat newstrg (substring strg 0 ii))) + (setq jj (match-end 0) ; End of \[...], \{...}, or \<...> + ma (and (not odd) (match-string-no-properties 0 strg)) + newstrg (if odd + (concat newstrg + (substring strg 0 escaped) ; Before \='s + (substring strg (+ 2 escaped) ii)) ; After \='s + (concat newstrg (substring strg 0 ii))))))))) + + (when ma + + (save-match-data ; KEYMAP + (setq ma (copy-sequence ma)) + (setq mk (string-match re-keymap ma)) + (setq mk (and mk (match-string-no-properties 0 ma))) + (when mk + (setq keymap (intern (match-string-no-properties 1 ma))) + (if (boundp keymap) + (setq keymap (symbol-value keymap)) + (setq msg (format "\nUses keymap \"%s\", which is not currently defined.\n" keymap)) + (setq keymap (or overriding-terminal-local-map overriding-local-map))))) + + (unless mk ; COMMAND + (save-match-data + (setq ma (copy-sequence ma)) + (setq mc (string-match re-command ma)) + (setq mc (and mc (match-string-no-properties 0 ma))) + (setq mc (and mc (intern (substring mc 2 -1)))) ; Remove \[...] envelope + (when mc + (let ((follow-remap t)) + (while (and (setq key (where-is-internal mc keymap 'FIRSTONLY)) + (vectorp key) (> (length key) 1) (eq 'remap (aref key 0)) + (symbolp (aref key 1)) follow-remap) + (setq mc (aref key 1) + follow-remap nil))) + (setq key (if key + (if (fboundp 'naked-key-description) + (naked-key-description key) + (key-description key)) + (concat "M-x " (symbol-name mc)))) + (when add-help-buttons (setq key (help-key-button-string key mc)))))) + + (unless (or mk mc) ; BINDINGS + (save-match-data + (setq ma (copy-sequence ma)) + (setq mb (string-match re-bindings ma)) + (setq mb (and mb (match-string-no-properties 0 ma))) + (when mb + (setq bindings (intern (match-string-no-properties 1 ma))) + (cond ((boundp bindings) + (setq bindings (substitute-command-keys mb))) ; Use original - no buttons. + (t + (setq msg (format "\nUses keymap \"%s\", which is not currently defined.\n" + bindings)) + (setq bindings nil)))))) + + (unless mk (setq newstrg (concat newstrg (or key bindings (substring strg ii jj))))) + (setq ii (or jj len-strg)))) + + (if (string= string newstrg) + string ; Return original string, not a copy, if no changes. + newstrg)))) + + (defun help-key-button-string (key-description command) + "Return a button for KEY-DESCRIPTION that links to the COMMAND description. +KEY-DESCRIPTION is a key-description string. +COMMAND is the command (a symbol) associated with the key described. +Return a copy of string KEY-DESCRIPTION with button properties added. +Clicking the button shows the help for COMMAND." + (let ((new-key (copy-sequence key-description))) + (make-text-button new-key nil 'button (list t) :type 'help-function 'help-args (list command)) + new-key))) + + +(when (boundp 'Info-virtual-files) ; Emacs 23.2+ + (defcustom help-cross-reference-manuals '(("emacs" "elisp")) + "*Manuals to search, for a `*Help*' buffer link to the manuals. +A cons. + + The car is a list of manuals to search, or the symbol `all', to + search all. If nil, then do not create a cross-reference link. + + The cdr is a boolean: + + Non-`nil' means search the manuals, then create a cross-ref link: + create it only if some search hits are found. + + `nil' means create a cross-ref link without searching manuals + first (but only if there are some manuals to search)." + :set #'(lambda (sym defs) (custom-set-default sym defs) (setq Info-indexed-nodes ())) + :type '(cons + (choice :tag "Which Manuals" + (repeat :tag "Specific Manuals (files)" string) + (const :tag "All Manuals" all)) + (boolean :tag "Search Before Creating Button?")) + :group 'help) + + (defvar Info-indexed-file "*Indexed*" + "Info file for virtual manual from `Info-index-entries-across-manuals'.") + + (defvar Info-indexed-nodes () + "Alist of cached nodes with matching index entries. +Each element is (NODENAME STRING MATCHES), where: + NODENAME is the name of the node that is indexed, + STRING is the search string passed to `Info-index-occurrences', + MATCHES is a list of index matches found by `Info-index-occurrences'. + +This has the same structure as `Info-apropos-nodes', but the search +was made by `Info-index-occurrences', not by `Info-apropos-matches', +so that matches are exact (ignoring case).") + + (defun Info-indexed-find-file (filename &optional _noerror) + "Index-search implementation of `Info-find-file'." + filename) + + (defun Info-indexed-find-node (_filename nodename &optional _no-going-back) + "Index-search implementation of `Info-find-node-2'." + (let* ((nodeinfo (assoc nodename Info-indexed-nodes)) + (matches (nth 2 nodeinfo))) + (when matches + (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n" Info-indexed-file nodename)) + (insert "Index Matches\n") + (insert "*************\n\n") + (insert "Index entries that match `" (nth 1 nodeinfo) "':\n\n") + (insert "\0\b[index\0\b]\n") + (if (eq matches t) + (insert "No matches found.\n") + (insert "* Menu:\n\n") + (dolist (entry matches) + (insert (format "* %-38s (%s)%s.%s\n" (format "%s [%s]:" (nth 1 entry) (nth 0 entry)) + (nth 0 entry) (nth 2 entry) + (if (nth 3 entry) (format " (line %s)" (nth 3 entry)) "")))))))) + (add-to-list 'Info-virtual-files '("\\`\\*Indexed\\*\\'" + (find-file . Info-indexed-find-file) + (find-node . Info-indexed-find-node) + ;; (slow . t) ; $$$$$$ Useless here? + )) + + (defun Info-make-manuals-xref (object &optional no-newlines-after-p manuals-spec nomsg) + "Create a cross-ref link for index entries for OBJECT in manuals. +Non-`nil' optional arg NO-NEWLINES-AFTER-P means do not add two +newlines after the cross reference. + +Optional arg MANUALS-SPEC controls which manuals to search. It has +the same form as option `help-cross-reference-manuals', and it +defaults to the value of that option. + +Do nothing if the car of MANUALS-SPEC is nil (no manuals to search). +If its cdr is `nil' then create the link without first searching any +manuals. Otherwise, create the link only if there are search hits in +the manuals." + (when (or (stringp object) (symbolp object)) ; Exclude, e.g., a keymap as OBJECT. + (unless manuals-spec (setq manuals-spec help-cross-reference-manuals)) + (when (car manuals-spec) ; Create no link if no manuals to search. + (let ((books (car manuals-spec)) + (search-now-p (cdr manuals-spec)) + (symb-name (if (stringp object) object (symbol-name object)))) + (when (or (not search-now-p) + (save-current-buffer (Info-first-index-occurrence symb-name () books nomsg))) + (let ((buffer-read-only nil) + (nl-before (cond ((and (eq ?\n (char-before)) ; Quicker than `looking-back', apparently. + (eq ?\n (char-before (1- (point))))) "") + ((eq ?\n (char-before)) "\n") + (t "\n\n")))) + (insert (format "%sFor more information %s the " nl-before (if (cdr manuals-spec) "see" "check"))) + (help-insert-xref-button "manuals" 'help-info-manual-lookup symb-name () books) + (insert ".") + (unless no-newlines-after-p (insert "\n\n")))))))) + + (when (and (> emacs-major-version 21) + (condition-case nil (require 'help-mode nil t) (error nil)) + (get 'help-xref 'button-category-symbol)) ; In `button.el' + (define-button-type 'help-info-manual-lookup + :supertype 'help-xref + 'help-function #'(lambda (string &optional index-nodes books nomsg) + (Info-index-entries-across-manuals string () books nomsg)) + 'help-echo "mouse-2, RET: Look it up in the manuals")) + + (defun Info-index-entries-across-manuals (string &optional index-nodes manuals nomsg) + "Look up STRING in Info MANUALS on your system. +Looks for exact matches (ignoring case): STRING is expected to be an +index entry. Build an Info menu of the possible matches. + +Optional arg INDEX-NODES are the index nodes in MANUALS to search. + By default (nil value), all indexes are searched. +Optional arg MANUALS is the list of manuals to search, or the symbol + `all', to search all. +Optional arg NOMSG non-nil means do not display a progress message." + (let ((nodes Info-indexed-nodes) + nodename) + (while (and nodes (not (equal string (nth 1 (car nodes))))) (setq nodes (cdr nodes))) + (if nodes + (Info-find-node Info-indexed-file (car (car nodes))) + (setq nodename (format "Index for `%s'" string)) + (push (list nodename string (Info-index-occurrences string index-nodes manuals nomsg)) + Info-indexed-nodes) + (Info-find-node Info-indexed-file nodename)))) + + ;; Similar to `Info-apropos-matches', but using exact matches (ignoring case). + (defun Info-index-occurrences (index-entry &optional index-nodes manuals nomsg) + "Collect occurrences of INDEX-ENTRY in INDEX-NODES of MANUALS. +Return a list of the form ((FILE INDEX-ENTRY NODE LINE) ...), where: + FILE is the name of an Info file, + NODE is an Info node name, + LINE is the line number of the INDEX-ENTRY occurrence in that node. + +Optional arg INDEX-NODES are the index nodes in MANUALS to search. + By default (nil value), search all indexes of each manual. +Optional arg MANUALS is the list of manuals to search, or the symbol + `all', to search all. +Optional arg NOMSG non-nil means do not display a progress message." + (unless (string= index-entry "") + ;; Unlike `Info-apropos-matches', we match only the exact string as an index entry. + (let ((pattern (format "\n\\* +\\(%s\\):[ \t]+\\([^\n]+\\)\ +\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?" + (regexp-quote index-entry))) + matches node) + (unless nomsg + (message "Searching indexes of %s..." + (cond ((eq manuals 'all) "all manuals") + ((null (cadr manuals)) (concat (car manuals) " manual")) + (t (concat "manuals " (mapconcat #'identity manuals ", ")))))) + (condition-case nil + (with-temp-buffer + (when (eq manuals 'all) (setq manuals ())) + (Info-mode) + ;; Next two lines are essentially `(Info-directory)'. + (info-initialize) + (Info-find-node-2 "dir" "top" 'NO-GOING-BACK) + (unless manuals + (goto-char (point-min)) + (re-search-forward "\\* Menu: *\n" nil t) + (let (manual) + (while (re-search-forward "\\*.*: *(\\([^)]+\\))" nil t) + ;; `add-to-list' ensures no dups in `manuals', so the `dolist' runs faster. + (setq manual (match-string 1)) + (set-text-properties 0 (length manual) nil manual) + (add-to-list 'manuals manual)))) + (dolist (manual manuals) + (unless nomsg (message "Searching indexes of manual `%s'..." manual)) + (when (or index-nodes + (setq index-nodes (Info-index-nodes (Info-find-file manual)))) + (Info-find-node manual (car index-nodes)) + (while (progn (goto-char (point-min)) + (while (re-search-forward pattern nil t) + (setq matches (cons (list manual + (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3)) + matches))) + (setq index-nodes (cdr index-nodes) + node (car index-nodes))) + (Info-goto-node node))))) + (error nil)) + matches))) + + ;; Like `Info-index-occurrences', but return only the first occurrence found. + (defun Info-first-index-occurrence (index-entry &optional index-nodes manuals nomsg) + "Return nil or an occurrence of INDEX-ENTRY in INDEX-NODES of MANUALS. +Search INDEX-NODES and MANUALS in order. +A non-nil return value is the first first successful index lookup, in +the form (FILE INDEX-ENTRY NODE LINE) - see `Info-index-occurrences'. + +Optional arg INDEX-NODES are the index nodes of MANUALS to search. + By default (nil value), search all indexes of each manual. +Optional arg MANUALS is the list of manuals to search, or the symbol + `all', to search all. +Optional arg NOMSG non-nil means do not display a progress message." + (and (not (string= index-entry "")) + ;; Unlike `Info-apropos-matches', we match only the exact string as an index entry. + (let ((pattern (format "\n\\* +\\(%s\\):[ \t]+\\([^\n]+\\)\ +\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?" + (regexp-quote index-entry))) + (found nil) + node) + (unless nomsg + (message "Searching indexes of %s..." + (cond ((eq manuals 'all) "all manuals") + ((null (cadr manuals)) (concat (car manuals) " manual")) + (t (concat "manuals " (mapconcat #'identity manuals ", ")))))) + (condition-case nil + (with-temp-buffer + (when (eq manuals 'all) (setq manuals ())) + (Info-mode) + ;; Next two lines are essentially `(Info-directory)'. + (info-initialize) + (Info-find-node-2 "dir" "top" 'NO-GOING-BACK) + (unless manuals + (goto-char (point-min)) + (re-search-forward "\\* Menu: *\n" nil t) + (let (manual) + (while (re-search-forward "\\*.*: *(\\([^)]+\\))" nil t) + ;; `add-to-list' ensures no dups in `manuals', so the `dolist' runs faster. + (setq manual (match-string 1)) + (set-text-properties 0 (length manual) nil manual) + (add-to-list 'manuals manual)))) + (setq found (catch 'Info-first-index-occurrence + (dolist (manual manuals) + (unless nomsg + (message "Searching indexes of manual `%s'..." manual)) + (when (or index-nodes + (setq index-nodes (Info-index-nodes + (Info-find-file manual)))) + (Info-find-node manual (car index-nodes)) + (while (progn (goto-char (point-min)) + (when (re-search-forward pattern nil t) + (throw 'Info-first-index-occurrence + (list manual + (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3)))) + (setq index-nodes (cdr index-nodes) + node (car index-nodes))) + (Info-goto-node node)))) + nil))) + (error nil)) + found))) + + (defun describe-buffer (&optional buffer-name) ; Bound to `C-h B' + "Describe the existing buffer named BUFFER-NAME. +The description includes the information provided by `describe-mode'. +By default, describe the current buffer." + ;; (interactive "bDescribe buffer: ") + (interactive "@") + (unless buffer-name (setq buffer-name (buffer-name))) + (help-setup-xref `(describe-buffer ,buffer-name) (called-interactively-p 'interactive)) + (let ((buf (get-buffer buffer-name))) + (unless (and buf (buffer-live-p buf)) (error(format "No such live buffer `%s'" buffer-name))) + (let* ((file (or (buffer-file-name buf) + (with-current-buffer buf + (and (eq major-mode 'dired-mode) default-directory)))) + (help-text (concat + (format "Buffer `%s'\n%s\n\n" buffer-name (make-string + (+ 9 (length buffer-name)) ?-)) + (and file (format "File/directory:\t%s\n" file)) + (format "Mode:\t\t%s\n" + (with-current-buffer buf (format-mode-line mode-name))) + (format "Size in chars:\t%g\n" (buffer-size buf)) + (with-current-buffer buf + (if (not buffer-display-time) + "Never displayed\n" + (format "Last displayed:\t%s\n" + (format-time-string + ;; Could use this, for short format: "%02H:%02M:%02S" + ;; Or this, for a bit longer: "%_3a %_2l:%02M:%02S %_2p" + "%a %b %e %T %Y (%z)" + buffer-display-time)))) + (format "Modified:\t%s\n" (if (buffer-modified-p buf) "yes" "no")) + (with-current-buffer buf + (format "Read-only:\t%s\n\n\n" (if buffer-read-only "yes" "no")))))) + (with-help-window (help-buffer) + (describe-mode-1 buf)) + (with-current-buffer (help-buffer) + (let ((inhibit-read-only t)) + (goto-char (point-min)) + (insert help-text)))))) + + + ;; REPLACE ORIGINAL + ;; + ;; Use `describe-mode-1', which is different from the original `describe-mode' in these ways: + ;; + ;; 1. Call `Info-make-manuals-xref' to create a cross-ref link to manuals. + ;; 2. Add key-description buttons to command help. Use `insert', not `princ'. + ;; + (defun describe-mode (&optional buffer) + "Display documentation of current major mode and minor modes. +A brief summary of the minor modes comes first, followed by the +major mode description. This is followed by detailed +descriptions of the minor modes, each on a separate page. + +For this to work correctly for a minor mode, the mode's indicator +variable \(listed in `minor-mode-alist') must also be a function +whose documentation describes the minor mode." + (interactive "@") + (unless buffer (setq buffer (current-buffer))) + (help-setup-xref (list #'describe-mode buffer) (called-interactively-p 'interactive)) + (with-help-window (help-buffer) (describe-mode-1 buffer)) + nil) ; For the sake of IELM and maybe others + + (defun describe-mode-1 (buffer) + "Helper for `describe-mode'. +Does everything except create the help window and set up the +back/forward buttons, so you can use this in other help commands that +have their own back/forward buttons." + ;; For the sake of `help-do-xref' and `help-xref-go-back', do not switch buffers before calling `help-buffer'. + (with-current-buffer buffer + (let (minor-modes) + ;; Older packages do not register in minor-mode-list but only in `minor-mode-alist'. + (dolist (x minor-mode-alist) + (setq x (car x)) + (unless (memq x minor-mode-list) (push x minor-mode-list))) + (dolist (mode minor-mode-list) ; Find enabled minor mode we will want to mention. + ;; Document minor mode if listed in `minor-mode-alist', non-nil, and has a function def. + (let ((fmode (or (get mode :minor-mode-function) mode))) + (and (boundp mode) (symbol-value mode) (fboundp fmode) + (let ((pretty-minor-mode (if (string-match "\\(\\(-minor\\)?-mode\\)?\\'" + (symbol-name fmode)) + (capitalize (substring (symbol-name fmode) + 0 (match-beginning 0))) + fmode))) + (push (list fmode pretty-minor-mode + (format-mode-line (assq mode minor-mode-alist))) + minor-modes))))) + (setq minor-modes (sort minor-modes (lambda (a b) (string-lessp (cadr a) (cadr b))))) + (when minor-modes + (princ "Enabled minor modes:\n") + (make-local-variable 'help-button-cache) + (with-current-buffer standard-output + (dolist (mode minor-modes) + (let ((mode-function (nth 0 mode)) + (pretty-minor-mode (nth 1 mode)) + (indicator (nth 2 mode))) + (add-text-properties 0 (length pretty-minor-mode) '(face bold) pretty-minor-mode) + (save-excursion + (goto-char (point-max)) + (princ "\n\f\n") + (push (point-marker) help-button-cache) + ;; Document the minor modes fully. + (insert pretty-minor-mode) + (princ (format " minor mode:\n(`%s'; %s)\n" mode-function (if (zerop (length indicator)) + "no indicator" + (format "indicator%s" indicator)))) + (save-excursion + (fill-region-as-paragraph (line-beginning-position 0) (line-end-position 0) nil t t)) + (with-current-buffer standard-output + (insert (help-documentation mode-function nil 'ADD-HELP-BUTTONS))) + (Info-make-manuals-xref mode-function + t nil (not (called-interactively-p 'interactive)))) ; Link manuals. + (insert-button pretty-minor-mode 'action (car help-button-cache) + 'follow-link t 'help-echo "mouse-2, RET: show full information") + (newline))) + (forward-line -1) + (fill-paragraph nil) + (forward-line 1)) + (princ "\n(Information about these minor modes follows the major mode info.)\n\n")) + (let ((mode mode-name)) ; Document the major mode. + (with-current-buffer standard-output + (let ((start (point))) + (insert (format-mode-line mode nil nil buffer)) + (add-text-properties start (point) '(face bold))))) + (princ " mode") + (let* ((mode major-mode) + (file-name (find-lisp-object-file-name mode nil))) + (when file-name + (princ (concat " defined in `" (file-name-nondirectory file-name) "'")) + (with-current-buffer standard-output ; Make a hyperlink to the library. + (save-excursion (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function-def mode file-name)))) + (with-current-buffer standard-output + (insert (format " (`%s'):\n" mode)) + (save-excursion + (fill-region-as-paragraph (line-beginning-position 0) (line-end-position 0) nil t t)))) + (let* ((maj major-mode) + (maj-doc (help-documentation maj nil 'ADD-HELP-BUTTONS))) + (with-current-buffer standard-output + (insert maj-doc) + (Info-make-manuals-xref + maj t nil (not (called-interactively-p 'interactive)))))))) ; Link to manuals. + ) + + + +;; REPLACE ORIGINAL in `help-fns.el': +;; +;; 1. Preferred candidate is `symbol-nearest-point'. +;; 2. With a prefix argument, candidates are commands only. +;; 3. No no-function message if not called interactively. +;; 4. Works for anonymous functions too: lambda forms and byte-compiled functions. (Fixes Emacs bug #24221.) +;; +(defun describe-function (function &optional commandp) + "Display the full documentation of FUNCTION (a symbol). +FUNCTION names an Emacs Lisp function, possibly a user command. +With a prefix argument, candidates are only commands (interactive). + +Default candidate is: preferably the `symbol-nearest-point', or else +the innermost function call surrounding point +\(`function-called-at-point'). +Return the description that was displayed, as a string." + (interactive + (let* ((fn (or (and (fboundp 'symbol-nearest-point) (symbol-nearest-point)) + (function-called-at-point))) + (enable-recursive-minibuffers t) + (completion-annotate-function (lambda (fn) (and (commandp (intern-soft fn)) " (command)"))) + (type (if current-prefix-arg 'command 'function)) + (prompt (format "Describe %s%s: " type + (if (if current-prefix-arg (commandp fn) (fboundp fn)) + (format " (default %s)" fn) + ""))) + val) + (setq val (completing-read prompt obarray (if current-prefix-arg 'commandp 'fboundp) t nil nil + (and (if current-prefix-arg (commandp fn) (fboundp fn)) (symbol-name fn)))) + (list (if (equal val "") fn (intern val)) current-prefix-arg))) + (let* ((interactivep (if (or (> emacs-major-version 23) ; Emacs 23.1 `called-interactively' accepts no arg. + (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p))) + (err/msg-fn (if interactivep #'message #'error)) + (fn/cmd-txt (if commandp 'command 'function))) + (if (and interactivep (not function)) + (funcall err/msg-fn "You did not specify a function symbol") ; Avoid "Not a defined function: `nil'". + (if (not (if commandp + (commandp function) + (or (functionp function) ; Allow anonymous functions (Emacs bug #24221). + (and function (fboundp (intern-soft function)))))) ; Allow macros and special forms. + (funcall err/msg-fn "Not a defined %s: `%S'" fn/cmd-txt function) + (help-setup-xref (list #'describe-function function) + (if (or (> emacs-major-version 23) ; Emacs 23.1 `called-interactively' accepts no arg. + (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p))) + (save-excursion + (if (fboundp 'with-help-window) + (with-help-window (help-buffer) ; Emacs 24.4 needs this - see Emacs bug #17109. + (prin1 function) + ;; Use " is " instead of ": " so it is easier to get the function name using `forward-sexp'. + (princ " is ") + (describe-function-1 function) + (with-current-buffer standard-output (buffer-string))) ; Return help text. + (with-output-to-temp-buffer (help-buffer) + (prin1 function) + ;; Use " is " instead of ": " so it is easier to get the function name using `forward-sexp'. + (princ " is ") + (describe-function-1 function) + (print-help-return-message) + (with-current-buffer standard-output (buffer-string))))))))) ; Return help text. + + + +;; REPLACE ORIGINAL in `help-fns.el' (`help.el', for Emacs < 22): +;; +;; Fill long lines. Add `,' before "which". +;; +(when (< emacs-major-version 23) + (defun describe-function-1 (function) + (let* ((def (if (symbolp function) (symbol-function function) function)) + (beg (if (commandp def) "an interactive " "a ")) + (pt1 (with-current-buffer (help-buffer) (point))) + file-name string) + (setq string (cond ((or (stringp def) (vectorp def)) "a keyboard macro") + ((subrp def) (if (eq 'unevalled (cdr (subr-arity def))) + (concat beg "special form") + (concat beg "built-in function"))) + ((byte-code-function-p def) (concat beg "compiled Lisp function")) + ((symbolp def) + (while (symbolp (symbol-function def)) + (setq def (symbol-function def))) + (format "an alias for `%s'" def)) + ((eq (car-safe def) 'lambda) (concat beg "Lisp function")) + ((eq (car-safe def) 'macro) "a Lisp macro") + ((eq (car-safe def) 'autoload) + (setq file-name (nth 1 def)) + (format "%s autoloaded %s" (if (commandp def) "an interactive" "an") + (if (eq (nth 4 def) 'keymap) + "keymap" + (if (nth 4 def) "Lisp macro" "Lisp function")))) + ((keymapp def) + (let ((is-full nil) + (elts (cdr-safe def))) + (while elts + (when (char-table-p (car-safe elts)) + (setq is-full t + elts ())) + (setq elts (cdr-safe elts))) + (if is-full "a full keymap" "a sparse keymap"))) + (t ""))) + (princ string) + (with-current-buffer standard-output + (save-excursion (save-match-data (when (re-search-backward "alias for `\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function def))))) + (unless file-name (setq file-name (symbol-file function 'defun))) + (setq file-name (describe-simplify-lib-file-name file-name)) + (when (equal file-name "loaddefs.el") + ;; Find the real def site of the preloaded function. This is necessary only for defaliases. + (let ((location (condition-case nil + (find-function-search-for-symbol function nil "loaddefs.el") + (error nil)))) + (when location + (with-current-buffer (car location) + (goto-char (cdr location)) + (when (re-search-backward "^;;; Generated autoloads from \\(.*\\)" nil t) + (setq file-name (match-string 1))))))) + (when (and (null file-name) (subrp def)) ; Find the C source file name. + (setq file-name (if (get-buffer " *DOC*") (help-C-file-name def 'subr) 'C-source))) + (when file-name + (princ " in `") + ;; We used to add `.el' to file name, but that's wrong when the user used `load-file'. + (princ (if (eq file-name 'C-source) "C source code" file-name)) + (princ "'") + (with-current-buffer standard-output ; Make a hyperlink to the library. + (save-excursion (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function-def function file-name)))) + (princ ".") + (with-current-buffer (help-buffer) + (fill-region-as-paragraph (save-excursion (goto-char pt1) (forward-line 0) (point)) (point))) + (terpri)(terpri) + (when (commandp function) + (let ((pt2 (with-current-buffer (help-buffer) (point)))) + (if (and (eq function 'self-insert-command) + (eq (key-binding "a") 'self-insert-command) + (eq (key-binding "b") 'self-insert-command) + (eq (key-binding "c") 'self-insert-command)) + (princ "It is bound to many ordinary text characters.\n") + (let* ((remapped (command-remapping function)) + (keys (where-is-internal + (or remapped function) overriding-local-map nil nil)) + non-modified-keys) + (dolist (key keys) ; Which non-control non-meta keys run this command? + (when (member (event-modifiers (aref key 0)) '(nil (shift))) + (push key non-modified-keys))) + (when remapped + (princ "It is remapped to `") (princ (symbol-name remapped)) (princ "'")) + (when keys + (princ (if remapped ", which is bound to " "It is bound to ")) + ;; If lots of ordinary text characters run this command, don't mention them one by one. + (if (< (length non-modified-keys) 10) + (princ (mapconcat (if (fboundp 'naked-key-description) + #'naked-key-description + #'key-description) + keys ", ")) + (dolist (key non-modified-keys) (setq keys (delq key keys))) + (if keys + (progn (princ (mapconcat (if (fboundp 'naked-key-description) + #'naked-key-description + #'key-description) + keys ", ")) + (princ ", and many ordinary text characters")) + (princ "many ordinary text characters")))) + (when (or remapped keys non-modified-keys) (princ ".") (terpri)))) + (with-current-buffer (help-buffer) (fill-region-as-paragraph pt2 (point))) + (terpri))) + (let* ((arglist (help-function-arglist def)) + (doc (documentation function)) + (usage (help-split-fundoc doc function))) + (with-current-buffer standard-output + ;; If definition is a keymap, skip arglist note. + (unless (keymapp def) + (let* ((use (cond (usage (setq doc (cdr usage)) (car usage)) + ((listp arglist) (format "%S" (help-make-usage function arglist))) + ((stringp arglist) arglist) + ;; Maybe the arglist is in the docstring of the alias. + ((let ((fun function)) + (while (and (symbolp fun) + (setq fun (symbol-function fun)) + (not (setq usage (help-split-fundoc (documentation fun) + function))))) + usage) + (car usage)) + ((or (stringp def) (vectorp def)) + (format "\nMacro: %s" (format-kbd-macro def))) + (t "[Missing arglist. Please make a bug report.]"))) + (high (help-highlight-arguments use doc))) + (let ((fill-begin (point))) + (insert (car high) "\n") + (fill-region fill-begin (point))) + (setq doc (cdr high)))) + (let ((obsolete (and (symbolp function) ; function might be a lambda construct. + (get function 'byte-obsolete-info)))) + (when obsolete + (princ "\nThis function is obsolete") + (when (nth 2 obsolete) (insert (format " since %s" (nth 2 obsolete)))) + (insert ";\n" (if (stringp (car obsolete)) + (car obsolete) + (format "use `%s' instead." (car obsolete))) + "\n")) + (insert "\n" (or doc "Not documented.")))))))) + + +;; REPLACE ORIGINAL in `help-fns.el': +;; +;; 1. Call `Info-make-manuals-xref' to create a cross-ref link to manuals. +;; 2. Add key-description buttons to command help. +;; +(when (and (boundp 'Info-virtual-files) ; Emacs 23.2 through 24.2 + (not (fboundp 'help-fns--autoloaded-p))) + (defun describe-function-1 (function) + (let* ((advised (and (symbolp function) (featurep 'advice) (ad-get-advice-info function))) + ;; If the function is advised, use the symbol that has the real def, if already set up. + (real-function (or (and advised (let ((origname (cdr (assq 'origname advised)))) + (and (fboundp origname) origname))) + function)) + ;; Get the real definition. + (def (if (symbolp real-function) (symbol-function real-function) function)) + (aliased (symbolp def)) + (real-def (if aliased + (let ((fn def)) + (while (and (fboundp fn) (symbolp (symbol-function fn))) + (setq fn (symbol-function fn))) + fn) + def)) + (file-name (find-lisp-object-file-name function def)) + (beg (if (commandp def) "an interactive " "a ")) + (pt1 (with-current-buffer (help-buffer) (point))) + string errtype) + (setq string (cond ((or (stringp def) (vectorp def)) "a keyboard macro") + ((subrp def) (if (eq 'unevalled (cdr (subr-arity def))) + (concat beg "special form") + (concat beg "built-in function"))) + ((byte-code-function-p def) (concat beg "compiled Lisp function")) + ((symbolp def) + (while (and (fboundp def) (symbolp (symbol-function def))) + (setq def (symbol-function def))) + ;; Handle (defalias 'foo 'bar), where bar is undefined. + (unless (fboundp def) (setq errtype 'alias)) + (format "an alias for `%s'" def)) + ((eq (car-safe def) 'lambda) (concat beg "Lisp function")) + ((eq (car-safe def) 'macro) "a Lisp macro") + ((eq (car-safe def) 'closure) (concat beg "Lisp closure")) + ((eq (car-safe def) 'autoload) + (format "%s autoloaded %s" (if (commandp def) "an interactive" "an") + (if (eq (nth 4 def) 'keymap) + "keymap" + (if (nth 4 def) "Lisp macro" "Lisp function")))) + ((keymapp def) (let ((is-full nil) + (elts (cdr-safe def))) + (while elts + (when (char-table-p (car-safe elts)) + (setq is-full t + elts ())) + (setq elts (cdr-safe elts))) + (if is-full "a full keymap" "a sparse keymap"))) + (t ""))) + (princ string) + (if (eq errtype 'alias) + (princ ",\nwhich is not defined. Please make a bug report.") + (with-current-buffer standard-output + (save-excursion (save-match-data (when (re-search-backward "alias for `\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function def))))) + (when file-name + (princ " in `") + ;; We used to add `.el' to the file name, but that's wrong when the user used `load-file'. + (princ (if (eq file-name 'C-source) "C source code" (file-name-nondirectory file-name))) + (princ "'") + ;; Make a hyperlink to the library. + (with-current-buffer standard-output + (save-excursion (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function-def function file-name)))) + (princ ".") + (with-current-buffer (help-buffer) + (fill-region-as-paragraph (save-excursion (goto-char pt1) (forward-line 0) (point)) (point))) + (terpri) (terpri) + (when (commandp function) + (let ((pt2 (with-current-buffer (help-buffer) (point))) + (remapped (command-remapping function))) + (unless (memq remapped '(ignore undefined)) + (let ((keys (where-is-internal (or remapped function) overriding-local-map nil nil)) + non-modified-keys) + (if (and (eq function 'self-insert-command) + (vectorp (car-safe keys)) + (consp (aref (car keys) 0))) + (princ "It is bound to many ordinary text characters.\n") + (dolist (key keys) ; Which non-control non-meta keys run this command? + (when (member (event-modifiers (aref key 0)) '(nil (shift))) + (push key non-modified-keys))) + (when remapped + (princ "It is remapped to `") (princ (symbol-name remapped)) (princ "'")) + (when keys + (princ (if remapped ", which is bound to " "It is bound to ")) + ;; If lots of ordinary text chars run this command, don't mention them one by one. + (if (< (length non-modified-keys) 10) + (princ (mapconcat (if (fboundp 'naked-key-description) + #'naked-key-description + #'key-description) + keys ", ")) + (dolist (key non-modified-keys) (setq keys (delq key keys))) + (if keys + (progn (princ (mapconcat (if (fboundp 'naked-key-description) + #'naked-key-description + #'key-description) + keys ", ")) + (princ ", and many ordinary text characters")) + (princ "many ordinary text characters")))) + (when (or remapped keys non-modified-keys) (princ ".") (terpri))))) + (with-current-buffer (help-buffer) + (fill-region-as-paragraph pt2 (point)) + (unless (and (eq ?\n (char-before)) ; Quicker than `looking-back', apparently. + (eq ?\n (char-before (1- (point))))) + (terpri))))) + ;; `list*' etc. do not get this property until `cl-hack-byte-compiler' runs, + ;; which is after bytecomp is loaded. + (when (and (symbolp function) (eq (get function 'byte-compile) 'cl-byte-compile-compiler-macro)) + (princ "This function has a compiler macro") + (let ((lib (get function 'compiler-macro-file))) + (when (stringp lib) + (princ (format " in `%s'" lib)) + (with-current-buffer standard-output + (save-excursion (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function-cmacro function lib))))) + (princ ".\n\n")) + (let* ((advertised (gethash def advertised-signature-table t)) + (arglist (if (listp advertised) advertised (help-function-arglist def))) + (doc (condition-case err + (help-documentation function nil 'ADD-HELP-BUTTONS) + (error (format "No Doc! %S" err)))) + (usage (help-split-fundoc doc function))) + (with-current-buffer standard-output + (unless (keymapp function) ; If definition is a keymap, skip arglist note. + (when usage (setq doc (cdr usage))) + (let* ((use (cond ((and usage (not (listp advertised))) (car usage)) + ((listp arglist) (format "%S" (help-make-usage function arglist))) + ((stringp arglist) arglist) + ;; Maybe arglist is in doc string of a symbol this one is aliased to. + ((let ((fun real-function)) + (while (and (symbolp fun) + (setq fun (symbol-function fun)) + (not (setq usage (help-split-fundoc + (help-documentation + fun nil 'ADD-HELP-BUTTONS) + function))))) + usage) + (car usage)) + ((or (stringp def) (vectorp def)) + (format "\nMacro: %s" (format-kbd-macro def))) + (t "[Missing arglist. Please submit a bug report.]"))) + (high (help-highlight-arguments use doc))) + (let ((fill-begin (point))) + (insert (car high) "\n") + (fill-region fill-begin (point))) + (setq doc (cdr high)))) + ;; If this is a derived mode, link to the parent. + (let ((parent-mode (and (symbolp real-function) (get real-function 'derived-mode-parent)))) + (when parent-mode + (with-current-buffer standard-output + (insert "\nParent mode: `") + (let ((beg (point))) + (insert (format "%s" parent-mode)) + (make-text-button beg (point) 'type 'help-function 'help-args (list parent-mode)))) + (princ "'.\n"))) + (let* ((obsolete (and (symbolp function) ; Function might be a lambda construct. + (get function 'byte-obsolete-info))) + (use (car obsolete))) + (when obsolete + (princ "\nThis function is obsolete") + (when (nth 2 obsolete) (insert (format " since %s" (nth 2 obsolete)))) + (insert (cond ((stringp use) (concat ";\n" use)) + (use (format ";\nuse `%s' instead." use)) + (t ".")) + "\n")) + (insert "\n") + (when (and doc (boundp 'Info-virtual-files)) ; Emacs 23.2+ + (Info-make-manuals-xref function)) ; Link to manuals. (With progress message.) + (insert (or doc "Not documented."))))))))) + +(when (fboundp 'help-fns--autoloaded-p) ; Emacs 24.3+ + + + ;; REPLACE ORIGINAL in `help-fns.el': + ;; + ;; Use `naked-key-description' if available, instead of `key-description'. + ;; + (defun help-fns--key-bindings (function) + (when (commandp function) + (let ((pt2 (with-current-buffer standard-output (point))) + (remapped (command-remapping function))) + (unless (memq remapped '(ignore undefined)) + (let ((keys (where-is-internal (or remapped function) overriding-local-map nil nil)) + non-modified-keys) + (if (and (eq function 'self-insert-command) + (vectorp (car-safe keys)) + (consp (aref (car keys) 0))) + (princ "It is bound to many ordinary text characters.\n") + (dolist (key keys) ; Which non-control non-meta keys run this command? + (when (member (event-modifiers (aref key 0)) '(nil (shift))) (push key non-modified-keys))) + (when remapped + (princ "Its keys are remapped to ") + (princ (if (symbolp remapped) (concat "`" (symbol-name remapped) "'") "an anonymous command")) + (princ ".\n")) + (when keys + (princ (if remapped "Without this remapping, it would be bound to " "It is bound to ")) + ;; If lots of ordinary text characters run this command, don't mention them one by one. + (if (< (length non-modified-keys) 10) + (princ (mapconcat (if (fboundp 'naked-key-description) + #'naked-key-description + #'key-description) + keys ", ")) + (dolist (key non-modified-keys) (setq keys (delq key keys))) + (if keys + (progn (princ (mapconcat (if (fboundp 'naked-key-description) + #'naked-key-description + #'key-description) + keys ", ")) + (princ ", and many ordinary text characters")) + (princ "many ordinary text characters")))) + (when (or remapped keys non-modified-keys) (princ ".") (terpri))))) + (with-current-buffer standard-output + (fill-region-as-paragraph pt2 (point)) + (unless (and (eq ?\n (char-before)) ; Quicker than `looking-back', apparently. + (eq ?\n (char-before (1- (point))))) + (terpri)))))) + + + ;; REPLACE ORIGINAL in `help-fns.el' + ;; + ;; 1. Add key-description buttons to command help: Use `help-documentation', not `documentation'. + ;; 2. Arg RAW is optional, so we can use this with older Emacs versions. + ;; + (defun help-fns--signature (function doc real-def real-function &optional raw) ; Keep RAW optional for old Emacs. + (if (keymapp function) + doc ; If definition is a keymap, skip arglist note. + (let* ((advertised (gethash real-def advertised-signature-table t)) + (arglist (if (listp advertised) advertised (help-function-arglist real-def))) + (usage (help-split-fundoc doc function))) + (when usage (setq doc (cdr usage))) + (let* ((use (cond ((and usage (not (listp advertised))) (car usage)) + ((listp arglist) + (if (fboundp 'help--make-usage-docstring) + (help--make-usage-docstring function arglist) ; Emacs 25+. + (format "%S" (help-make-usage function arglist)))) + ((stringp arglist) arglist) + ;; Maybe the arglist is in the docstring of a symbol this one is aliased to. + ((let ((fun real-function)) + (while (and (symbolp fun) + (setq fun (symbol-function fun)) + (not (setq usage (help-split-fundoc + (help-documentation fun nil 'ADD-HELP-BUTTONS) + function))))) + usage) + (car usage)) + ((or (stringp real-def) (vectorp real-def)) + (format "\nMacro: %s" + (if (fboundp 'help--docstring-quote) + (help--docstring-quote (format-kbd-macro real-def)) ; Emacs 25+. + (format-kbd-macro real-def)))) + (t "[Missing arglist. Please submit a bug report.]"))) + ;; Insert "`X", not "(\` X)", when documenting `X. + (use1 (replace-regexp-in-string "\\`(\\\\=\\\\\\\\=` \\([^\n ]*\\))\\'" "\\\\=`\\1" use t)) + (high (if raw + (cons use1 doc) + (help-highlight-arguments (substitute-command-keys use1) (substitute-command-keys doc))))) + (let ((fill-begin (point)) + (high-usage (car high)) + (high-doc (cdr high))) + (insert high-usage "\n") + (fill-region fill-begin (point)) + high-doc))))) + ) + +(when (and (= emacs-major-version 24) (= emacs-minor-version 3)) + (defun describe-function-1 (function) + (let* ((advised (and (symbolp function) (featurep 'advice) (ad-get-advice-info function))) + ;; If the function is advised, use the symbol that has the real def, if already set up. + (real-function (or (and advised (let ((origname (cdr (assq 'origname advised)))) + (and (fboundp origname) origname))) + function)) + ;; Get the real definition. + (def (if (symbolp real-function) (symbol-function real-function) function)) + (aliased (symbolp def)) + (real-def (if aliased + (let ((fn def)) + (while (and (fboundp fn) (symbolp (symbol-function fn))) + (setq fn (symbol-function fn))) + fn) + def)) + (file-name (find-lisp-object-file-name function def)) + (pt1 (with-current-buffer (help-buffer) (point))) + (beg (if (and (or (byte-code-function-p def) (keymapp def) + (memq (car-safe def) '(macro lambda closure))) + file-name + (help-fns--autoloaded-p function file-name)) + (if (commandp def) "an interactive autoloaded " "an autoloaded ") + (if (commandp def) "an interactive " "a ")))) + ;; Print what kind of function-like object FUNCTION is. + (princ (cond ((or (stringp def) (vectorp def)) "a keyboard macro") + ((subrp def) (if (eq 'unevalled (cdr (subr-arity def))) + (concat beg "special form") + (concat beg "built-in function"))) + ((byte-code-function-p def) (concat beg "compiled Lisp function")) + (aliased (format "an alias for `%s'" real-def)) + ((eq (car-safe def) 'lambda) (concat beg "Lisp function")) + ((eq (car-safe def) 'macro) (concat beg "Lisp macro")) + ((eq (car-safe def) 'closure) (concat beg "Lisp closure")) + ((autoloadp def) + (format "%s autoloaded %s" (if (commandp def) "an interactive" "an") + (if (eq (nth 4 def) 'keymap) + "keymap" + (if (nth 4 def) "Lisp macro" "Lisp function")))) + ((keymapp def) (let ((is-full nil) + (elts (cdr-safe def))) + (while elts + (when (char-table-p (car-safe elts)) + (setq is-full t + elts ())) + (setq elts (cdr-safe elts))) + (concat beg (if is-full "keymap" "sparse keymap")))) + (t ""))) + (if (and aliased (not (fboundp real-def))) + (princ ",\nwhich is not defined. Please submit a bug report.") + (with-current-buffer standard-output + (save-excursion (save-match-data (when (re-search-backward "alias for `\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function real-def))))) + (when file-name + (princ " in `") + ;; We used to add `.el' to the file name, but that's wrong when the user used `load-file'. + (princ (if (eq file-name 'C-source) "C source code" (file-name-nondirectory file-name))) + (princ "'") + ;; Make a hyperlink to the library. + (with-current-buffer standard-output + (save-excursion (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function-def function file-name)))) + (princ ".") + (with-current-buffer (help-buffer) + (fill-region-as-paragraph (save-excursion (goto-char pt1) (forward-line 0) (point)) (point))) + (terpri) (terpri) + (let* ((doc-raw (documentation function 'RAW)) + ;; If the function is autoloaded, and its docstring has key substitution constructs, + ;; load the library. In any case, add help buttons. + (doc (if (and (autoloadp real-def) + doc-raw + help-enable-auto-load + (string-match "\\([^\\]=\\|[^=]\\|\\`\\)\\\\[[{<]" doc-raw) + (load (cadr real-def) t)) + (help-substitute-command-keys doc-raw 'ADD-HELP-BUTTONS) + (condition-case err + (help-documentation function nil 'ADD-HELP-BUTTONS) + (error (format "No Doc! %S" err)))))) + (help-fns--key-bindings function) + (with-current-buffer standard-output + (setq doc (help-fns--signature function doc real-def real-function)) + (help-fns--compiler-macro function) + (help-fns--parent-mode function) + (help-fns--obsolete function) + (insert "\n") + (when (and doc (boundp 'Info-virtual-files)) ; Emacs 23.2+ + (Info-make-manuals-xref function)) ; Link to manuals. (With progress message.) + (insert (or doc "Not documented.")))))))) + +(when (or (> emacs-major-version 24) (and (= emacs-major-version 24) (> emacs-minor-version 3))) + (defun describe-function-1 (function) + (let* ((advised (and (symbolp function) + (featurep 'nadvice) + (advice--p (advice--symbol-function function)))) + ;; If the function is advised, use the symbol that has the real definition, if already set up. + (real-function (or (and advised (advice--cd*r (advice--symbol-function function))) + function)) + ;; Get the real definition. + (def (if (symbolp real-function) (symbol-function real-function) real-function)) + (aliased (or (symbolp def) + (and advised (symbolp real-function)))) ; Advised & aliased function. + (real-def (cond (aliased (let ((f real-function)) + (while (and (fboundp f) (symbolp (symbol-function f))) + (setq f (symbol-function f))) + f)) + ((subrp def) (intern (subr-name def))) + (t def))) + (sig-key (if (subrp def) (indirect-function real-def) real-def)) + (file-name (find-lisp-object-file-name function def)) + (pt1 (with-current-buffer (help-buffer) (point))) + (beg (if (and (or (byte-code-function-p def) (keymapp def) + (memq (car-safe def) '(macro lambda closure))) + (stringp file-name) + (help-fns--autoloaded-p function file-name)) + (if (commandp def) "an interactive autoloaded " "an autoloaded ") + (if (commandp def) "an interactive " "a ")))) + ;; Print what kind of function-like object FUNCTION is. + (princ (cond ((or (stringp def) (vectorp def)) "a keyboard macro") + ((subrp def) (if (eq 'unevalled (cdr (subr-arity def))) + (concat beg "special form") + (concat beg "built-in function"))) + ;; Aliases are Lisp functions, so we need to check aliases before functions. + ;; Do NOT use curly quotes, so do not need to wrap format string in `substitute-command-keys'. + (aliased (format "an alias for `%s'" real-def)) + ((autoloadp def) (format "%s autoloaded %s" + (if (commandp def) "an interactive" "an") + (if (eq (nth 4 def) 'keymap) + "keymap" + (if (nth 4 def) "Lisp macro" "Lisp function")))) + ((or (eq (car-safe def) 'macro) + ;; For advised macros, DEF is a lambda expression or is `byte-code-function-p', + ;; so check macros before functions. + (macrop function)) + (concat beg "Lisp macro")) + ((byte-code-function-p def) (concat beg "compiled Lisp function")) + ((eq (car-safe def) 'lambda) (concat beg "Lisp function")) + ((eq (car-safe def) 'closure) (concat beg "Lisp closure")) + ((keymapp def) (let ((is-full nil) + (elts (cdr-safe def))) + (while elts + (when (char-table-p (car-safe elts)) + (setq is-full t + elts ())) + (setq elts (cdr-safe elts))) + (concat beg (if is-full "keymap" "sparse keymap")))) + (t ""))) + (if (and aliased (not (fboundp real-def))) + (princ ",\nwhich is not defined. Please submit a bug report.") + (with-current-buffer standard-output + (save-excursion (save-match-data (when (re-search-backward "alias for `\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function real-def))))) + (when file-name + (princ " in `") + ;; We used to add `.el' to the file name, but that's wrong when the user used `load-file'. + (princ (if (eq file-name 'C-source) + "C source code" + (if (fboundp 'help-fns-short-filename) + (help-fns-short-filename file-name) ; Emacs 25+ + (file-name-nondirectory file-name)))) + (princ "'") + ;; Make a hyperlink to the library. + (with-current-buffer standard-output + (save-excursion (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function-def function file-name)))) + (princ ".") + (with-current-buffer (help-buffer) + (fill-region-as-paragraph (save-excursion (goto-char pt1) (forward-line 0) (point)) (point))) + (terpri) (terpri) + (let* ((doc-raw (documentation function 'RAW)) + ;; If the function is autoloaded and its docstring has key substitution constructs, then + ;; load the library. In any case, add help buttons. + (doc (if (and (autoloadp real-def) + doc-raw + help-enable-auto-load + (string-match "\\([^\\]=\\|[^=]\\|\\`\\)\\\\[[{<]" doc-raw) + (autoload-do-load real-def)) + (help-substitute-command-keys doc-raw 'ADD-HELP-BUTTONS) + (condition-case err + (help-documentation function nil 'ADD-HELP-BUTTONS) + (error (format "No Doc! %S" err)))))) + (help-fns--key-bindings function) + (with-current-buffer standard-output + (setq doc (if (> emacs-major-version 24) + (help-fns--signature function doc-raw sig-key real-function nil) + (help-fns--signature function doc real-def real-function))) + (run-hook-with-args 'help-fns-describe-function-functions function) + (insert "\n") + (when (and doc (boundp 'Info-virtual-files)) ; Emacs 23.2+ + (Info-make-manuals-xref function)) ; Link to manuals. (With progress message.) + (insert (or doc "Not documented.")))))))) + +;;;###autoload +(defun describe-command (function) ; Bound to `C-h c' + "Describe an Emacs command (interactive function). +Equivalent to using a prefix arg with `describe-function'. + +If you use Icicles then in Icicle mode keys bound to the commands are +shown next to them in `*Completions*. You can toggle this keys +display on/off using `C-x C-a'." + (interactive + (let ((fn (or (and (fboundp 'symbol-nearest-point) (symbol-nearest-point)) + (function-called-at-point))) + (enable-recursive-minibuffers t) + (completion-annotate-function (and (boundp 'icicle-mode) icicle-mode + (lambda (cand) + (with-current-buffer icicle-pre-minibuffer-buffer + (and (setq cand (intern-soft cand)) (symbolp cand) + (let ((key (where-is-internal cand nil t))) + (and key + (format " %s" (icicle-key-description key))))))))) + val) + (setq val (completing-read + (format "Describe command%s: " (if (commandp fn) (format " (default %s)" fn) "")) + obarray 'commandp t nil nil (and fn (commandp fn) (symbol-name fn)))) + (list (if (equal val "") fn (intern val))))) + (describe-function function t)) + + +;; REPLACE ORIGINAL in `help.el': +;; +;; 1. With a prefix argument, candidates are user variables (options) only. +;; 2. Preferred default candidate is `symbol-nearest-point'. +;; 3. Remove initial `*' from doc string (indicates it is a user variable). +;; 4. PREDICATE to `completing-read' uses original buffer (not minibuffer), when testing `boundp'. (BUG #21252) +;; 5. Use `substitute-command-keys' on doc string. +;; 6. Preserve text properties. +;; 7. No message if not called interactively. +;; +(when (< emacs-major-version 23) + (defun describe-variable (variable &optional buffer optionp) + "Display the full documentation of VARIABLE (a symbol). +VARIABLE names an Emacs Lisp variable, possibly a user option. +With a prefix argument, candidates are user variables (options) only. +Default candidate is the `symbol-nearest-point'. +Return the documentation, as a string. +If VARIABLE has a buffer-local value in BUFFER (default to the current buffer), +it is displayed along with the global value." + (interactive + (let ((symb (or (and (fboundp 'symbol-nearest-point) (symbol-nearest-point)) + (variable-at-point))) + (enable-recursive-minibuffers t) + (completion-annotate-function (lambda (var) (and (custom-variable-p (intern-soft var)) " (option)"))) + (curbuf (current-buffer)) + val) + (when (numberp symb) (setq symb nil)) ; `variable-at-point' returns 0 when there is no var. + (setq val (completing-read + (format "Describe variable%s: " + (if (and symb (boundp symb)) (format " (default %s)" symb) "")) + obarray (if current-prefix-arg + `(lambda (vv) (with-current-buffer ',curbuf (user-variable-p vv))) + `(lambda (vv) (with-current-buffer ',curbuf + (or (boundp vv) (get vv 'variable-documentation))))) + t nil nil (and (symbolp symb) (boundp symb) (symbol-name symb)))) + (list (if (equal val "") symb (intern val)) + nil + current-prefix-arg))) + (unless (buffer-live-p buffer) (setq buffer (current-buffer))) + (if (not (symbolp variable)) + (when (interactive-p) (message "You did not specify a variable")) + (unless (or (not optionp) (user-variable-p variable)) + (error "Not a defined Emacs user option: `%s'" variable)) + ;;$$ (unless (boundp variable) (error "Not a defined Emacs variable: `%s'" variable)) + (save-excursion + (let* ((valvoid (not (with-current-buffer buffer (boundp variable)))) + ;; Extract the value before setting up the output buffer, + ;; in case `buffer' *is* the output buffer. + (val (and (not valvoid) (buffer-local-value variable buffer))) + val-start-pos) + (help-setup-xref (list #'describe-variable variable buffer) (interactive-p)) + (with-output-to-temp-buffer (help-buffer) + (with-current-buffer buffer + (prin1 variable) + ;; Make a hyperlink to the library if appropriate. (Don't change the format of the + ;; buffer's initial line in case anything expects the current format.) + (let ((file-name (symbol-file variable 'defvar))) + (setq file-name (describe-simplify-lib-file-name file-name)) + (when (equal file-name "loaddefs.el") + ;; Find the real def site of the preloaded variable. + (let ((location (condition-case nil + (find-variable-noselect variable file-name) + (error nil)))) + (when location + (with-current-buffer (car location) + (when (cdr location) (goto-char (cdr location))) + (when (re-search-backward "^;;; Generated autoloads from \\(.*\\)" nil t) + (setq file-name (match-string 1))))))) + (when (and (null file-name) (integerp (get variable 'variable-documentation))) + ;; It's a var not defined in Elisp but in C. + (setq file-name (if (get-buffer " *DOC*") + (help-C-file-name variable 'var) + 'C-source))) + (if file-name + (progn (princ " is a variable defined in `") + (princ (if (eq file-name 'C-source) "C source code" file-name)) + (princ "'.\n") + (with-current-buffer standard-output + (save-excursion + (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-variable-def variable file-name))) + (if valvoid (princ "It is void as a variable.") (princ "Its "))) + (if valvoid (princ " is void as a variable.") (princ "'s ")))) + (unless valvoid + (with-current-buffer standard-output + (setq val-start-pos (point)) + (princ "value is ") (terpri) + (let ((from (point))) + (pp val) + ;; Hyperlinks in variable's value are quite frequently inappropriate + ;; e.g `C-h v features ' + ;; (help-xref-on-pp from (point)) + (when (< (point) (+ from 20)) (delete-region (1- from) from))))) + (terpri) + (when (local-variable-p variable) + (princ (format "%socal in buffer %s; " + (if (get variable 'permanent-local) "Permanently l" "L") + (buffer-name))) + (if (not (default-boundp variable)) + (princ "globally void") + (let ((val (default-value variable))) + (with-current-buffer standard-output + (princ "global value is ") (terpri) + ;; Fixme: `pp' can take an age if you happen to ask for a very large expression. + ;; We should probably print it raw once and check it's a sensible size before + ;; prettyprinting. -- fx + (let ((from (point))) + (pp val) + ;; See previous comment for this function. + ;; (help-xref-on-pp from (point)) + (when (< (point) (+ from 20)) (delete-region (1- from) from))))))) + ;; Add a note for variables that have been `make-var-buffer-local'. + (when (and (local-variable-if-set-p variable) + (or (not (local-variable-p variable)) + (with-temp-buffer (local-variable-if-set-p variable)))) + (princ "\nAutomatically becomes buffer-local when set in any fashion.\n")) + (terpri) + (with-current-buffer standard-output ; If the value is large, move it to the end. + (when (> (count-lines (point-min) (point-max)) 10) + ;; Note that setting the syntax table like below makes `forward-sexp' move over a + ;; `'s' at the end of a symbol. + (set-syntax-table emacs-lisp-mode-syntax-table) + (goto-char val-start-pos) + ;; The line below previously read as + ;; (delete-region (point) (progn (end-of-line) (point))) + ;; which suppressed display of the buffer local value for large values. + (when (looking-at "value is") (replace-match "")) + (save-excursion (insert "\n\nValue:") + (set (make-local-variable 'help-button-cache) (point-marker))) + (insert "value is shown ") + (insert-button "below" 'action help-button-cache 'follow-link t + 'help-echo "mouse-2, RET: show value") + (insert ".\n"))) + ;; Mention if it's an alias + (let* ((alias (condition-case nil (indirect-variable variable) (error variable))) + (obsolete (get variable 'byte-obsolete-variable)) + (safe-var (get variable 'safe-local-variable)) + (doc (or (documentation-property variable 'variable-documentation) + (documentation-property alias 'variable-documentation)))) + (when (and (> (length doc) 1) (eq ?* (elt doc 0))) + (setq doc (substring doc 1))) ; Remove any user-variable prefix `*'. + (unless (eq alias variable) + (princ (format "\nThis variable is an alias for `%s'.\n" alias))) + (when (or obsolete safe-var) (terpri)) + (when obsolete + (princ "This variable is obsolete") + (when (cdr obsolete) (princ (format " since %s" (cdr obsolete)))) + (princ ";") (terpri) + (princ (if (stringp (car obsolete)) + (car obsolete) + (format "use `%s' instead." (car obsolete)))) + (terpri)) + (when safe-var + (princ "This variable is safe as a file local variable ") + (princ "if its value\nsatisfies the predicate ") + (princ (if (byte-code-function-p safe-var) + "which is byte-compiled expression.\n" + (format "`%s'.\n" safe-var)))) + (princ "\nDocumentation:\n") + ;; Use `insert', not `princ', to keep text properties. + ;; Was: (princ (or doc "Not documented as a variable."))) + (with-current-buffer standard-output + (insert (or (substitute-command-keys doc) "Not documented as a variable.")))) + ;; Make a link to customize if this variable can be customized. + (when (custom-variable-p variable) + (let ((customize-label "customize")) + (terpri) (terpri) (princ (concat "You can " customize-label " this variable.")) + (with-current-buffer standard-output + (save-excursion (re-search-backward (concat "\\(" customize-label "\\)") nil t) + (help-xref-button 1 'help-customize-variable variable))))) + (print-help-return-message) + (with-current-buffer standard-output (buffer-string))))))))) ; Return the text displayed. + +;;; This macro is no different from what is in vanilla Emacs 23+. +;;; Add it here so this file can be byte-compiled with Emacs 22 and used with Emacs 23+. +(defmacro with-selected-frame (frame &rest body) + "Execute the forms in BODY with FRAME as the selected frame. +Save the selected frame, select FRAME, execute BODY, then restore the +originally selected frame. Return the value of the last form in BODY. + +This macro changes the order of neither the recently selected windows +nor the buffers in the buffer list. See also `with-temp-buffer'." + (declare (indent 1) (debug t)) + (let ((old-frame (make-symbol "old-frame")) + (old-buffer (make-symbol "old-buffer"))) + `(let ((,old-frame (selected-frame)) + (,old-buffer (current-buffer))) + (unwind-protect + (progn (if (> emacs-major-version 22) (select-frame ,frame 'NORECORD) (select-frame ,frame)) + ,@body) + (when (frame-live-p ,old-frame) + (if (> emacs-major-version 22) (select-frame ,old-frame 'NORECORD) (select-frame ,old-frame))) + (when (buffer-live-p ,old-buffer) (set-buffer ,old-buffer)))))) + + +;; REPLACE ORIGINAL in `help.el': +;; +;; 1. With a prefix argument, candidates are user variables (options) only. +;; 2. Preferred default candidate is `symbol-nearest-point'. +;; 3. PREDICATE to `completing-read' uses original buffer (not minibuffer), when testing `boundp'. (BUG #21252) +;; 4. Preserve text properties. +;; 5. Remove initial `*' from doc string (indicates it is a user variable). +;; 6. Call `Info-make-manuals-xref' to create a cross-ref link to manuals (Emacs 23.3). +;; 7. Add key-description buttons to command help. Use `insert', not `princ'. +;; 8. No no-function message if not called interactively. +;; +(when (= emacs-major-version 23) + (defun describe-variable (variable &optional buffer frame optionp) + "Display the full documentation of VARIABLE (a symbol). +VARIABLE names an Emacs Lisp variable, possibly a user option. +With a prefix argument, candidates are user variables (options) only. +Default candidate is the `symbol-nearest-point'. +Return the documentation, as a string. +If VARIABLE has a buffer-local value in BUFFER or FRAME +\(default to the current buffer and current frame), +it is displayed along with the global value." + (interactive + (let ((symb (or (and (fboundp 'symbol-nearest-point) (symbol-nearest-point)) + (variable-at-point))) + (enable-recursive-minibuffers t) + (completion-annotate-function (lambda (var) (and (custom-variable-p (intern-soft var)) " (option)"))) + (curbuf (current-buffer)) + val) + (when (numberp symb) (setq symb nil)) ; `variable-at-point' returns 0 when there is no var. + (setq val (completing-read + (format "Describe variable%s: " + (if (and symb (boundp symb)) (format " (default %s)" symb) "")) + obarray + (if current-prefix-arg + `(lambda (vv) (with-current-buffer ',curbuf (user-variable-p vv))) + `(lambda (vv) (with-current-buffer ',curbuf + (or (get vv 'variable-documentation) (and (boundp vv) (not (keywordp vv))))))) + t nil nil (and (symbolp symb) (boundp symb) (symbol-name symb)))) + (list (if (equal val "") symb (intern val)) + nil + nil + current-prefix-arg))) + (let (file-name) + (unless (buffer-live-p buffer) (setq buffer (current-buffer))) + (unless (frame-live-p frame) (setq frame (selected-frame))) + (if (not (symbolp variable)) + (when (if (or (> emacs-major-version 23) ; Emacs 23.1 `called-interactively' accepts no arg. + (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p)) + (message "You did not specify a variable")) + (unless (or (not optionp) (user-variable-p variable)) + (error "Not a defined Emacs user option: `%s'" variable)) + ;;$$ (unless (boundp variable) (error "Not a defined Emacs variable: `%s'" variable)) + (save-excursion + (let ((valvoid (not (with-current-buffer buffer (boundp variable)))) + val val-start-pos locus) + ;; Extract the value before setting up the output buffer, in case BUFFER *is* the + ;; output buffer. + (unless valvoid + (with-selected-frame frame + (with-current-buffer buffer + (setq val (symbol-value variable) + locus (variable-binding-locus variable))))) + (help-setup-xref (list #'describe-variable variable buffer) + (if (or (> emacs-major-version 23) + (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p))) + (with-help-window (help-buffer) + (with-current-buffer buffer + (prin1 variable) + (setq file-name (find-lisp-object-file-name variable 'defvar)) + (if file-name + (progn (princ " is a variable defined in `") + (princ (if (eq file-name 'C-source) + "C source code" + (file-name-nondirectory file-name))) + (princ "'.\n") + (with-current-buffer standard-output + (save-excursion + (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-variable-def variable file-name))) + (if valvoid (princ "It is void as a variable.") (princ "Its "))) + (if valvoid (princ " is void as a variable.") (princ "'s ")))) + (unless valvoid + (with-current-buffer standard-output + (setq val-start-pos (point)) + (princ "value is ") + (let ((from (point))) + (terpri) + (pp val) + (if (< (point) (+ 68 (line-beginning-position 0))) + (delete-region from (1+ from)) + (delete-region (1- from) from))))) + (terpri) + (when locus + (if (bufferp locus) + (princ (format "%socal in buffer %s; " + (if (get variable 'permanent-local) "Permanently l" "L") + (buffer-name))) + (princ (format "It is a frame-local variable; "))) + (if (not (default-boundp variable)) + (princ "globally void") + (let ((val (default-value variable))) + (with-current-buffer standard-output + (princ "global value is ") (terpri) + ;; Fixme: `pp' can take an age if you happen to ask for a very large expression. + ;; We should probably print it raw once and check it's a sensible size before + ;; prettyprinting. -- fx + (let ((from (point))) + (pp val) + ;; See previous comment for this function. + ;; (help-xref-on-pp from (point)) + (when (< (point) (+ from 20)) (delete-region (1- from) from)))))) + (terpri)) + (with-current-buffer standard-output ; If the value is large, move it to the end. + (when (> (count-lines (point-min) (point-max)) 10) + ;; Note that setting the syntax table like below makes `forward-sexp' move over a + ;; `'s' at the end of a symbol. + (set-syntax-table emacs-lisp-mode-syntax-table) + (goto-char val-start-pos) + ;; The line below previously read as + ;; (delete-region (point) (progn (end-of-line) (point))) + ;; which suppressed display of the buffer local value for large values. + (when (looking-at "value is") (replace-match "")) + (save-excursion (insert "\n\nValue:") (terpri) + (set (make-local-variable 'help-button-cache) (point-marker))) + (insert "value is shown ") + (insert-button "below" 'action help-button-cache 'follow-link t + 'help-echo "mouse-2, RET: show value") + (insert ".\n"))) + (terpri) + (let* ((alias (condition-case nil (indirect-variable variable) (error variable))) + (obsolete (get variable 'byte-obsolete-variable)) + (use (car obsolete)) + (safe-var (get variable 'safe-local-variable)) + (vardoc (help-documentation-property variable 'variable-documentation + nil 'ADD-HELP-BUTTONS)) + (vardoc (and (not (equal "" vardoc)) vardoc)) + (doc (or vardoc (help-documentation-property alias 'variable-documentation + nil 'ADD-HELP-BUTTONS))) + (extra-line nil)) + (when (and (> (length doc) 1) (eq ?* (elt doc 0))) + (setq doc (substring doc 1))) ; Remove any user-variable prefix `*'. + ;; Add a note for variables that have been `make-var-buffer-local'. + (when (and (local-variable-if-set-p variable) + (or (not (local-variable-p variable)) + (with-temp-buffer (local-variable-if-set-p variable)))) + (setq extra-line t) + (princ " Automatically becomes buffer-local when set in any fashion.\n")) + ;; Mention if it's an alias + (unless (eq alias variable) + (setq extra-line t) + (princ (format " This variable is an alias for `%s'.\n" alias))) + (when obsolete + (setq extra-line t) + (princ " This variable is obsolete") + (when (cdr obsolete) (princ (format " since %s" (cdr obsolete)))) + (princ (cond ((stringp use) (concat ";\n " use)) + (use (format ";\n use `%s' instead." (car obsolete))) + (t "."))) + (terpri)) + (when (member (cons variable val) file-local-variables-alist) + (setq extra-line t) + (if (member (cons variable val) dir-local-variables-alist) + (let ((file (and (buffer-file-name) + (not (file-remote-p (buffer-file-name))) + (dir-locals-find-file (buffer-file-name))))) + (princ " This variable is a directory local variable") + (when file + (princ (concat "\n from the file \"" (if (consp file) (car file) file) + "\""))) + (princ ".\n")) + (princ " This variable is a file local variable.\n"))) + (when (memq variable ignored-local-variables) + (setq extra-line t) + (princ " This variable is ignored when used as a file local \ +variable.\n")) + ;; Can be both risky and safe, eg `auto-fill-function'. + (when (risky-local-variable-p variable) + (setq extra-line t) + (princ " This variable is potentially risky when used as a \ +file local variable.\n") + (when (assq variable safe-local-variable-values) + (princ " However, you have added it to \ +`safe-local-variable-values'.\n"))) + (when safe-var + (setq extra-line t) + (princ " This variable is safe as a file local variable ") + (princ "if its value\n satisfies the predicate ") + (princ (if (byte-code-function-p safe-var) + "which is byte-compiled expression.\n" + (format "`%s'.\n" safe-var)))) + (when extra-line (terpri)) + (princ "Documentation:\n") + (with-current-buffer standard-output + (insert (or doc "Not documented as a variable.")))) + ;; Make a link to customize if this variable can be customized. + (when (custom-variable-p variable) + (let ((customize-label "customize")) + (terpri) (terpri) + (princ (concat "You can " customize-label " this variable.")) + (with-current-buffer standard-output + (save-excursion (re-search-backward (concat "\\(" customize-label "\\)") nil t) + (help-xref-button 1 'help-customize-variable variable)))) + ;; Note variable's version or package version + (let ((output (describe-variable-custom-version-info variable))) + (when output (terpri) (terpri) (princ output)))) + (when (boundp 'Info-virtual-files) ; Emacs 23.2+ + (unless valvoid + (with-current-buffer standard-output ; Link to manuals. + (Info-make-manuals-xref variable nil nil + (not (if (or (> emacs-major-version 23) + (and (= emacs-major-version 23) + (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p))))))) + (with-current-buffer standard-output (buffer-string))))))))) ; Return the text displayed. + + +;; REPLACE ORIGINAL in `help-fns.el': +;; +;; 1. With a prefix argument, candidates are user variables (options) only. +;; 2. Preferred default candidate is `symbol-nearest-point'. +;; 3. PREDICATE to `completing-read' uses original buffer (not minibuffer), when testing `boundp'. (BUG #21252) +;; 4. Preserve text properties. +;; 5. Remove initial `*' from doc string (indicates it is a user variable). +;; 6. Call `Info-make-manuals-xref' to create a cross-ref link to manuals (Emacs 23.3). +;; 7. Add key-description buttons to command help. Use `insert', not `princ'. +;; 8. No no-function message if not called interactively. +;; +(when (> emacs-major-version 23) + + (defface describe-variable-value '((((background dark)) (:foreground "#58DFFA4FFFFF")) ; a dark cyan + (t (:foreground "Firebrick"))) + "*Face used to highlight the variable value, for `describe-variable'." + :group 'help :group 'faces) + + (defun describe-variable (variable &optional buffer frame optionp) + "Display the full documentation of VARIABLE (a symbol). +With a prefix argument, candidates are user variables (options) only. +Default candidate is the `symbol-nearest-point'. +Return the documentation, as a string. + +VARIABLE names an Emacs Lisp variable, possibly a user option. +If VARIABLE has a buffer-local value in BUFFER or FRAME (default to +the current buffer and current frame) then it is displayed, along with +the global value." + (interactive + (let ((symb (or (and (fboundp 'symbol-nearest-point) (symbol-nearest-point)) + (variable-at-point))) + (enable-recursive-minibuffers t) + (completion-annotate-function (lambda (vv) (and (custom-variable-p (intern-soft vv)) " (option)"))) + (curbuf (current-buffer)) + val) + (when (numberp symb) (setq symb nil)) ; `variable-at-point' returns 0 when there is no var. + (setq val (completing-read + (format "Describe variable%s: " + (if (and symb (boundp symb)) (format " (default %s)" symb) "")) + obarray + (if current-prefix-arg + `(lambda (vv) (with-current-buffer ',curbuf (user-variable-p vv))) + `(lambda (vv) (with-current-buffer ',curbuf + (or (get vv 'variable-documentation) (and (boundp vv) (not (keywordp vv))))))) + t nil nil (and (symbolp symb) (boundp symb) (symbol-name symb)))) + (list (if (equal val "") symb (intern val)) + nil + nil + current-prefix-arg))) + (let (file-name) + (unless (buffer-live-p buffer) (setq buffer (current-buffer))) + (unless (frame-live-p frame) (setq frame (selected-frame))) + (if (not (symbolp variable)) + (when (called-interactively-p 'interactive) (message "You did not specify a variable")) + (unless (or (not optionp) (user-variable-p variable)) + (error "Not a defined Emacs user option: `%s'" variable)) + ;;$$ (unless (boundp variable) (error "Not a defined Emacs variable: `%s'" variable)) + (save-excursion + (let ((valvoid (not (with-current-buffer buffer (boundp variable)))) + (permanent-local (get variable 'permanent-local)) + val val-start-pos locus) + ;; Extract the value before setting up the output buffer, in case BUFFER *is* the output buffer. + (unless valvoid + (with-selected-frame frame + (with-current-buffer buffer + (setq val (symbol-value variable) + locus (variable-binding-locus variable))))) + (help-setup-xref (list #'describe-variable variable buffer) + (called-interactively-p 'interactive)) + (with-help-window (help-buffer) + (with-current-buffer buffer + (prin1 variable) + (setq file-name (find-lisp-object-file-name variable 'defvar)) + (if file-name + (progn (princ " is a variable defined in `") + (princ (if (eq file-name 'C-source) + "C source code" + (file-name-nondirectory file-name))) + (princ "'.\n") + (with-current-buffer standard-output + (save-excursion (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-variable-def variable file-name))) + (if valvoid (princ "It is void as a variable.") (princ "Its "))) + (if valvoid (princ " is void as a variable.") (princ "'s ")))) + (unless valvoid + (with-current-buffer standard-output + (setq val-start-pos (point)) + (princ "value is ") + (let ((from (point)) + (line-beg (line-beginning-position)) + (print-rep (let ((print-quoted t)) (prin1-to-string val)))) + (if (< (+ (length print-rep) (point) (- line-beg)) 68) + (progn (insert print-rep) + (put-text-property from (point) 'face 'describe-variable-value) + (terpri)) + (terpri) + (unless (or (numberp val) (symbolp val) (characterp val) + (and (stringp val) (string-match-p "[\n]" val))) + (terpri)) + (let ((opoint (point))) + (pp val) + (save-excursion (fill-region-as-paragraph opoint (point) nil t t))) + (when (stringp val) (terpri)) + (put-text-property from (point) 'face 'describe-variable-value) + (if (< (point) (+ 68 (line-beginning-position 0))) + (delete-region from (1+ from)) + (delete-region (1- from) from))) + (let* ((sv (get variable 'standard-value)) + (origval (and (consp sv) + (condition-case nil (eval (car sv)) (error :help-eval-error))))) + (when (and (consp sv) + (not (equal origval val)) + (not (equal origval :help-eval-error))) + (princ "\nOriginal value was \n") + (setq from (point)) + (unless (or (numberp origval) (symbolp origval) (characterp origval) + (and (stringp origval) (string-match-p "[\n]" origval))) + (terpri)) + (let ((opoint (point))) + (pp origval) + (save-excursion (fill-region-as-paragraph opoint (point) nil t t))) + (put-text-property from (point) 'face 'describe-variable-value) + (when (< (point) (+ from 20)) (delete-region (1- from) from) (terpri))))))) + (terpri) + (when locus + (cond ((bufferp locus) + (terpri) + (princ (format "%socal in buffer `%s'; " + (if (get variable 'permanent-local) "Permanently l" "L") + (buffer-name buffer)))) + ((framep locus) + (princ (format "It is a frame-local variable; "))) + ((terminal-live-p locus) + (princ (format "It is a terminal-local variable; "))) + (t (princ (format "It is local to %S" locus)))) + (if (not (default-boundp variable)) + (progn (princ "globally void") (terpri)) + (let ((global-val (default-value variable))) + (with-current-buffer standard-output + (princ "global value is") + (if (eq val global-val) + (progn (princ " the same.") (terpri)) + (princ ":") (terpri) (terpri) + ;; Fixme: `pp' can take an age if you happen to ask for a very large expression. + ;; We should probably print it raw once and check whether it is a sensible size, + ;; before prettyprinting. -- fx + (let ((opoint (point))) + (pp global-val) + (save-excursion (fill-region-as-paragraph opoint (point) nil t t)) + (put-text-property opoint (point) 'face 'describe-variable-value) + ;; See previous comment for this function. (help-xref-on-pp opoint (point)) + (when (< (point) (+ opoint 20)) (delete-region (1- opoint) opoint)))))))) + (with-current-buffer standard-output ; If the value is large, move it to the end. + (when (> (count-lines (point-min) (point-max)) 10) + ;; Note that setting the syntax table like below makes `forward-sexp' move over a + ;; `'s' at the end of a symbol. + (set-syntax-table emacs-lisp-mode-syntax-table) + (goto-char val-start-pos) + ;; The line below previously read as (delete-region (point) (progn (end-of-line) (point))), + ;; which suppressed display of the buffer local value for large values. + (when (looking-at "value is") (replace-match "")) + (save-excursion (let ((nl-before (cond ((and (eq ?\n (char-before)) ; vs `looking-back'. + (eq ?\n (char-before (1- (point))))) "") + ((eq ?\n (char-before)) "\n") + (t "\n\n"))) + (nl-after (cond ((looking-at "[\n]") "") + (t "\n")))) + (insert (format "%sValue:%s" nl-before nl-after))) + (set (make-local-variable 'help-button-cache) (point-marker))) + (insert "value is shown ") + (insert-button "below" 'action help-button-cache 'follow-link t + 'help-echo "mouse-2, RET: show value") + (insert ".\n"))) + (terpri) + (let* ((alias (condition-case nil (indirect-variable variable) (error variable))) + (obsolete (get variable 'byte-obsolete-variable)) + (use (car obsolete)) + (safe-var (get variable 'safe-local-variable)) + (vardoc (help-documentation-property variable 'variable-documentation + nil 'ADD-HELP-BUTTONS)) + (vardoc (and (not (equal "" vardoc)) vardoc)) + (doc (or vardoc (help-documentation-property alias 'variable-documentation + nil 'ADD-HELP-BUTTONS))) + (extra-line nil)) + (when (and (> (length doc) 1) (eq ?* (elt doc 0))) + (setq doc (substring doc 1))) ; Remove any user-variable prefix `*'. + (cond ((and (local-variable-if-set-p variable) ; Mention if it's a local variable. + (or (not (local-variable-p variable)) + (with-temp-buffer (local-variable-if-set-p variable)))) + (setq extra-line t) + (princ " Automatically becomes ") + (when permanent-local (princ "permanently ")) + (princ "buffer-local when set.\n")) + ((not permanent-local)) + ((bufferp locus) (princ " This variable's buffer-local value is permanent.\n")) + (t (princ " This variable's value is permanent when it is given a local binding.\n"))) + (unless (eq alias variable) ; Mention if it's an alias. + (setq extra-line t) + (princ (format " This variable is an alias for `%s'.\n" alias))) + (when obsolete + (setq extra-line t) + (princ " This variable is obsolete") + (when (nth 2 obsolete) (princ (format " since %s" (nth 2 obsolete)))) + (princ (cond ((stringp use) (concat ";\n " use)) + (use (format ";\n use `%s' instead." (car obsolete))) + (t "."))) + (terpri)) + (when (member (cons variable val) file-local-variables-alist) + (setq extra-line t) + (if (member (cons variable val) dir-local-variables-alist) + (let ((file (and (buffer-file-name) + (not (file-remote-p (buffer-file-name))) + (dir-locals-find-file (buffer-file-name)))) + (dir-file t)) + (princ " This variable's value is directory-local") + (if (null file) + (princ ".\n") + (princ ", set ") + (when (consp file) ; When result is from cache... + (if (nth 2 file) ; If cache element has an mtime, assume it came from a file. + (setq file (expand-file-name dir-locals-file (car file))) + (setq dir-file nil))) ; Otherwise, assume it was set directly. + (princ (if dir-file "by the file\n `" "for the directory\n `")) + (with-current-buffer standard-output + (insert-text-button file 'type 'help-dir-local-var-def + 'help-args (list variable file))) + (princ "'.\n"))) + (princ " This variable's value is file-local.\n"))) + (when (memq variable ignored-local-variables) + (setq extra-line t) + (princ " This variable is ignored when used as a file-local variable.\n")) + (when (risky-local-variable-p variable) ; Can be both risky & safe, eg `auto-fill-function'. + (setq extra-line t) + (princ " This variable can be risky when used as a file-local variable.\n") + (when (assq variable safe-local-variable-values) + (princ " However, it has been added to `safe-local-variable-values'.\n"))) + (when safe-var + (setq extra-line t) + (princ " This variable is safe as a file local variable ") + (princ "if its value\n satisfies the predicate ") + (princ (if (byte-code-function-p safe-var) + "which is a byte-compiled expression.\n" + (format "`%s'.\n" safe-var)))) + (when extra-line (terpri)) + (princ "Documentation:\n") + (with-current-buffer standard-output (insert (or doc "Not documented as a variable.")))) + ;; Make a link to customize if this variable can be customized. + (when (custom-variable-p variable) + (let ((customize-label "customize")) + (terpri) (terpri) + (princ (concat "You can " customize-label " this variable.")) + (with-current-buffer standard-output + (save-excursion (re-search-backward (concat "\\(" customize-label "\\)") nil t) + (help-xref-button 1 'help-customize-variable variable)))) + ;; Note variable's version or package version + (let ((output (describe-variable-custom-version-info variable))) + (when output (terpri) (terpri) (princ output)))) + (unless valvoid + (with-current-buffer standard-output ; Link to manuals. + (Info-make-manuals-xref variable nil nil (not (called-interactively-p 'interactive))) + (let ((nb-nls (cond ((looking-at "[\n][\n][\n]") 3) + ((looking-at "[\n][\n]") 2) + ((looking-at "[\n]") 1) + (t 0)))) + (delete-region (- (line-beginning-position) nb-nls) (line-beginning-position))))) + (with-current-buffer standard-output (buffer-string))))))))) ; Return the text displayed. + +;;;###autoload +(defun describe-option (variable &optional buffer) ; Bound to `C-h o' + "Describe an Emacs user variable (option). +Same as using a prefix arg with `describe-variable'." + (interactive (let ((symb (or (and (fboundp 'symbol-nearest-point) + (symbol-nearest-point)) + (variable-at-point))) + (enable-recursive-minibuffers t)) + (when (numberp symb) (setq symb nil)) ; `variable-at-point' returns 0 when there is no var. + (list (intern (completing-read + (format "Describe user option%s: " + (if (and symb (user-variable-p symb)) + (format " (default %s)" symb) + "")) + obarray 'user-variable-p + t nil nil (and symb (user-variable-p symb) (symbol-name symb)) t))))) + (describe-variable variable buffer t)) + +;;;###autoload +(defun describe-option-of-type (type option) ; Bound to `C-h C-o' + "Describe an Emacs user OPTION (variable) of a given `defcustom' TYPE. +A prefix argument determines the type-checking behavior: + - None: OPTION is defined with TYPE or a subtype of TYPE. + - Plain `C-u': OPTION is defined with TYPE or a subtype of TYPE, + or its current value is compatible with TYPE. + - Negative: OPTION is defined with TYPE (exact match). + - Non-negative: OPTION is defined with TYPE (exact match), + or its current value is compatible with TYPE. + +If TYPE is nil (default value) then *all* `defcustom' variables are +potential candidates. That is different from using `describe-option', +because `describe-option' includes user-variable candidates not +defined with `defcustom' (with `*'-prefixed doc strings)." + (interactive + (let* ((symb (or (and (fboundp 'symbol-nearest-point) (symbol-nearest-point)) (variable-at-point))) + (typ (car (condition-case err + (read-from-string (let ((types ())) + (mapatoms + (lambda (cand) + (when (custom-variable-p cand) + (push (list + (format + "%s" + (format "%S" (get cand 'custom-type)))) + types)))) + (completing-read "Describe option of type: " + (help-remove-duplicates types) + nil nil nil nil "nil"))) + (end-of-file (error "No such custom type"))))) + (pref-arg current-prefix-arg)) + (when (numberp symb) (setq symb nil)) ; `variable-at-point' returns 0 when there is no var. + (list typ + (intern + (completing-read + (format "Option%s: " (if (and symb (user-variable-p symb)) (format " (default %s)" symb) "")) + obarray + (lambda (v) + (and (custom-variable-p v) + (or (not typ) ; Allow all vars if requested type = nil. + (help-var-is-of-type-p v (list typ) (cond ((not pref-arg) 'inherit) + ((consp pref-arg) 'inherit-or-value) + ((wholenump + (prefix-numeric-value pref-arg)) + 'direct-or-value) + (t 'direct)))))) + t nil nil (and symb (user-variable-p symb) (symbol-name symb)) t))))) + (describe-variable option nil t)) + +(defun help-var-is-of-type-p (variable types &optional mode) + "Return non-nil if VARIABLE satisfies one of the custom types in TYPES. +TYPES is a list of `defcustom' type sexps or a list of regexp strings. +TYPES are matched, in order, against VARIABLE's type definition or +VARIABLE's current value, until one is satisfied or all are tried. + +If TYPES is a list of regexps, then each is regexp-matched against +VARIABLE's custom type. + +Otherwise, TYPES is a list of type sexps, each of which is a +definition acceptable for `defcustom' :type or the first symbol of +such a definition (e.g. `choice'). In this case, two kinds of type +comparison are possible: + +1. VARIABLE's custom type, or its first symbol, is matched using + `equal' against each type in TYPES. + +2. VARIABLE's current value is checked against each type in TYPES to + see if it satisfies one of them. In this case, VARIABLE's own type + is not used; VARIABLE might not even be typed - it could be a + variable not defined using `defcustom'. + +For any of the comparisons against VARIABLE's type, either that type +can be checked directly or its supertypes (inherited types) can also +be checked. + +These different type-checking possibilities depend on the value of +argument MODE, as follows, and they determine the meaning of the +returned value: + +`direct': VARIABLE's type matches a member of list TYPES +`inherit': VARIABLE's type matches or is a subtype of a TYPES member +`value': VARIABLE is bound, and its value satisfies a type in TYPES +`inherit-or-value': `inherit' or `value', tested in that order +`direct-or-value': `direct' or `value', tested in that order +anything else (default): `inherit' + +VARIABLE's current value cannot satisfy a regexp type: it is +impossible to know which concrete types a value must match." + (case mode + ((nil inherit) (help-var-inherits-type-p variable types)) + (inherit-or-value (or (help-var-inherits-type-p variable types) + (help-var-val-satisfies-type-p variable types))) + (value (help-var-val-satisfies-type-p variable types)) + (direct (help-var-matches-type-p variable types)) + (direct-or-value (or (member (get variable 'custom-type) types) + (help-var-val-satisfies-type-p variable types))) + (otherwise (help-var-inherits-type-p variable types)))) + +(defun help-var-matches-type-p (variable types) + "VARIABLE's type matches a member of TYPES." + (catch 'help-type-matches + (let ((var-type (get variable 'custom-type))) + (dolist (type types) + (when (if (stringp type) + (save-match-data (string-match type (format "%s" (format "%S" var-type)))) + (equal var-type type)) + (throw 'help-type-matches t)))) + nil)) + +(defun help-var-inherits-type-p (variable types) + "VARIABLE's type matches or is a subtype of a member of list TYPES." + (catch 'help-type-inherits + (let ((var-type (get variable 'custom-type))) + (dolist (type types) + (while var-type + (when (or (and (stringp type) + (save-match-data (string-match type (format "%s" (format "%S" var-type))))) + (equal type var-type)) + (throw 'help-type-inherits t)) + (when (consp var-type) (setq var-type (car var-type))) + (when (or (and (stringp type) + (save-match-data (string-match type (format "%s" (format "%S" var-type))))) + (equal type var-type)) + (throw 'help-type-inherits t)) + (setq var-type (car (get var-type 'widget-type)))) + (setq var-type (get variable 'custom-type)))) + nil)) + +(defun help-var-val-satisfies-type-p (variable types) + "VARIABLE is bound, and its value satisfies a type in the list TYPES." + (and (boundp variable) + (let ((val (symbol-value variable))) + (and (widget-convert (get variable 'custom-type)) (help-value-satisfies-type-p val types))))) + +(defun help-value-satisfies-type-p (value types) + "Return non-nil if VALUE satisfies a type in the list TYPES." + (catch 'help-type-value-satisfies + (dolist (type types) + (unless (stringp type) ; Skip, for regexp type. + (setq type (widget-convert type)) + (when (condition-case nil ; Satisfies if either :match or :validate. + (progn (when (and (widget-get type :match) (widget-apply type :match value)) + (throw 'help-type-value-satisfies t)) + (when (and (widget-get type :validate) + (progn (widget-put type :value value) + (not (widget-apply type :validate)))) + (throw 'help-type-value-satisfies t))) + (error nil)) + (throw 'help-type-value-satisfies t)))) + nil)) + +(defun help-custom-type (variable) + "Returns the `defcustom' type of VARIABLE. +Returns nil if VARIABLE is not a user option. + +Note: If the library that defines VARIABLE has not yet been loaded, +then `help-custom-type' loads it. Be sure you want to do that +before you call this function." + (and (custom-variable-p variable) + (or (get variable 'custom-type) (progn (custom-load-symbol variable) + (get variable 'custom-type))))) + +;; Borrowed from `ps-print.el' +(defun help-remove-duplicates (list) + "Copy of LIST with duplicate elements removed. Tested with `equal'." + (let ((tail list) + new) + (while tail + (unless (member (car tail) new) (push (car tail) new)) + (pop tail)) + (nreverse new))) + + +;; REPLACE ORIGINAL in `faces.el': +;; +;; Call `Info-make-manuals-xref' to create a cross-ref link to manuals. +;; +(when (or (> emacs-major-version 23) (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (defun describe-face (face &optional frame) + "Display the properties of face FACE on FRAME. +Interactively, FACE defaults to the faces of the character after point +and FRAME defaults to the selected frame. + +If the optional argument FRAME is given, report on face FACE in that frame. +If FRAME is t, report on the defaults for face FACE (for new frames). +If FRAME is omitted or nil, use the selected frame." + (interactive + (list (read-face-name "Describe face" (if (> emacs-major-version 23) + (or (face-at-point t) 'default) + "= `default' face") + t))) + (let* ((attrs '((:family . "Family") + (:foundry . "Foundry") + (:width . "Width") + (:height . "Height") + (:weight . "Weight") + (:slant . "Slant") + (:foreground . "Foreground") + (:background . "Background") + (:underline . "Underline") + (:overline . "Overline") + (:strike-through . "Strike-through") + (:box . "Box") + (:inverse-video . "Inverse") + (:stipple . "Stipple") + (:font . "Font") + (:fontset . "Fontset") + (:inherit . "Inherit"))) + (max-width (apply #'max (mapcar #'(lambda (x) (length (cdr x))) attrs)))) + (help-setup-xref (list #'describe-face face) (called-interactively-p 'interactive)) + (unless face (setq face 'default)) + (unless (listp face) (setq face (list face))) + (with-help-window (help-buffer) + (with-current-buffer standard-output + (dolist (f face) + (when (stringp f) (setq f (intern f))) + ;; We may get called for anonymous faces (i.e., faces expressed using prop-value plists). + ;; Those can't be usefully customized, so ignore them. + (when (symbolp f) + (insert "Face: " (symbol-name f)) + (if (not (facep f)) + (insert " undefined face.\n") + (let ((customize-label "customize this face") + file-name) + (insert (concat " (" (propertize "sample" 'font-lock-face f) ")")) + (princ (concat " (" customize-label ")\n")) + ;; FIXME not sure how much of this belongs here, how much in `face-documentation'. + ;; The latter is not used much, but needs to return nil for undocumented faces. + (let ((alias (get f 'face-alias)) + (face f) + obsolete) + (when alias + (setq face alias) + (insert (format "\n %s is an alias for the face `%s'.\n%s" f alias + (if (setq obsolete (get f 'obsolete-face)) + (format " This face is obsolete%s; use `%s' instead.\n" + (if (stringp obsolete) (format " since %s" obsolete) "") + alias) + "")))) + (insert "\nDocumentation:\n" (or (face-documentation face) + "Not documented as a face.") + "\n\n")) + (with-current-buffer standard-output + (save-excursion (re-search-backward (concat "\\(" customize-label "\\)") nil t) + (help-xref-button 1 'help-customize-face f))) + (setq file-name (find-lisp-object-file-name f 'defface)) + (when file-name + (princ "Defined in `") (princ (file-name-nondirectory file-name)) (princ "'") + (save-excursion ; Make a hyperlink to the library. + (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-face-def f file-name)) + (princ ".") (terpri) (terpri)) + (dolist (a attrs) + (let ((attr (face-attribute f (car a) frame))) + (insert (make-string (- max-width (length (cdr a))) ?\s) + (cdr a) ": " (format "%s" attr)) + (when (and (eq (car a) :inherit) (not (eq attr 'unspecified))) + (save-excursion ; Make a hyperlink to the parent face. + (re-search-backward ": \\([^:]+\\)" nil t) + (help-xref-button 1 'help-face attr))) + (insert "\n"))) + (when (boundp 'Info-virtual-files) ; Emacs 23.2+ + (with-current-buffer standard-output ; Link to manuals. + (Info-make-manuals-xref f nil nil (not (called-interactively-p 'interactive))))))) + (terpri)))))))) + +;;;###autoload +(defun describe-file (filename &optional internal-form-p no-error-p) ; Bound to `C-h M-f' + "Describe the file named FILENAME. +If FILENAME is nil, describe current directory (`default-directory'). + +Starting with Emacs 22, if the file is an image file then: + * Show a thumbnail of the image as well. + * If you have command-line tool `exiftool' installed and in your + `$PATH' or `exec-path', then show EXIF data (metadata) about the + image. See standard Emacs library `image-dired.el' for more + information about `exiftool'. + +If FILENAME is the name of an autofile bookmark and you use library +`Bookmark+', then show also the bookmark information (tags etc.). In +this case, a prefix arg shows the internal form of the bookmark. + +In Lisp code: + +Non-nil optional arg INTERNAL-FORM-P shows the internal form. +Non-nil optional arg NO-ERROR-P prints an error message but does not + raise an error." + (interactive "FDescribe file: \nP") + (unless filename (setq filename default-directory)) + (help-setup-xref `(describe-file ,filename ,internal-form-p ,no-error-p) + (if (or (> emacs-major-version 23) ; Emacs 23.1 `called-interactively' accepts no arg. + (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p))) + (let ((attrs (file-attributes filename)) + ;; Functions `bmkp-*' are defined in `bookmark+.el'. + (bmk (and (fboundp 'bmkp-get-autofile-bookmark) (bmkp-get-autofile-bookmark filename)))) + (if (not attrs) + (if no-error-p (message "Cannot open file `%s'" filename) (error "Cannot open file `%s'" filename)) + (let* ((type (nth 0 attrs)) + (numlinks (nth 1 attrs)) + (uid (nth 2 attrs)) + (gid (nth 3 attrs)) + (last-access (nth 4 attrs)) + (last-mod (nth 5 attrs)) + (last-status-chg (nth 6 attrs)) + (size (nth 7 attrs)) + (permissions (nth 8 attrs)) + ;; Skip 9: t iff file's gid would change if file were deleted and recreated. + (inode (nth 10 attrs)) + (device (nth 11 attrs)) + (thumb-string (and (fboundp 'image-file-name-regexp) ; In `image-file.el' (Emacs 22+). + (if (fboundp 'string-match-p) + (string-match-p (image-file-name-regexp) filename) + (save-match-data + (string-match (image-file-name-regexp) filename))) + (if (fboundp 'display-graphic-p) (display-graphic-p) window-system) + (require 'image-dired nil t) + (image-dired-get-thumbnail-image filename) + (apply #'propertize "XXXX" + `(display ,(append (image-dired-get-thumbnail-image filename) + '(:margin 10)) + rear-nonsticky (display) + mouse-face highlight + follow-link t + help-echo "`mouse-2' or `RET': Show full image" + keymap (keymap + (mouse-2 . (lambda (e) (interactive "e") + (find-file ,filename))) + (13 . (lambda () (interactive) + (find-file ,filename)))))))) + (image-info (and (require 'image-dired nil t) + (fboundp 'image-file-name-regexp) + (if (fboundp 'string-match-p) + (string-match-p (image-file-name-regexp) filename) + (save-match-data + (string-match (image-file-name-regexp) filename))) + (progn (when (if (or (> emacs-major-version 23) + (and (= emacs-major-version 23) + (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p)) + (message "Gathering image data...")) t) + (condition-case nil + (let ((all (help-all-exif-data (expand-file-name filename)))) + (concat + (and all + (not (zerop (length all))) + (format "\nImage Data (EXIF)\n-----------------\n%s" all)))) + (error nil)))) + (help-text (concat + (format "%s\n%s\n\n" filename (make-string (length filename) ?-)) + (format "File Type: %s\n" + (cond ((eq t type) "Directory") + ((stringp type) (format "Symbolic link to `%s'" type)) + (t "Normal file"))) + (format "Permissions: %s\n" permissions) + (and (not (eq t type)) (format "Size in bytes: %g\n" size)) + (format-time-string + "Time of last access: %a %b %e %T %Y (%Z)\n" last-access) + (format-time-string + "Time of last modification: %a %b %e %T %Y (%Z)\n" last-mod) + (format-time-string + "Time of last status change: %a %b %e %T %Y (%Z)\n" last-status-chg) + (format "Number of links: %d\n" numlinks) + (format "User ID (UID): %s\n" uid) + (format "Group ID (GID): %s\n" gid) + (format "Inode: %S\n" inode) + (format "Device number: %s\n" device) + image-info))) + (if (fboundp 'with-help-window) + (with-help-window (help-buffer) + (when bmk + (if internal-form-p + (let* ((bname (bookmark-name-from-full-record bmk)) + (bmk-defn (format "Bookmark `%s'\n%s\n\n%s" bname + (make-string (+ 11 (length bname)) ?-) + (pp-to-string bmk)))) + (princ bmk-defn) (terpri) (terpri)) + (princ (bmkp-bookmark-description bmk 'NO-IMAGE)) (terpri) (terpri))) + (princ help-text)) + (with-output-to-temp-buffer "*Help*" + (when bmk + (if internal-form-p + (let* ((bname (bookmark-name-from-full-record bmk)) + (bmk-defn (format "Bookmark `%s'\n%s\n\n%s" bname + (make-string (+ 11 (length bname)) ?-) + (pp-to-string bmk)))) + (princ bmk-defn) (terpri) (terpri)) + (princ (bmkp-bookmark-description bmk 'NO-IMAGE)) (terpri) (terpri))) + (princ help-text))) + (when thumb-string + (with-current-buffer "*Help*" + (save-excursion + (goto-char (point-min)) + (let ((buffer-read-only nil)) + (when (re-search-forward "Device number:.+\n" nil t) (insert thumb-string)))))) + help-text)))) ; Return displayed text. + +(defun help-all-exif-data (file) + "Return all EXIF data from FILE, using command-line tool `exiftool'." + (with-temp-buffer + (delete-region (point-min) (point-max)) + (unless (eq 0 (call-process shell-file-name nil t nil shell-command-switch + (format "exiftool -All \"%s\"" file))) + (error "Could not get EXIF data")) + (buffer-substring (point-min) (point-max)))) + +(defun describe-keymap (keymap &optional search-symbols-p) ; Bound to `C-h M-k' + "Describe key bindings in KEYMAP. +Interactively, prompt for a variable that has a keymap value. +Completion is available for the variable name. + +Non-interactively: +* KEYMAP can be such a keymap variable or a keymap. +* Non-nil optional arg SEARCH-SYMBOLS-P means that if KEYMAP is not a + symbol then search all variables for one whose value is KEYMAP." + (interactive (list (intern (completing-read "Keymap: " obarray + (lambda (m) (and (boundp m) (keymapp (symbol-value m)))) + t nil 'variable-name-history)))) + (unless (and (symbolp keymap) (boundp keymap) (keymapp (symbol-value keymap))) + (if (not (keymapp keymap)) + (error "%sot a keymap%s" + (if (symbolp keymap) (format "`%S' is n" keymap) "N") + (if (symbolp keymap) " variable" "")) + (let ((sym nil)) + (when search-symbols-p + (setq sym (catch 'describe-keymap + (mapatoms (lambda (symb) (when (and (boundp symb) + (eq (symbol-value symb) keymap) + (not (eq symb 'keymap)) + (throw 'describe-keymap symb))))) + nil))) + (unless sym + (setq sym (gentemp "KEYMAP OBJECT (no variable) ")) + (set sym keymap)) + (setq keymap sym)))) + (setq keymap (or (condition-case nil (indirect-variable keymap) (error nil)) keymap)) ; Follow aliasing. + (let* ((name (symbol-name keymap)) + (doc (if (fboundp 'help-documentation-property) ; Emacs 23+ + (help-documentation-property keymap 'variable-documentation nil 'ADD-HELP-BUTTONS) + (documentation-property keymap 'variable-documentation))) + (doc (and (not (equal "" doc)) doc))) + (help-setup-xref (list #'describe-keymap keymap) + (if (or (> emacs-major-version 23) ; Emacs 23.1 `called-interactively' accepts no arg. + (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p))) + (if (fboundp 'with-help-window) + (with-help-window (help-buffer) + (princ name) (terpri) (princ (make-string (length name) ?-)) (terpri) (terpri) + (when doc + (when (boundp 'Info-virtual-files) ; Emacs 23.2+ + (with-current-buffer "*Help*" ; Link to manuals. + (Info-make-manuals-xref name nil nil (not (if (or (> emacs-major-version 23) + (and (= emacs-major-version 23) + (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p)))))) + (princ doc) (terpri) (terpri)) + ;; Use `insert' instead of `princ', so control chars (e.g. \377) insert correctly. + (with-current-buffer "*Help*" (insert (substitute-command-keys (concat "\\{" name "}"))))) + (with-output-to-temp-buffer "*Help*" + (princ name) (terpri) (princ (make-string (length name) ?-)) (terpri) (terpri) + (when doc + (when (boundp 'Info-virtual-files) ; Emacs 23.2+ + (with-current-buffer "*Help*" ; Link to manuals. + (Info-make-manuals-xref name nil nil (not (if (or (> emacs-major-version 23) + (and (= emacs-major-version 23) + (> emacs-minor-version 1))) + (called-interactively-p 'interactive) + (interactive-p)))))) + (princ doc) (terpri) (terpri)) + ;; Use `insert' instead of `princ', so control chars (e.g. \377) insert correctly. + (with-current-buffer "*Help*" (insert (substitute-command-keys (concat "\\{" name "}")))))))) + + +;; REPLACE ORIGINAL in `package.el': +;; +;; Call `Info-make-manuals-xref' to create a cross-ref link to manuals. +;; +(when (fboundp 'describe-package) ; Emacs 24+ + + (when (or (> emacs-major-version 24) (and (= emacs-major-version 24) (> emacs-minor-version 3))) + (defun describe-package (package) + "Display the full documentation of PACKAGE (a symbol)." + (interactive + (let* ((guess (function-called-at-point))) + (require 'finder-inf nil t) + ;; Load the package list if necessary (but don't activate them). + (unless package--initialized + (package-initialize t)) + (let ((packages (append (mapcar 'car package-alist) + (mapcar 'car package-archive-contents) + (mapcar 'car package--builtins)))) + (unless (memq guess packages) + (setq guess nil)) + (setq packages (mapcar 'symbol-name packages)) + (let ((val + (completing-read (if guess + (format "Describe package (default %s): " + guess) + "Describe package: ") + packages nil t nil nil guess))) + (list (intern val)))))) + (if (not (or (package-desc-p package) (and package (symbolp package)))) + (message "No package specified") + (help-setup-xref (list #'describe-package package) + (called-interactively-p 'interactive)) + (with-help-window (help-buffer) + (with-current-buffer standard-output + (describe-package-1 package) + (let* ((desc (or (and (package-desc-p package) package) + (cadr (assq package package-alist)) + (let ((built-in (assq package package--builtins))) + (if built-in + (package--from-builtin built-in) + (cadr (assq package package-archive-contents)))))) + (name (if desc (package-desc-name desc) package))) + (setq package name) + (Info-make-manuals-xref (concat (symbol-name package) " package") + nil nil (not (called-interactively-p 'interactive))))))))) ; Link to manuals + + (unless (or (> emacs-major-version 24) (and (= emacs-major-version 24) (> emacs-minor-version 3))) + (defun describe-package (package) + "Display the full documentation of PACKAGE (a symbol)." + (interactive + (let* ((guess (function-called-at-point))) + (require 'finder-inf nil t) + ;; Load the package list if necessary (but don't activate them). + (unless package--initialized (package-initialize t)) + (let ((packages (append (mapcar 'car package-alist) (mapcar 'car package-archive-contents) + (mapcar 'car package--builtins)))) + (unless (memq guess packages) (setq guess nil)) + (setq packages (mapcar 'symbol-name packages)) + (let ((val (completing-read (if guess + (format "Describe package (default %s): " guess) + "Describe package: ") + packages nil t nil nil guess))) + (list (if (equal val "") guess (intern val))))))) + (if (not (or (and (fboundp 'package-desc-p) (package-desc-p package)) + (and package (symbolp package)))) + (when (called-interactively-p 'interactive) (message "No package specified")) + (help-setup-xref (list #'describe-package package) (called-interactively-p 'interactive)) + (with-help-window (help-buffer) + (with-current-buffer standard-output + (describe-package-1 package) + (when (fboundp 'package-desc-name) (setq package (package-desc-name package))) ; Emacs 24.4 + (Info-make-manuals-xref (concat (symbol-name package) " package") + nil nil (not (called-interactively-p 'interactive)))))))) ; Link to manuals + + ) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(provide 'help-fns+) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; help-fns+.el ends here diff --git a/layers/+distributions/spacemacs-base/packages.el b/layers/+distributions/spacemacs-base/packages.el index 59ea8f0..6d5f3c9 100644 --- a/layers/+distributions/spacemacs-base/packages.el +++ b/layers/+distributions/spacemacs-base/packages.el @@ -28,7 +28,7 @@ ;; some packages need to look for binaries, ;; which means the path must be ready by then (exec-path-from-shell :step pre) - help-fns+ + (help-fns+ :location local) (hi-lock :location built-in) (holy-mode :location local :step pre) (hybrid-mode :location local :step pre) diff --git a/layers/+emacs/org/packages.el b/layers/+emacs/org/packages.el index 06d7319..d6fad0e 100644 --- a/layers/+emacs/org/packages.el +++ b/layers/+emacs/org/packages.el @@ -24,8 +24,7 @@ (org :location built-in) (org-agenda :location built-in) org-download - ;; org-mime is installed by `org-plus-contrib' - (org-mime :location built-in) + org-mime org-pomodoro org-present (org-projectile :toggle (configuration-layer/package-usedp 'projectile)) diff --git a/layers/+intl/chinese/packages.el b/layers/+intl/chinese/packages.el index ac76750..4d9812f 100644 --- a/layers/+intl/chinese/packages.el +++ b/layers/+intl/chinese/packages.el @@ -13,7 +13,7 @@ ;; which require an initialization must be listed explicitly in the list. (setq chinese-packages '( - (chinese-pyim :toggle (eq chinese-default-input-method 'pinyin)) + (pyim :toggle (eq chinese-default-input-method 'pinyin)) (chinese-wbim :toggle (eq chinese-default-input-method 'wubi)) (fcitx :toggle chinese-enable-fcitx) find-by-pinyin-dired @@ -59,18 +59,16 @@ ;; Enable Chinese word segmentation support youdao-dictionary-use-chinese-word-segmentation t)))) -(defun chinese/init-chinese-pyim () - (use-package chinese-pyim +(defun chinese/init-pyim () + (use-package pyim :if (eq 'pinyin chinese-default-input-method) :init (progn - (setq pyim-use-tooltip t + (setq pyim-page-tooltip t pyim-directory (expand-file-name "pyim/" spacemacs-cache-directory) - pyim-dicts-directory (expand-file-name "dicts/" pyim-directory) pyim-dcache-directory (expand-file-name "dcache/" pyim-directory) - pyim-personal-file (expand-file-name "pyim-personal.txt" pyim-directory) - default-input-method "chinese-pyim") - (evilified-state-evilify pyim-dicts-manager-mode pyim-dicts-manager-mode-map)))) + default-input-method "pyim") + (evilified-state-evilify pyim-dm-mode pyim-dm-mode-map)))) (defun chinese/init-find-by-pinyin-dired () (use-package find-by-pinyin-dired diff --git a/layers/+lang/ess/README.org b/layers/+lang/ess/README.org index 8d65028..e6992a6 100644 --- a/layers/+lang/ess/README.org +++ b/layers/+lang/ess/README.org @@ -44,11 +44,10 @@ Send code to inferior process with these commands: ** Helpers Helpers for inspecting objects at point are available in R buffers only. -| Key Binding | Description | -|-------------+---------------------------------------------------------------------| -| ~SPC m h d~ | view data under point using [ess-R-data-view][ess-R-data-view] | -| ~SPC m h i~ | object introspection popup [ess-R-object-popup][ess-R-object-popup] | -| ~SPC m h t~ | view table using [ess-R-data-view][ess-R-data-view] | +| Key Binding | Description | +|-------------+----------------------------------------------------------------| +| ~SPC m h d~ | view data under point using [ess-R-data-view][ess-R-data-view] | +| ~SPC m h t~ | view table using [ess-R-data-view][ess-R-data-view] | * Options =ess-smart-equals= is disabled by default. In order to enable it, set in your diff --git a/layers/+lang/ess/packages.el b/layers/+lang/ess/packages.el index 5f32dbd..9b9012d 100644 --- a/layers/+lang/ess/packages.el +++ b/layers/+lang/ess/packages.el @@ -13,7 +13,6 @@ '( ess ess-R-data-view - ess-R-object-popup ess-smart-equals golden-ratio org)) @@ -104,7 +103,6 @@ "st" 'ess-eval-function ;; R helpers "hd" 'ess-R-dv-pprint - "hi" 'ess-R-object-popup "ht" 'ess-R-dv-ctable ) (define-key ess-mode-map (kbd "") 'ess-eval-line) @@ -113,8 +111,6 @@ (defun ess/init-ess-R-data-view ()) -(defun ess/init-ess-R-object-popup ()) - (defun ess/init-ess-smart-equals () (use-package ess-smart-equals :defer t diff --git a/layers/+lang/extra-langs/packages.el b/layers/+lang/extra-langs/packages.el index 7dd784b..1567a13 100644 --- a/layers/+lang/extra-langs/packages.el +++ b/layers/+lang/extra-langs/packages.el @@ -7,7 +7,9 @@ scad-mode stan-mode thrift - wolfram-mode + ;; removed from MELPA (https://github.com/syl20bnr/spacemacs/issues/9795) + ;; TODO re-enable this mode when it is added back to MELPA + ;; wolfram-mode )) (defun extra-langs/init-arduino-mode () diff --git a/layers/+lang/python/packages.el b/layers/+lang/python/packages.el index 2c06f15..81b92f4 100644 --- a/layers/+lang/python/packages.el +++ b/layers/+lang/python/packages.el @@ -57,8 +57,10 @@ "ga" 'anaconda-mode-find-assignments "gb" 'anaconda-mode-go-back "gu" 'anaconda-mode-find-references) - (evilified-state-evilify anaconda-mode-view-mode anaconda-mode-view-mode-map + + (evilified-state-evilify anaconda-view-mode anaconda-view-mode-map (kbd "q") 'quit-window) + (spacemacs|hide-lighter anaconda-mode) (defadvice anaconda-mode-goto (before python/anaconda-mode-goto activate) @@ -84,8 +86,8 @@ :init (progn (spacemacs/set-leader-keys-for-major-mode 'cython-mode - "hh" 'anaconda-mode-view-doc - "gu" 'anaconda-mode-usages)))) + "hh" 'anaconda-mode-show-doc + "gu" 'anaconda-mode-find-references)))) (defun python/post-init-eldoc () (defun spacemacs//init-eldoc-python-mode () diff --git a/layers/+spacemacs/spacemacs-completion/funcs.el b/layers/+spacemacs/spacemacs-completion/funcs.el index 8466865..1cfd21a 100644 --- a/layers/+spacemacs/spacemacs-completion/funcs.el +++ b/layers/+spacemacs/spacemacs-completion/funcs.el @@ -112,7 +112,7 @@ (window-height . 0.4))) (defvar spacemacs-display-buffer-alist nil) -(defun spacemacs//display-helm-window (buffer) +(defun spacemacs//display-helm-window (buffer &optional resume) "Display the Helm window respecting `dotspacemacs-helm-position'." (let ((display-buffer-alist (list spacemacs-helm-display-help-buffer-regexp diff --git a/layers/+spacemacs/spacemacs-editing-visual/local/hide-comnt/hide-comnt.el b/layers/+spacemacs/spacemacs-editing-visual/local/hide-comnt/hide-comnt.el new file mode 100644 index 0000000..07e3e5e --- /dev/null +++ b/layers/+spacemacs/spacemacs-editing-visual/local/hide-comnt/hide-comnt.el @@ -0,0 +1,312 @@ +;;; hide-comnt.el --- Hide/show comments in code. +;; +;; Filename: hide-comnt.el +;; Description: Hide/show comments in code. +;; Author: Drew Adams +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 2011-2017, Drew Adams, all rights reserved. +;; Created: Wed May 11 07:11:30 2011 (-0700) +;; Version: 0 +;; Package-Requires: () +;; Last-Updated: Thu Feb 23 07:40:11 2017 (-0800) +;; By: dradams +;; Update #: 228 +;; URL: https://www.emacswiki.org/emacs/download/hide-comnt.el +;; Doc URL: http://www.emacswiki.org/HideOrIgnoreComments +;; Keywords: comment, hide, show +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Hide/show comments in code. +;; +;; Comments are hidden by giving them and `invisible' property of +;; value `hide-comment'. +;; +;; +;; Macros defined here: +;; +;; `with-comments-hidden'. +;; +;; Commands defined here: +;; +;; `hide/show-comments', `hide/show-comments-toggle'. +;; +;; User options defined here: +;; +;; `hide-whitespace-before-comment-flag', `ignore-comments-flag', +;; `show-invisible-comments-shows-all'. +;; +;; Non-interactive functions defined here: +;; +;; `hide/show-comments-1'. +;; +;; +;; Put this in your init file (`~/.emacs'): +;; +;; (require 'hide-comnt) +;; +;; +;; Note for Emacs 20: The commands and option defined here DO NOTHING +;; IN EMACS 20. Nevertheless, the library can be byte-compiled in +;; Emacs 20 and `hide-comnt.elc' can be loaded in later Emacs +;; versions and used there. This is the only real use of this +;; library for Emacs 20: it provides macro `with-comments-hidden'. +;; +;; Note for Emacs 21: It lacks the `comment-forward' function, so we +;; rely on the `comment-end' variable to determine the end of a +;; comment. This means that only one type of comment terminator is +;; supported. For example, `c++-mode' sets `comment-end' to "", +;; which is the convention for single-line comments ("// COMMENT"). +;; So "/* */" comments are treated as single-line commentsonly the +;; first line of such comments is hidden. The "*/" terminator is not +;; taken into account. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change Log: +;; +;; 2017/01/16 dadams +;; hide/show-comments-1: ((add-to|remove-from)-invisibility-spec 'hide-comment). +;; See https://github.com/syl20bnr/spacemacs/issues/8123. +;; 2016/12/27 dadams +;; Added: show-invisible-comments-shows-all. +;; hide/show-comments(-1): Respect show-invisible-comments-shows-all. +;; NOTE: Default behavior has changed: other invisible text is no longer made visible. +;; 2015/08/01 dadams +;; Added hide/show-comments-1. (And removed save-excursion around looking-back etc.) +;; hide/show-comments: +;; Use with-silent-modifications if available. Use hide/show-comments-1. +;; 2015/07/31 dadams +;; hide/show-comments: +;; Bind buffer-file-name to nil to inhibit ask-user-about-supersession-threat. +;; 2015/07/29 dadams +;; hide/show-comments: +;; No-op if no comment-start. Pass NOERROR arg to comment-normalize-vars. +;; 2014/11/05 dadams +;; hide/show-comments: +;; Use comment-forward even for "", so handle setting CEND correctly, e.g., for C++, +;; where comment-end is "" but multi-line comments are also OK. +;; Do not hide newline after single-line comments. +;; hide-whitespace-before-comment-flag non-nil no longer hides empty lines. +;; Prevent infloop for comment at bol. +;; Thx to Hinrik Sigurosson. +;; 2014/02/06 dadams +;; Added: hide-whitespace-before-comment-flag. +;; hide/show-comments: +;; Go to start of comment before calling comment-forward. +;; Hide whitespace preceding comment, if hide-whitespace-before-comment-flag. +;; 2013/12/26 dadams +;; hide/show-comments: Update START to comment end or END. +;; 2013/10/09 dadams +;; hide/show-comments: Use save-excursion. If empty comment-end go to CBEG. +;; Use comment-forward if available. +;; 2012/10/06 dadams +;; hide/show-comments: Call comment-normalize-vars first. Thx to Stefan Monnier. +;; hide/show-comments-toggle: Do nothing if newcomment.el not available. +;; 2012/05/10 dadams +;; Added: hide/show-comments-toggle. Thx to Denny Zhang for the suggestion. +;; 2011/11/23 dadams +;; hide/show-comments: Bug fix - ensure CEND is not past eob. +;; 2011/05/11 dadams +;; Created: moved code here from thing-cmds.el. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + + +(defvar comment-start) ; In `newcomment.el'. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;###autoload +(defcustom ignore-comments-flag t + "*Non-nil means macro `with-comments-hidden' hides comments." + :type 'boolean :group 'matching) + +;;;###autoload +(defcustom hide-whitespace-before-comment-flag t + "*Non-nil means `hide/show-comments' hides whitespace preceding a comment. +It does not hide empty lines (newline chars), however." + :type 'boolean :group 'matching) + +;;;###autoload +(defcustom show-invisible-comments-shows-all nil + "Non-nil means `(hide/show-comments 'show ...)' shows all invisible text. +The default value, nil, means it shows only text that was made +invisible by `(hide/show-comments 'hide ...)'." + :type 'boolean :group 'matching) + + +(defmacro with-comments-hidden (start end &rest body) + "Evaluate the forms in BODY while comments are hidden from START to END. +But if `ignore-comments-flag' is nil, just evaluate BODY, +without hiding comments. Show comments again when BODY is finished. + +See `hide/show-comments', which is used to hide and show the comments. +Note that prior to Emacs 21, this never hides comments." + (let ((result (make-symbol "result")) + (ostart (make-symbol "ostart")) + (oend (make-symbol "oend"))) + `(let ((,ostart ,start) + (,oend ,end) + ,result) + (unwind-protect (setq ,result (progn (when ignore-comments-flag + (hide/show-comments 'hide ,ostart ,oend)) + ,@body)) + (when ignore-comments-flag (hide/show-comments 'show ,ostart ,oend)) + ,result)))) + +;;;###autoload +(defun hide/show-comments (&optional hide/show start end) + "Hide or show comments from START to END. +Interactively, hide comments, or show them if you use a prefix arg. +\(This is thus *NOT* a toggle command.) + +If option `hide-whitespace-before-comment-flag' is non-nil, then hide +also any whitespace preceding a comment. + +Interactively, START and END default to the region limits, if active. +Otherwise, including non-interactively, they default to `point-min' +and `point-max'. + +Uses `save-excursion', restoring point. + +Option `show-invisible-comments-shows-all': + +* If non-nil then using this command to show invisible text shows + *ALL* such text, regardless of how it was hidden. IOW, it does not + just show invisible text that you previously hid using this command. + +* If nil (the default value) then using this command to show invisible + text makes visible only such text that was previously hidden by this + command. (More precisely, it makes visible only text whose + `invisible' property has value `hide-comment'.) + +From Lisp, a HIDE/SHOW value of `hide' hides comments. Other values +show them. + +This command does nothing in Emacs versions prior to Emacs 21, because +it needs `comment-search-forward'." + + (interactive + (cons (if current-prefix-arg 'show 'hide) + (if (or (not mark-active) (null (mark)) (= (point) (mark))) + (list (point-min) (point-max)) + (if (< (point) (mark)) (list (point) (mark)) (list (mark) (point)))))) + (when (and comment-start ; No-op if no comment syntax defined. + (require 'newcomment nil t)) ; `comment-search-forward', Emacs 21+. + (comment-normalize-vars 'NO-ERROR) ; Must call this first. + (unless start (setq start (point-min))) + (unless end (setq end (point-max))) + (unless (<= start end) (setq start (prog1 end (setq end start)))) ; Swap. + (if (fboundp 'with-silent-modifications) + (with-silent-modifications ; Emacs 23+. + (restore-buffer-modified-p nil) (hide/show-comments-1 hide/show start end)) + (let ((bufmodp (buffer-modified-p)) ; Emacs < 23. + (buffer-read-only nil) + (buffer-file-name nil)) ; Inhibit `ask-user-about-supersession-threat'. + (set-buffer-modified-p nil) + (unwind-protect (hide/show-comments-1 hide/show start end) + (set-buffer-modified-p bufmodp)))))) + +;; Used only so that we can use `hide/show-comments' with older Emacs releases that do not +;; have macro `with-silent-modifications' and built-in `restore-buffer-modified-p', which +;; it uses. +(defun hide/show-comments-1 (hide/show start end) + "Helper for `hide/show-comments'." + (let (cbeg cend) + (if (eq 'hide hide/show) + (add-to-invisibility-spec 'hide-comment) + (remove-from-invisibility-spec 'hide-comment)) + (save-excursion + (goto-char start) + (while (and (< start end) (save-excursion + (setq cbeg (comment-search-forward end 'NOERROR)))) + (goto-char cbeg) + (save-excursion + (setq cend (cond ((fboundp 'comment-forward) ; Emacs 22+ + (if (comment-forward 1) + (if (= (char-before) ?\n) (1- (point)) (point)) + end)) + ((string= "" comment-end) (min (line-end-position) end)) + (t (search-forward comment-end end 'NOERROR))))) + (when hide-whitespace-before-comment-flag ; Hide preceding whitespace. + (if (fboundp 'looking-back) ; Emacs 22+ + (when (looking-back "\n?\\s-*" nil 'GREEDY) + (setq cbeg (match-beginning 0))) + (while (memq (char-before cbeg) '(?\ ?\t ?\f)) (setq cbeg (1- cbeg))) + (when (eq (char-before cbeg) ?\n) (setq cbeg (1- cbeg)))) + ;; First line: Hide newline after comment. + (when (and (= cbeg (point-min)) (= (char-after cend) ?\n)) + (setq cend (min (1+ cend) end)))) + (when (and cbeg cend) + (if show-invisible-comments-shows-all + (put-text-property cbeg cend 'invisible (and (eq 'hide hide/show) + 'hide-comment)) + (while (< cbeg cend) + ;; Do nothing to text that is already invisible for some other reason. + (unless (and (get-text-property cbeg 'invisible) + (not (eq 'hide-comment (get-text-property cbeg 'invisible)))) + (put-text-property cbeg (1+ cbeg) 'invisible (and (eq 'hide hide/show) + 'hide-comment))) + (setq cbeg (1+ cbeg))))) + (goto-char (setq start (or cend end))))))) + +(defun hide/show-comments-toggle (&optional start end) + "Toggle hiding/showing of comments in the active region or whole buffer. +If the region is active then toggle in the region. Otherwise, in the +whole buffer. + +This command does nothing in Emacs versions prior to Emacs 21, because +it needs `comment-search-forward'. + +Interactively, START and END default to the region limits, if active. +Otherwise, including non-interactively, they default to `point-min' +and `point-max'. + +See `hide/show-comments' for more information." + (interactive (if (or (not mark-active) (null (mark)) (= (point) (mark))) + (list (point-min) (point-max)) + (if (< (point) (mark)) (list (point) (mark)) (list (mark) (point))))) + (when (require 'newcomment nil t) ; `comment-search-forward', Emacs 21+. + (comment-normalize-vars) ; Must call this first. + (if (save-excursion + (goto-char start) + (and (comment-search-forward end 'NOERROR) + (if show-invisible-comments-shows-all + (get-text-property (point) 'invisible) + (eq 'hide-comment (get-text-property (point) 'invisible))))) + (hide/show-comments 'show start end) + (hide/show-comments 'hide start end)))) + +;;;;;;;;;;;;;;;;;;;;;;;; + +(provide 'hide-comnt) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; hide-comnt.el ends here diff --git a/layers/+spacemacs/spacemacs-editing-visual/packages.el b/layers/+spacemacs/spacemacs-editing-visual/packages.el index 733fd18..23669e6 100644 --- a/layers/+spacemacs/spacemacs-editing-visual/packages.el +++ b/layers/+spacemacs/spacemacs-editing-visual/packages.el @@ -15,7 +15,7 @@ adaptive-wrap auto-highlight-symbol column-enforce-mode - hide-comnt + (hide-comnt :location local) highlight-indentation highlight-numbers highlight-parentheses diff --git a/layers/+spacemacs/spacemacs-ui/local/info+/info+.el b/layers/+spacemacs/spacemacs-ui/local/info+/info+.el new file mode 100644 index 0000000..217b054 --- /dev/null +++ b/layers/+spacemacs/spacemacs-ui/local/info+/info+.el @@ -0,0 +1,5040 @@ +;;; info+.el --- Extensions to `info.el'. -*- coding:utf-8 -*- +;; +;; Filename: info+.el +;; Description: Extensions to `info.el'. +;; Author: Drew Adams +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 1996-2017, Drew Adams, all rights reserved. +;; Created: Tue Sep 12 16:30:11 1995 +;; Version: 0 +;; Package-Requires: () +;; Last-Updated: Fri Nov 17 10:02:09 2017 (-0800) +;; By: dradams +;; Update #: 6275 +;; URL: https://www.emacswiki.org/emacs/download/info%2b.el +;; Doc URL: https://www.emacswiki.org/emacs/InfoPlus +;; Keywords: help, docs, internal +;; Compatibility: GNU Emacs: 23.x, 24.x, 25.x +;; +;; Features that might be required by this library: +;; +;; `apropos', `apropos+', `avoid', `backquote', `bookmark', +;; `bookmark+', `bookmark+-1', `bookmark+-bmu', `bookmark+-key', +;; `bookmark+-lit', `button', `cl', `cmds-menu', `col-highlight', +;; `crosshairs', `fit-frame', `font-lock', `font-lock+', +;; `frame-fns', `help+', `help-fns', `help-fns+', `help-macro', +;; `help-macro+', `help-mode', `hl-line', `hl-line+', `info', +;; `info+', `kmacro', `menu-bar', `menu-bar+', `misc-cmds', +;; `misc-fns', `naked', `pp', `pp+', `second-sel', `strings', +;; `syntax', `thingatpt', `thingatpt+', `view', `vline', +;; `w32browser-dlgopen', `wid-edit', `wid-edit+'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Extensions to `info.el'. +;; +;; More description below. +;; +;; If you use Emacs 20, 21, or 22 then use library `info+20.el' +;; instead of `info+.el'. + +;;(@> "Index") +;; +;; Index +;; ----- +;; +;; If you have library `linkd.el', load `linkd.el' and turn on +;; `linkd-mode' now. It lets you easily navigate around the sections +;; of this doc. Linkd mode will highlight this Index, as well as the +;; cross-references and section headings throughout this file. You +;; can get `linkd.el' here: +;; https://www.emacswiki.org/emacs/download/linkd.el. +;; +;; (@> "Things Defined Here") +;; (@> "Documentation") +;; (@> "Macros") +;; (@> "Faces (Customizable)") +;; (@> "User Options (Customizable)") +;; (@> "Internal Variables") +;; (@> "New Commands") +;; (@> "Replacements for Existing Functions") +;; (@> "Non-Interactive Functions") + +;;(@* "Things Defined Here") +;; +;; Things Defined Here +;; ------------------- +;; +;; Commands defined here: +;; +;; `Info-breadcrumbs-in-mode-line-mode', +;; `Info-change-visited-status' (Emacs 24+), +;; `Info-describe-bookmark' (Emacs 24.2+), +;; `Info-follow-nearest-node-new-window', `Info-goto-node-web', +;; `Info-history-clear', `Info-make-node-unvisited', `info-manual', +;; `Info-merge-subnodes', +;; `Info-mouse-follow-nearest-node-new-window', +;; `Info-outline-demote', `Info-outline-promote', +;; `Info-persist-history-mode' (Emacs 24.4+), +;; `Info-save-current-node', `Info-set-breadcrumbs-depth', +;; `Info-set-face-for-bookmarked-xref' (Emacs 24.2+), +;; `Info-toggle-breadcrumbs-in-header', +;; `Info-toggle-fontify-angle-bracketed', +;; `Info-toggle-fontify-bookmarked-xrefs' (Emacs 24.2+), +;; `Info-toggle-fontify-emphasis', +;; `Info-toggle-fontify-quotations', +;; `Info-toggle-fontify-single-quote', +;; `Info-toggle-node-access-invokes-bookmark' (Emacs 24.4+), +;; `Info-toc-outline', `Info-toc-outline-refontify-region', +;; `Info-url-for-node', `Info-virtual-book'. +;; +;; Faces defined here: +;; +;; `info-command-ref-item', `info-constant-ref-item', +;; `info-double-quoted-name', `info-emphasis', `info-file', +;; `info-function-ref-item',`info-macro-ref-item', `info-menu', +;; `info-node', `info-quoted-name', `info-reference-item', +;; `info-single-quote', `info-special-form-ref-item', +;; `info-string', `info-syntax-class-item', +;; `info-user-option-ref-item', `info-variable-ref-item', +;; `info-xref-bookmarked' (Emacs 24.2+). +;; +;; Options (user variables) defined here: +;; +;; `Info-bookmarked-node-xref-faces' (Emacs 24.2+), +;; `Info-breadcrumbs-in-header-flag', +;; `Info-display-node-header-fn', `Info-emphasis-regexp', +;; `Info-fit-frame-flag', `Info-fontify-angle-bracketed-flag', +;; `Info-fontify-bookmarked-xrefs-flag' (Emacs 24.2+), +;; `Info-fontify-emphasis-flag', `Info-fontify-quotations-flag', +;; `Info-fontify-reference-items-flag', +;; `Info-fontify-single-quote-flag', +;; `Info-node-access-invokes-bookmark-flag' (Emacs 24.4+), +;; `Info-saved-history-file' (Emacs 24.4+), `Info-saved-nodes', +;; `Info-subtree-separator', `Info-toc-outline-no-redundancy-flag'. +;; +;; Macros defined here: +;; +;; `info-user-error'. +;; +;; Non-interactive functions defined here: +;; +;; `Info-bookmark-for-node', `Info-bookmark-name-at-point', +;; `Info-bookmark-named-at-point', `Info-bookmark-name-for-node', +;; `Info-display-node-default-header', `info-fontify-quotations', +;; `info-fontify-reference-items', +;; `Info-insert-breadcrumbs-in-mode-line', `Info-isearch-search-p', +;; `Info-node-name-at-point', `Info-read-bookmarked-node-name', +;; `Info-restore-history-list' (Emacs 24.4+), +;; `Info-save-history-list' (Emacs 24.4+), `Info-search-beg', +;; `Info-search-end', `Info-toc-outline-find-node', +;; `Info-toc-outline-refontify-links'. +;; +;; Internal variables defined here: +;; +;; `Info-breadcrumbs-depth-internal', `info-fontify-emphasis', +;; `Info-merged-map', `Info-mode-syntax-table', +;; `info-quotation-regexp', `info-quoted+<>-regexp', +;; `Info-toc-outline-map'. +;; +;; +;; ***** NOTE: The following standard faces defined in `info.el' +;; have been REDEFINED HERE: +;; +;; `info-title-1', `info-title-2', `info-title-3', `info-title-4'. +;; +;; +;; ***** NOTE: The following standard functions defined in `info.el' +;; have been REDEFINED or ADVISED HERE: +;; +;; `info-display-manual' - Use completion to input manual name. +;; `Info-find-emacs-command-nodes' - Added arg MSGP and message. +;; `Info-find-file' - Handle virtual books. +;; `Info-find-node', `Info-find-node-2' - +;; Call `fit-frame' if `Info-fit-frame-flag'. +;; Added optional arg NOMSG. +;; `Info-fontify-node' - +;; 1. Show breadcrumbs in header line and/or mode line. +;; 2. File name in face `info-file'. +;; 3. Node names in face `info-node'. +;; 4. Menu items in face `info-menu'. +;; 5. Only 5th and 9th menu items have their `*' colored. +;; 6. Notes in face `info-xref'. +;; 7. If `Info-fontify-emphasis-flag', then fontify _..._. +;; 8. If `Info-fontify-quotations-flag', then fontify ‘...’ or +;; `...' in face `info-quoted-name', “...” in face +;; `info-double-quoted-name', and "..." in face `info-string'. +;; 9. If `Info-fontify-angle-bracketed-flag' and +;; `Info-fontify-quotations-flag' then fontify <...> in face +;; `info-quoted-name'. +;; 10. If `Info-fontify-single-quote-flag' and +;; `Info-fontify-quotations-flag', then fontify ' in face +;; `info-single-quote'. +;; `Info-goto-emacs-command-node' - +;; 1. Uses `completing-read' in interactive spec, with, +;; as default, `symbol-nearest-point'. +;; 2. Added optional arg MSGP. +;; 3. Message if single node found. +;; 4. Returns `num-matches' if found; nil if not. +;; `Info-goto-emacs-key-command-node' - +;; 1. Added optional arg MSGP. +;; 2. If key's command not found, then `Info-search's for key +;; sequence in text and displays message about repeating. +;; `Info-goto-node' - Respect option +;; `Info-node-access-invokes-bookmark-flag' (Emacs 24.4+). +;; `Info-history' - A prefix arg clears the history. +;; `Info-insert-dir' - +;; Added optional arg NOMSG to inhibit showing progress msgs. +;; `Info-mode' - Doc string shows all bindings. +;; `Info-read-node-name' - Added optional arg DEFAULT. +;; `Info-search' - 1. Fits frame. +;; 2. Highlights found regexp if `search-highlight'. +;; `Info-set-mode-line' - Handles breadcrumbs in the mode line. +;; `Info-mouse-follow-nearest-node' - With prefix arg, show node in +;; a new Info buffer. +;; `Info-isearch-search' - Respect restriction to active region. +;; `Info-isearch-wrap' - Respect restriction to active region. +;; +;; +;; ***** NOTE: The following standard function +;; has been REDEFINED HERE: +;; +;; `outline-invisible-p' - Fixes Emacs bug #28080. + +;;(@* "Documentation") +;; +;; Documentation +;; ------------- +;; +;; Library `info+.el' extends the standard Emacs library `info.el' in +;; several ways. It provides: +;; +;; * Association of additional information (metadata) with Info +;; nodes. You do this by bookmarking the nodes. Library Bookmark+ +;; gives you the following features in combination with `info+.el'. +;; In many ways an Info node and its default bookmark can be +;; thought of as the same animal. +;; +;; - Rich node metadata. In particular, you can tag nodes with any +;; number of arbitrary tags, to classify them in different and +;; overlapping ways. You can also annotate them (in Org mode, by +;; default). +;; +;; - You can use `C-h C-b' to show the metadata for a (bookmarked) +;; node. This is all of the associated bookmark information, +;; including the annotation and tags for that node and the number +;; of times you have visited it. If invoked with point on a +;; link, the targeted node is described; otherwise, you are +;; prompted for the node name. +;; +;; - Links for bookmarked nodes can have a different face, to let +;; you know that those nodes have associated metadata. Option +;; `Info-fontify-bookmarked-xrefs-flag' controls whether this is +;; done. +;; +;; - The face for this is `info-xref-bookmarked' by default, but +;; you can set the face to use for a given Info bookmark using +;; `C-x f' (command `Info-set-face-for-bookmarked-xref'). This +;; gives you an easy way to classify nodes and show the class of +;; a node by its links. Uses faces to make clear which nodes are +;; most important to you, or which are related to this or that +;; general topic. +;; +;; - If option `Info-node-access-invokes-bookmark-flag' is non-nil +;; then going to a bookmarked Info node invokes its bookmark, so +;; that the node metadata (such as number of visits) gets +;; updated. Command `Info-toggle-node-access-invokes-bookmark' +;; toggles the option value. +;; +;; - You can automatically bookmark nodes you visit, by enabling +;; mode `bmkp-info-auto-bookmark-mode'. Toggle the mode off +;; anytime you do not want to record Info visits. +;; +;; - In the bookmark-list display (from `C-x r l') you can sort +;; bookmarks by the time of last visit (`s d') or by the number +;; of visits (`s v'). This gives you an easy way to see which +;; parts of which Info manuals you have visited most recently and +;; how much you have visited them. +;; +;; * Editable, outline-enabled tables of contents (TOCs). Command +;; `Info-toc-outline' (bound to `O') opens a separate Info buffer +;; showing the table of contents (TOC). This is similar to the +;; standard command `Info-toc' (bound to `T'), but the buffer is +;; cloned from the manual and is in `outline-minor-mode'. Also, +;; there is no redundancy, by default: each TOC entry is listed +;; only once, not multiple times. (This is controlled by option +;; `Info-toc-outline-no-redundancy-flag'.) +;; +;; You can have any number of such TOCs, for the same manual or for +;; different manuals. +;; +;; Outline minor mode lets you hide and show, and promote and +;; demote, various parts of the TOC tree for a manual. And since +;; the TOC is editable you can make other changes to it: sort parts +;; of it, delete parts of it, duplicate parts of it, move parts +;; aroundin an ad hoc way, and so on. Info+ makes the outlining +;; commands behave, so that hidden Info text (e.g. markup text such +;; as `*note'...`::' surrounding links) is kept hidden. +;; +;; Especially when combined with `Info-persist-history-mode', +;; command `Info-change-visited-status' (`C-x DEL', see below), and +;; the Info+ bookmarking enhancements (e.g., special link +;; highlighting and persistently tracking the number of visits per +;; node), `Info-toc-outline' gives you a way to organize access and +;; visibility of a manual's nodes, to reflect how you use it. +;; +;; * Additional, finer-grained Info highlighting. This can make a +;; big difference in readability. +;; +;; - Quoted names, like this: `name-stands-out' or +;; `name-stands-out', and strings, like this: "string-stands-out" +;; are highlighted if `Info-fontify-quotations-flag' is +;; non-`nil'. +;; +;; - Angle-bracketed names, like this: , are highlighted if +;; `Info-fontify-angle-bracketed-flag' and +;; `Info-fontify-quotations-flag' are non-`nil'. +;; +;; - Isolated single quotes, like this: 'foobar, are highlighted if +;; `Info-fontify-single-quote-flag' and +;; `Info-fontify-quotations-flag' are non-`nil'. +;; +;; - Emphasized text, that is, text enclosed in underscore +;; characters, like this: _this is emphasized text_, is +;; highlighted if `Info-fontify-emphasis-flag' is non-`nil'. +;; (But if internal variable `info-fontify-emphasis' is `nil' +;; then there is no such highlighting, and that option has no +;; effect.) +;; +;; - In the Emacs Lisp manual, reference items are highlighted, so +;; they stand out. This means: constants, commands, functions, +;; macros, special forms, syntax classes, user options, and other +;; variables. +;; +;; Be aware that such highlighting is not 100% foolproof. +;; Especially for a manual such as Emacs or Elisp, where arbitrary +;; keys and characters can be present anywhere, the highlighting +;; can be thrown off. +;; +;; You can toggle each of the `Info-fontify-*-flag' options from +;; the `Info' menu or using an `Info-toggle-fontify-*' command. +;; For example, command `Info-toggle-fontify-emphasis' toggles +;; option `Info-fontify-emphasis-flag'. +;; +;; * You can show breadcrumbs in the mode line or the header line, or +;; both. See where you are in the Info hierarchy, and access higher +;; nodes directly. +;; +;; - In the mode line. Turned on by default. +;; +;; See ‘Toggle Breadcrumbs’ in the `mouse-3' mode-line menu and +;; `Toggle Breadcrumbs in Mode Line' in the `Info' menu (in the +;; menu-bar or in the minor-mode indicator). You can customize +;; option `Info-breadcrumbs-in-mode-line-mode' if you want to +;; turn this off by default. (Available for Emacs 23+ only.) +;; +;; - In the header (just below the header line). +;; +;; (I also added this to vanilla Emacs 23.) This is OFF by +;; default in `Info+'. See `Toggle Breadcrumbs in Header Line' +;; in `Info' menu. Be aware that unlike breadcrumbs in the mode +;; line, this can occasionally throw off the destination accuracy +;; of cross references and searches slightly. +;; +;; * Some of the commands defined here: +;; +;; - `Info-virtual-book' (bound to `v') – Open a virtual Info +;; manual of saved nodes from any number of manuals. The nodes +;; are those saved in option `Info-virtual-book'. With `C-u', +;; bookmarked Info nodes are also included. (If you use Icicles, +;; see also `icicle-Info-virtual-book'.) +;; +;; - `Info-persist-history-mode' - Enabling this minor mode saves +;; the list of your visited Info nodes between Emacs sessions. +;; Together with command `Info-history' (bound to `L' by +;; default), this gives you a persistent virtual manual of the +;; nodes you have visited in the past. If the mode is enabled +;; then the list of visited nodes is saved to the file named by +;; option `Info-saved-history-file' when you quit Emacs (not +;; Info) or when you kill an Info buffer. +;; +;; (If you also use library Bookmark+ then you can bookmark Info +;; nodes, including automatically. This records how many times +;; you have visited each node and when you last did so.) +;; +;; - `Info-change-visited-status' (bound to `C-x DEL') - Toggle or +;; set the visited status of the node at point or the nodes in +;; the active region. Useful if you use +;; `Info-fontify-visited-nodes' to show you which nodes you have +;; visited. No prefix arg: toggle. Non-negative prefix arg: set +;; to visited. Negative prefix arg: set to unvisited. +;; +;; - `Info-save-current-node' (bound to `.') – Save the name of the +;; current node to list `Info-saved-nodes', for use by `v' +;; (`Info-virtual-book'). +;; +;; - `Info-merge-subnodes' – Integrate the current Info node with +;; its subnodes (the nodes in its Menu), perhaps recursively. +;; +;; Use `Info-merge-subnodes' to extract a self-contained report +;; (possibly the whole manual) from an Info manual. The report +;; is itself an Info buffer, with hyperlinks and normal Info +;; behavior. +;; +;; There are various prefix-argument possibilities that govern +;; just how subnodes are treated (recursively or not, for +;; instance). There are a few user options that let you +;; customize the report appearance. +;; +;; +;; The following bindings are made here for Info-mode: +;; +;; `?' `describe-mode' (replaces `Info-summary') +;; `+' `Info-merge-subnodes' +;; `.' `Info-save-current-node' +;; `a' `info-apropos' +;; `G' `Info-goto-node-web' +;; `O' `Info-toc-outline' +;; `v' `Info-virtual-book' +;; `mouse-4' `Info-history-back' +;; `mouse-5' `Info-history-forward' +;; `S-down-mouse-2' `Info-mouse-follow-nearest-node-new-window' +;; `S-RET' `Info-follow-nearest-node-new-window' +;; +;; The following bindings are made here for merged Info buffers: +;; +;; `.' `beginning-of-buffer' +;; `b' `beginning-of-buffer' +;; `q' `quit-window' +;; `s' `nonincremental-re-search-forward' +;; `M-s' `nonincremental-re-search-forward' +;; `TAB' `Info-next-reference' +;; `ESC TAB' `Info-prev-reference' +;; +;; The global binding `C-h r' is changed from `info-emacs-manual' to +;; `info-manual', which behaves the same except if you use a prefix +;; arg. With a prefix arg you can open any manual, choosing either +;; from all installed manuals or from those that are already shown in +;; Info buffers. +;; +;; The following behavior defined in `info.el' has been changed: +;; "*info" has been removed from `same-window-buffer-names', so that +;; a separate window can be used if you so choose. +;; +;; Suggestion: Use a medium-dark background for Info. Try, for +;; example, setting the background to "LightSteelBlue" in your +;; `~/.emacs' file. You can do this as follows: +;; +;; (setq special-display-buffer-names +;; (cons '("*info*" (background-color . "LightSteelBlue")) +;; special-display-buffer-names)) +;; +;; Alternatively, you can change the background value of +;; `special-display-frame-alist' and set `special-display-regexps' to +;; something matching "*info*": +;; +;; (setq special-display-frame-alist +;; (cons '(background-color . "LightSteelBlue") +;; special-display-frame-alist)) +;; (setq special-display-regexps '("[ ]?[*][^*]+[*]")) +;; +;; If you do use a medium-dark background for Info, consider +;; customizing face to a lighter foreground color - I use "Yellow". +;; +;; Also, consider customizing face `link' to remove its underline +;; attribute. +;; +;; This file should be loaded after loading the standard GNU file +;; `info.el'. So, in your `~/.emacs' file, do this: +;; (eval-after-load "info" '(require 'info+)) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change Log: +;; +;; 2017/11/17 dadams +;; Info-TOC-outline stuff needs Info-virtual-nodes. Thx to Mike Fitzgerald. +;; http -> https everywhere. +;; 2017/11/09 dadams +;; info-quotation-regexp, info-quoted+<>-regexp: Added \\ to first alternative of each ... type, to exclude \ from it. +;; 2017/09/23 dadams +;; Info-url-for-node: Fix per TeXInfo manual - encode embedded hyphens etc. +;; 2017/08/30 dadams +;; Renamed: Info-refontify-toc-outline-region to Info-toc-outline-refontify-region. +;; 2017/08/28 dadams +;; Added: Info-refontify-toc-outline-region. +;; Info-refontify-toc-outline-region: Add Info-refontify-toc-outline-region to post-command-hook and bind to C-x M-l. +;; Info-toc-outline: Turn off Info-breadcrumbs-in-mode-line-mode in TOC buffer. +;; Info-change-visited-status: Typo: go-to-char. +;; 2017/08/25 dadams +;; Added: Info-change-visited-status. Bound to `C-x DEL (instead of Info-make-node-unvisited). +;; Info-node-name-at-point: Replace newline chars by spaces. +;; Info-toc-outline: Pass NEWNAME arg to clone-buffer, instead of explicitly renaming buffer. +;; 2017/08/22 dadams +;; Added: Info-toc-outline, Info-outline-demote, Info-outline-promote, Info-toc-outline-no-redundancy-flag, +;; Info-toc-outline-find-node, Info-toc-outline-map, Info-toc-outline-refontify-links, redefinition of +;; outline-invisible-p. +;; Bind Info-toc-outline to O. +;; Info-mode-menu: Added Editable Outline TOC item for Info-toc-outline. +;; Info-node-access-invokes-bookmark-flag, Info-toggle-node-access-invokes-bookmark, Info-goto-node advice: +;; Reserve for Emacs 24.4+. +;; 2017/08/10 dadams +;; Info-goto-node: Define it for Emacs 23 also. +;; Info-mode-menu: Add menu items for Info-toggle-node-access-invokes-bookmark, Info-toggle-fontify-bookmarked-xrefs. +;; 2017/08/07 dadams +;; Added: Info-make-node-unvisited. Bound to C-x DEL. +;; 2017/08/06 dadams +;; Added: Info-bookmarked-node-xref-faces, Info-read-bookmarked-node-name, +;; Info-set-face-for-bookmarked-xref. +;; Bind Info-set-face-for-bookmarked-xref to C-x f. +;; Info-describe-bookmark: If no bookmarked node name at point, use Info-read-bookmarked-node-name. +;; Info-bookmark-for-node: Made NODE arg optional - if nil then read the node name. Added LOCALP arg. +;; Info-fontify-node (Emacs 24.2+): Get face for bookmarked xref from bmkp-info-face tag value, if any. +;; Call Info-bookmark-for-node with arg LOCALP. +;; 2017/08/04 dadams +;; Info-describe-bookmark: Use Info-bookmark-name-at-point, not Info-node-name-at-point. +;; Info-goto-node: Do it only for Emacs 24.2+. +;; 2017/08/02 dadams +;; Info-goto-node: Define only if can soft-require bookmark+.el. +;; No-op if NODE is in Info-index-nodes. +;; Bind Info-node-access-invokes-bookmark-flag to nil while invoking bookmark. +;; Use bookmark--jump-via with ignore as display function, instead of bookmark-jump. +;; 2017/07/30 dadams +;; Added advice of Info-goto-node, to respect Info-node-access-invokes-bookmark-flag. +;; Removed redefinitions of Info-follow-nearest-node, Info-try-follow-nearest-node. +;; Replaced Info-follow-xref-bookmarks-flag by Info-node-access-invokes-bookmark-flag. +;; Replaced Info-toggle-follow-bookmarked-xrefs by Info-toggle-node-access-invokes-bookmark. +;; Info-bookmark-for-node, Info-bookmark-named-at-point: Include manual name in bookmark name. +;; 2017/07/29 dadams +;; Added: Info-fontify-bookmarked-xrefs-flag, face info-xref-bookmarked, Info-describe-bookmark, +;; Info-bookmark-for-node, Info-bookmark-name-at-point, Info-bookmark-named-at-point, +;; Info-bookmark-name-for-node, Info-toggle-fontify-bookmarked-xrefs, +;; Info-follow-xref-bookmarks-flag, Info-toggle-follow-bookmarked-xrefs. +;; Added (redefinition of): Info-follow-nearest-node, Info-try-follow-nearest-node. +;; Info-fontify-node (24.2+): Respect Info-fontify-bookmarked-xrefs-flag. +;; Bind Info-describe-bookmark to C-h C-b. +;; 2017/02/20 dadams +;; Added: Info-saved-history-file, Info-persist-history-mode, Info-save-history-list, +;; Info-restore-history-list. +;; Added autoload cookies: Info-breadcrumbs-in-mode-line-mode, Info-set-breadcrumbs-depth, +;; Info-search, Info-mouse-follow-nearest-node, info-display-manual. +;; 2017/01/09 dadams +;; Info-find-emacs-command-nodes: Updated for handle LINE-NUMBER (Emacs 24.5+). +;; 2016/12/13 dadams +;; Removed obsolete face aliases: info-menu-5, Info-title-*-face. +;; 2016/12/11 dadams +;; Added defvars for isearch(-regexp)-lax-whitespace for Emacs 24.1 and 24.2. +;; 2016/12/10 dadams +;; Use string as 3rd arg to make-obsolete. +;; 2016/10/31 dadams +;; info-quotation-regexp: Typo: misplaced curly double-quote. Thx to Don March. +;; 2016/07/02 dadams +;; Added: Info-toggle-fontify-emphasis, Info-breadcrumbs-in-header-flag, Info-emphasis-regexp, +;; Info-fontify-emphasis-flag, info-fontify-emphasis, and face info-emphasis. +;; Added some doc from Emacs Wiki to commentary. +;; Info-mode-menu: +;; Add toggle indicators. Moved toggle commands to Toggle submenu. Added Info-toggle-fontify-emphasis. +;; Info-fontify-node: Fontify emphasis. +;; 2015/09/14 dadams +;; info-double-quoted-name: Changed default colors. +;; 2015/09/13 dadams +;; Added face info-double-quoted-name. +;; info-quotation-regexp, info-quoted+<>-regexp: Added pattern for curly double-quotes (“...”). +;; Use shy groups for all parts. +;; info-fontify-quotations: Fontify text between curly double-quotes (“...”). +;; 2015/03/19 dadams +;; info-quoted+<>-regexp: Highlight <...> only if the first char is alphabetic. +;; 2015/03/06 dadams +;; Added: info-manual. Bound it globally to C-h r. +;; Info-fontify-node (Emacs 24.1.N+): Updated per Emacs 24.4: allow Info-fontify-maximum-menu-size to be t. +;; info-display-manual: Updated for Emacs 25: use info--manual-names with prefix arg. +;; 2015/02/28 dadams +;; Added: redefinition of Info-read-node-name. +;; Info-goto-node-web, Info-url-for-node: Use Info-current-node as default. +;; 2014/12/21 dadams +;; Added: Info-goto-node-web, Info-url-for-node. +;; Reorganized. Code cleanup. Improved commentary. Added index links. +;; Info-toggle-breadcrumbs-in-header-line: Added 3rd arg to make-obsolete. +;; Info-breadcrumbs-in-mode-line-mode: (default-value 'mode-line-format), not default-mode-line-format, +;; Info-display-node-default-header: (goto-char (point-min)), not (beginning-of-buffer). +;; Info-merge-subnodes: with-current-buffer, not save-excursion + set-buffer. +;; 2014/05/04 dadams +;; REMOVED SUPPORT for Emacs 20-22. That support is offered by a new library now: info+20.el. +;; Added coding:utf-8 declaration. Replace \x2018, \x2019 with literal ‘ and ’, since now Emacs 23+. +;; 2014/05/03 dadams +;; info-quotation-regexp, info-quoted+<>-regexp: Handle also curly single quotes (Emacs 24.4+). +;; Removed double * and moved openers outside \(...\) group. +;; info-fontify-quotations: Handle also curly single quotes (Emacs 24.4+). +;; 2014/03/04 dadams +;; Renamed Info-toggle-breadcrumbs-in-header-line to Info-toggle-breadcrumbs-in-header. +;; Declared old name obsolete. +;; 2014/03/02 dadams +;; Info-find-file: Go to directory if no previous file (per Emacs 24.4+). +;; Info-find-node-2 (Emacs > 22): Go to Top node at end, if no history. +;; 2013/10/17 dadams +;; Added: Info-search-beg, Info-search-end, Info-isearch-search-p. +;; Added redefinition: Info-isearch-wrap, Info-isearch-search. +;; Info-display-node-default-header, Info-merge-subnodes: Renamed node-name to infop-node-name. +;; 2013/03/17 dadams +;; Added: Info-history-clear, macro info-user-error (and font-lock it). Advised: Info-history. +;; Use info-user-error instead of error, where appropriate. +;; 2013/02/26 dadams +;; Info-mode-menu and Info-mode doc string: Removed Info-edit, Info-enable-edit (now obsolete). +;; 2013/02/09 dadams +;; Info-read-node-name-1: Removed Emacs 23+ redefinition. +;; 2013/02/03 dadams +;; Added: Info-fontify-angle-bracketed-flag, Info-toggle-fontify-angle-bracketed, +;; Info-toggle-fontify-quotations, Info-toggle-fontify-single-quote, info-quoted+<>-regexp. +;; info-fontify-quotations: Fixed case for Info-toggle-fontify-single-quote = nil. +;; Handle also Info-fontify-angle-bracketed-flag. +;; Added Info-fontify-*-flag to Info menu (so menu bar and C-mouse-3). +;; 2012/09/24 dadams +;; Info-search. Info-mode: Applied latest Emacs 24 updates by Juri (from 2012-09-12). +;; 2012/08/25 dadams +;; Info-fontify-node: Hide any empty lines at end of node (fixes bug #12272). +;; 2012/08/24 dadams +;; info-fontify-reference-items: Fontify parameters on continuation lines also. +;; Info-fontify-node: Juri's fix for Emacs bug #12187. +;; Reverted Juri's change from 08/20, since Juri fixed it elsewhere afterward. +;; 2012/08/21 dadams +;; Call tap-put-thing-at-point-props after load thingatpt+.el. +;; 2012/08/20 dadams +;; Applied Juri's fix for Emacs bug #12230: +;; Added: Info-file-attributes. +;; Info-find-file: Clear caches of modified Info files. +;; 2012/08/18 dadams +;; Invoke tap-define-aliases-wo-prefix if thingatpt+.el is loaded. +;; 2012/08/12 dadams +;; Added: info-constant-ref-item (face). +;; info-fontify-reference-items: Handle constants, using face info-constant-ref-item. +;; Info-toggle-breadcrumbs-in-header-line, Info-save-current-node: Added MSGP arg. +;; 2012/08/10 dadams +;; Info-search: Use latest Emacs 24 msg: _end of node_, not _initial node_. +;; 2012/08/09 dadams +;; Info-fontify-node: Updated guards for Emacs 24 versions. +;; 2012/07/28 dadams +;; Info-fontify-node: Typo on guard: (/= 1 emacs-minor-version) should have been =, not /=. +;; 2012/07/17 dadams +;; Added redefinition of Info-fontify-node for post-Emacs 24.1. +;; Added redefinitions of Info-insert-dir, Info(-directory)-find-node, with args controlling msgs. +;; info-find-node-2: Added optional arg NOMSG. +;; Info-find-emacs-command-nodes, Info-goto-emacs(-key)-command-node: Added optional arg MSGP. +;; Info-search, Info-save-current-node: Show messages only if interactive-p. +;; 2012/01/15 dadams +;; Added: info-display-manual (redefinition). +;; Info-find-file: Do not define for < Emacs 23.2 - no virtual books. +;; 2011/11/15 dadams +;; Added: redefinition of Info-find-file for Emacs 23+, to handle virtual books. +;; 2011/08/23 dadams +;; Removed hard-code removal of info from same-window-(regexps|buffer-names). Thx to PasJa. +;; 2011/02/06 dadams +;; info-user-option-ref-item: Corrected background for light-bg case. +;; 2011/02/03 dadams +;; All deffaces: Provided default values for dark-background screens too. +;; 2011/01/04 dadams +;; Removed autoload cookies from non def* sexps. Added for defgroup and defface. +;; 2010/05/27 dadams +;; Added: Info-set-mode-line. +;; Info-find-node-2: +;; Added redefinition of it for Emacs 23.2 (they keep twiddling it). +;; Do not call Info-insert-breadcrumbs-in-mode-line. Do that in Info-set-mode-line now. +;; 2010/04/06 dadams +;; Added: Info-breadcrumbs-in-header-flag, Info-toggle-breadcrumbs-in-header-line, +;; Info-breadcrumbs-in-mode-line-mode, Info-set-breadcrumbs-depth, +;; Info-insert-breadcrumbs-in-mode-line, Info-breadcrumbs-depth-internal. +;; Added to Info-mode-menu (Emacs 23+): Info-breadcrumbs-in-mode-line-mode. +;; Info-find-node-2 (Emacs 23+): Add breadcrumbs to header line & mode line only according to vars. +;; Info-fontify-node (Emacs 23+): Handle breadcrumbs in header only if flag says to. +;; 2010/01/12 dadams +;; Info-find-node for Emacs 20, Info-find-node-2 for Emacs 21, 22, Info-search: +;; save-excursion + set-buffer -> with-current-buffer. +;; 2010/01/10 dadams +;; Info-find-node-2 for Emacs 23+: Updated for Emacs 23.2 (pretest) - virtual function stuff. +;; 2009/12/13 dadams +;; Typo: Incorrectly used Emacs 22 version for Emacs 21 also. +;; 2009/12/11 dadams +;; info-fontify-(node|quotations|reference-items), Info-merge-subnodes: +;; Use font-lock-face property, not face, if > Emacs 21. +;; 2009/08/03 dadams +;; Updated for Emacs 23.1 release: Info-find-node-2, Info-fontify-node, Info-search: new version. +;; 2009/06/10 dadams +;; Added: Info-fontify-reference-items-flag, Info-mode-syntax-table. +;; Info-mode: Use Info-mode-syntax-table, not text-mode-syntax-table. +;; Info-fontify-node: Fontify ref items if *-reference-items-flag, not just for Elisp manual. +;; Renamed: info-elisp-* to info-*. +;; 2009/06/09 dadams +;; info-fontify-quotations: Allow \ before ', just not before`. +;; 2009/06/08 dadams +;; info-fontify-quotations: Rewrote, using better regexp. Don't fontify escaped ` or '. +;; Fontify `\', `\\', etc. Respect Info-fontify-single-quote-flag. +;; Added: info-single-quote, Info-fontify-single-quote-flag, info-quotation-regexp. +;; info-quoted-name: Changed face spec to (:inherit font-lock-string-face :foreground "DarkViolet") +;; 2009/05/25 dadams +;; Info-virtual-book: Treat info-node bookmarks too. +;; 2009/05/23 dadams +;; Added: Info-mode for Emacs 23. +;; They added Info-isearch-filter, Info-revert-buffer-function, Info-bookmark-make-record. +;; 2009/05/22 dadams +;; Added: Info-saved-nodes, Info-save-current-node, Info-virtual-book. Added to Info-mode-menu. +;; Bind info-apropos, Info-save-current-node, Info-virtual-book to a, ., and v. +;; Info-mode: Updated doc string. +;; 2009/04/26 dadams +;; Info-merge-subnodes: Bind inhibit-field-text-motion to t, for end-of-line. +;; 2008/10/07 dadams +;; Require cl.el at compile time for all Emacs versions, because of case. +;; 2008/10/05 dadams +;; Added: Info-read-node-name-1, Info-read-node-name-2. +;; 2008-07-11 dadams +;; Info-fontify-node (Emacs 22+): Protect histories when getting ancestor nodes for breadcrumbs. +;; (Emacs 22+) Don't change faces info-menu-header, *-title-*, *(-header)-node, header-line. +;; (Emacs 20, 21): Removed bold and italic attributes from info-node and info-xref. +;; Removed commented out defface for info-xref and info-node. +;; Face info-file: Blue, not DarkBlue, foreground, by default. +;; 2008/06/12 dadams +;; Info-fontify-node (Emacs 22+): +;; Prevent infinite recursion from Info-goto-node calling Info-fontify-node. +;; Fixed for nil Info-hide-note-references. +;; 2008/06/10 dadams +;; Info-fontify-node (Emacs 22+): Added breadcrumbs. +;; 2008/03/06 dadams +;; info-mode: Use fboundp for Info-clone-buffer, not version test, for Emacs 22+. Thx to Sebastien Vauban. +;; 2008/02/01 dadams +;; Info-mode: Renamed Info-clone-buffer-hook to Info-clone-buffer for Emacs 22.1.90. +;; 2008/01/08 dadams +;; Info-search (Emacs 22): Removed phony pred arg. +;; 2008/01/06 dadams +;; Removed soft require of Icicles due to cirular dependency. Thx to Tennis Smith. +;; 2007/11/27 dadams +;; Info-search: Use icicle-read-string-completing, if available. +;; Added soft require Icicles. +;; 2007/11/20 dadams +;; Info-subtree-separator: Escaped slashes in doc string: \f -> \\f. +;; 2007/09/26 dadams +;; Better default color for info-quoted-name. Added group face to all deffaces. +;; 2007/09/25 dadams +;; Bound Info-mouse-*-new-* to S-down-mouse-2, not S-mouse-2, because of mouse-scan-lines-or-M-:. +;; Info-goto-emacs-command-node: Convert completion default value to string. +;; 2007/08/27 dadams +;; Info-fontify-node: Ensure Info-fontify-node is a string when fontifiy quotations. Updated for Emacs 22. +;; 2007/07/13 dadams +;; Info-find-node: Redefine only for Emacs < 21. +;; 2006/09/15 dadams +;; Info-mouse-follow-nearest-node redefinition is only for Emacs >= 22. +;; Changed Emacs 22 tests to just (>= emacs-major-version 22). +;; Bind tool-bar-map for Emacs 21. Otherwise, binding of [tool-bar] gives an error (why?). +;; 2006/08/18 dadams +;; Everywhere: Corrected previous change: minibuffer-selected-window to window-minibuffer-p. +;; 2006/08/14 dadams +;; Everywhere: fit-frame only if not a minibuffer window. +;; 2006/08/12 dadams +;; Info-merge-subnodes: Bug fixes: +;; Added concat for insertion of main node when recursive-display-p is negative. +;; Don't recurse down Index menus. +;; When checking for subnodes menu, check for nonfile menu item also. +;; After come back from recursion, go back to Info buffer before trying to go back in history. +;; Call fit-frame at end. +;; 2006/06/10 dadams +;; Added: Info(-mouse)-follow-nearest-node-new-window. Bound to S-RET, S-mouse-2. +;; 2006/03/31 dadams +;; info-menu-header: Removed :underline, because links are underlined in Emacs 22. +;; No longer use display-in-minibuffer. +;; 2006/01/08 dadams +;; Added: redefinition of Info-mouse-follow-nearest-node. +;; 2006/01/07 dadams +;; Added :link for sending bug report. +;; 2006/01/06 dadams +;; Added defgroup Info-Plus and used it. Added :link. +;; 2005/12/30 dadams +;; Moved everything from setup-info.el to here, after getting rid of some of it. +;; Use defface for all faces. Renamed faces, without "-face". +;; Use minibuffer-prompt face, not info-msg-face. +;; No longer require setup-info.el. No longer require cl.el when compile. +;; 2005/11/21 dadams +;; Info-search for Emacs 22: Don't display repeat `s' message if isearch-mode. +;; 2005/11/09 dadams +;; Info-fontify-node: Updated to reflect latest CVS (replaced Info-escape-percent header). +;; 2005/10/31 dadams +;; Use nil as init-value arg in calls to completing-read, everywhere. +;; 2005/07/04 dadams +;; info-fontify-quotations: Use font-lock-face property, instead of face, for Emacs 22. +;; Wrap re-search-forward in condition-case for stack overflow. +;; 2005/07/02 dadams +;; Info-search: fit-frame. Added Emacs 22 version too. +;; Info-goto-emacs-command-node, Info-goto-emacs-key-command-node, Info-merge-subnodes: +;; Use Info-history-back for Emacs 22. +;; Info-mode: Added Emacs 22 version. +;; 2005/06/23 dadams +;; Info-fontify-node: Fontify reference items if in Emacs-Lisp manual. +;; Added: info-fontify-reference-items +;; 2005/05/17 dadams +;; Updated to work with Emacs 22.x. +;; 2004/11/20 dadams +;; Info-find-emacs-command-nodes: bug fix: regexp (cmd-desc) was only for Emacs 21. +;; Refined to deal with Emacs 21 < 21.3.50 (soon to be 22.x) +;; 2004/10/09 dadams +;; info-fontify-quotations: +;; 1) Allow all characters inside `...'. +;; 2) Treat case of "..." preceded by backslashes +;; Info-fontify-node (for Emacs 21): Moved info-fontify-quotations before fontification of titles. +;; 2004/10/07 dadams +;; Renamed Info-resize-frame-p to Info-fit-frame-flag. +;; 2004/10/05 dadams +;; Improved regexp treatment further for fontifying quotations. +;; 2004/10/04 dadams +;; Improved regexp treatment for fontifying quotations. +;; Added info-fontify-quotations. Removed info-fontify-strings-p. +;; Renamed Info-fontify-quotations-p to Info-fontify-quotations-flag. +;; 2004/10/03/dadams +;; Major update: updated to work with Emacs 21 also. +;; Made require of setup-info.el mandatory. +;; Removed all variables and keys to setup-info.el. +;; Renamed to Emacs 21 names and only define for Emacs < 21: emacs-info -> info-emacs-manual. +;; 2004/09/28 dadams +;; Removed dir-info (same as Info-directory). +;; Renamed to Emacs 21 names and only define for Emacs < 21: emacs-lisp-info -> menu-bar-read-lispref +;; 2004/06/01 dadams +;; Renamed: Info-fit-frame-p to Info-resize-frame-p, shrink-frame-to-fit to resize-frame. +;; 2000/09/27 dadams +;; 1. Added: Info-fit-frame-p. +;; 2. Info-find-node: added shrink-frame-to-fit. +;; 1999/04/14 dadams +;; Info-fontify-node: Fontify indexes too. +;; 1999/04/14 dadams +;; 1. Added vars: info-file-face, info-menu-face, info-node-face, info-quoted-name-face, info-string-face, +;; info-xref-face. +;; 2. No longer use (or define) faces: info-node, info-file, info-xref, info-menu-5, info-quoted-name, +;; info-string. +;; 3. Info-fontify-node: Use new face variables instead of faces in #2, above. +;; Corrected: node names in info-node-face (was xref). Use info-menu-face for * and menu item. +;; 4. Info-mode: Redefined like original, but: no make-face's; use face vars. +;; Added user options description to doc string. +;; 1999/04/08 dadams +;; Info-goto-emacs-key-command-node: regexp-quote pp-key for Info-search. +;; 1999/04/07 dadams +;; Info-goto-emacs-key-command-node: a) msgs only if interactive, b) return nil if not found, else non-nil, +;; c) "is undefined" -> "doc not found", d) use display-in-minibuffer more, e) corrected error handler. +;; 1999/04/01 dadams +;; 1. Added: (remove-hook 'same-window-buffer-names "*info*"). +;; 2. Info-find-node: switch-to-buffer-other-window -> pop-to-buffer. +;; 1999/03/31 dadams +;; 1. Added (put 'Info-goto-emacs-(key-)command-node 'info-file "emacs"). +;; 2. Info-find-node: Mention searched file in error messages. +;; 3. Added (replacement): Info-find-emacs-command-nodes, with progress msg. +;; 4. a. Info-goto-emacs-key-command-node: Use global-map, unless menu item. +;; b. Added message "Not found using Index ...". +;; 1999/03/31 dadams +;; 1. Info-goto-emacs(-key)-command-node: Only display-in-minibuffer if +;; interactive-p. +;; 2. Info-goto-emacs-key-command-node: Messages: "key"; other entries. +;; 1999/03/31 dadams +;; 1. Added (put 'info 'info-file "emacs") so find doc on `info' cmd. +;; 2. Info-goto-emacs-command-node: +;; a. Added message when =< 1 match. +;; b. Return num-matches if found. +;; c. Uses `display-in-minibuffer' instead of `message'. +;; 3. a. Wrapped call to Info-search in condition-case, not if. +;; b. Info-goto-emacs-key-command-node: Return num-matches if found. +;; 1999/03/30 dadams +;; 1. Added Info menu bar menu. +;; 2. Info-goto-emacs-command-node: Only error if interactive-p. +;; 3. Info-goto-emacs-key-command-node: +;; a. Print key in msgs +;; b. If Info-goto-emacs-command-node doesn't find it, then try Info-search. +;; If found & interactive-p, then msg ("repeat"). Else error. +;; 4. Info-search: Msg ("repeat") if found & interactive-p. +;; 1999/03/17 dadams +;; 1. Updated to correspond with Emacs 34.1 version. +;; 2. Protect with fboundp. +;; 1996/07/11 dadams +;; Added redefinitions of Info-goto-emacs-(key-)command-node. +;; 1996/04/26 dadams +;; Put escaped newlines on long-line strings. +;; 1996/04/16 dadams +;; Added: info-file, info-quoted-name, info-string, Info-fontify-quotations-flag, info-fontify-strings-p. +;; Take into account in Info-fontify-node. +;; 1996/02/23 dadams +;; 1. Changed binding of Info-merge-subnodes back to `r', but now requires user confirmation when invoked. +;; 2. Info-subtree-separator: Incorporates "\n* ". variable-interactive prop. +;; 1996/02/22 dadams +;; display-Info-node-subtree: +;; 1. display-Info-node-subtree -> Info-merge-subnodes (renamed). +;; 2. Changed binding of Info-merge-subnodes from `r' to `C-d'. +;; 3. Don't pick up text between menu-item-line and "\n* ". Hardwire "\n* ". +;; 4. Untabify menu-item-line, so can count chars to underline. +;; 5. indent-rigidly, not indent-region. +;; 1996/02/22 dadams +;; 1. Bind describe-mode and display-Info-node-subtree. +;; 2. Added redefinition of Info-mode: Only the doc string was changed. +;; 3. Added Info-subtree-separator. +;; 3. display-Info-node-subtree: Info-subtree-separator. Doc. Garbage-collect. +;; 1996/02/22 dadams +;; Info-merge-subnodes: Rewrote, adding optional args. Renamed (defaliased) to display-Info-node-subtree. +;; 1996/02/22 dadams +;; Added redefinition of Info-merge-subnodes (cleanup, corrections). +;; 1996/02/20 dadams +;; 1. Make info-node, info-xref, info-menu-5 here. (Diff faces than before.) +;; 2. Added redefinition of Info-find-node. (Uses other window.) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(require 'info) +(eval-when-compile (require 'cl)) ;; case + +;; These are optional, for cosmetic purposes. +(require 'thingatpt nil t) ;; (no error if not found): symbol-at-point + +(when (and (require 'thingatpt+ nil t) ;; (no error if not found): symbol-nearest-point + (fboundp 'tap-put-thing-at-point-props)) ; >= 2012-08-21 + (tap-define-aliases-wo-prefix) + (tap-put-thing-at-point-props)) + +(require 'strings nil t) ;; (no error if not found): concat-w-faces +(require 'fit-frame nil t) ;; (no error if not found): fit-frame + +;; Took this out because it leads to a circular `require' dependency. +;; (require 'icicles nil t) ;; (no error if not found): icicle-read-string-completing + +;; Quiet the byte compiler a bit. +;; +(defvar browse-url-new-window-flag) ; In `browse-url.el' +(defvar desktop-save-buffer) +(defvar header-line-format) +(defvar Info-breadcrumbs-depth) +(defvar Info-breadcrumbs-depth-internal) +(defvar Info-breadcrumbs-in-header-flag) +(defvar Info-breadcrumbs-in-mode-line-mode) +(defvar Info-current-node-virtual) +(defvar isearch-filter-predicate) +(defvar Info-bookmarked-node-xref-faces) ; Here, Emacs 24.2+, with Bookmark+. +(defvar Info-fontify-bookmarked-xrefs-flag) ; Here, Emacs 24.2+, with Bookmark+. +(defvar Info-fontify-visited-nodes) +(defvar Info-hide-note-references) +(defvar Info-history-list) +(defvar Info-isearch-initial-node) +(defvar Info-isearch-search) +(defvar Info-last-search) +(defvar Info-link-keymap) +(defvar Info-menu-entry-name-re) +(defvar Info-next-link-keymap) +(defvar Info-mode-line-node-keymap) +(defvar Info-node-spec-re) +(defvar Info-persist-history-mode) +(defvar Info-point-loc) +(defvar Info-prev-link-keymap) +(defvar Info-read-node-completion-table) +(defvar Info-refill-paragraphs) +(defvar Info-saved-history-file) +(defvar Info-saved-nodes) +(defvar Info-search-case-fold) +(defvar Info-search-history) +(defvar Info-search-whitespace-regexp) +(defvar info-tool-bar-map) +(defvar Info-up-link-keymap) +(defvar Info-use-header-line) +(defvar isearch-lax-whitespace) ; In `isearch.el'. +(defvar isearch-regexp-lax-whitespace) ; In `isearch.el'. +(defvar infop-node-name) ; Here, in `Info-merge-subnodes'. +(defvar outline-heading-alist) ; In `outline.el'. +(defvar widen-automatically) + +;;;;;;;;;;;;;;;;;;;; + +(provide 'info+) +(require 'info+) ;; Ensure loaded before compiling. + +;;;;;;;;;;;;;;;;;;;; + + +;;(@* "Macros") +;;; Macros ----------------------------------------------------------- + +(defmacro info-user-error (&rest args) + "`user-error' if defined, otherwise `error'." + `(if (fboundp 'user-error) (user-error ,@args) (error ,@args))) + +(font-lock-add-keywords + 'emacs-lisp-mode + '(("(\\(info-user-error\\)\\>" 1 font-lock-warning-face))) + +;;; KEYS & MENUS ;;;;;;;;;;;;;;;;;;;;;;;; + +(define-key Info-mode-map "?" 'describe-mode) ; Don't use `Info-summary'. +(define-key Info-mode-map "+" 'Info-merge-subnodes) +(define-key Info-mode-map "." 'Info-save-current-node) +(define-key Info-mode-map "a" 'info-apropos) +(define-key Info-mode-map "G" 'Info-goto-node-web) +(define-key Info-mode-map "O" 'Info-toc-outline) +(define-key Info-mode-map "v" 'Info-virtual-book) +(define-key Info-mode-map (kbd "C-x DEL") 'Info-change-visited-status) +;; Mouse back and forward buttons +(define-key Info-mode-map [S-down-mouse-2] 'Info-mouse-follow-nearest-node-new-window) +(define-key Info-mode-map [S-return] 'Info-follow-nearest-node-new-window) +(define-key Info-mode-map [mouse-4] 'Info-history-back) +(define-key Info-mode-map [mouse-5] 'Info-history-forward) + +;;(@* "Faces (Customizable)") +;;; Faces (Customizable) --------------------------------------------- + +;;;###autoload +(defgroup Info-Plus nil + "Various enhancements to Info." + :group 'info + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\ +info+.el bug: \ +&body=Describe bug here, starting with `emacs -q'. \ +Don't forget to mention your Emacs and library versions.")) + :link '(url-link :tag "Other Libraries by Drew" + "https://www.emacswiki.org/DrewsElispLibraries") + :link '(url-link :tag "Download" "https://www.emacswiki.org/info+.el") + :link '(url-link :tag "Description" "https://www.emacswiki.org/InfoPlus") + :link '(emacs-commentary-link :tag "Commentary" "info+") + ) + +;; FWIW, I use a `LightSteelBlue' background for `*info*', and I use `red3' for this face. +;;;###autoload +(defface info-double-quoted-name ; For “...” + '((((background dark)) (:inherit font-lock-string-face :foreground "Cyan")) + (t (:inherit font-lock-string-face :foreground "DarkOrange"))) + "*Face for names enclosed in curly double-quotes (“...”) in `info'." + :group 'Info-Plus :group 'faces) + +;;;###autoload +(defface info-emphasis ; For _..._ + '((t (:inherit italic))) + "*Face for emphasizing text enclosed with underscores (_..._) in `info'." + :group 'Info-Plus :group 'faces) + +;;;###autoload +(defface info-file + '((((background dark)) (:foreground "Yellow" :background "DimGray")) + (t (:foreground "Blue" :background "LightGray"))) + "*Face for file heading labels in `info'." :group 'Info-Plus :group 'faces) + +;;;###autoload +(defface info-menu + '((((background dark)) (:foreground "Yellow")) + (t (:foreground "Blue"))) + "*Face used for menu items in `info'." :group 'Info-Plus :group 'faces) + +;; FWIW, I use a `LightSteelBlue' background for `*info*', and I use `yellow' for this face. +;;;###autoload +(defface info-quoted-name ; For ‘...’ and `...' + '((((background dark)) (:inherit font-lock-string-face :foreground "#6B6BFFFF2C2C")) ; ~ bright green + (((background light)) (:inherit font-lock-string-face :foreground "DarkViolet")) + (t (:foreground "yellow"))) + "*Face for quoted names (‘...’ or `...') in `info'." + :group 'Info-Plus :group 'faces) + +;; FWIW, I use a `LightSteelBlue' background for `*info*', and I use `red3' for this face. +;;;###autoload +(defface info-string ; For "..." + '((((background dark)) (:inherit font-lock-string-face :foreground "Orange")) + (t (:inherit font-lock-string-face :foreground "red3"))) + "*Face for strings (\"...\") in `info'." + :group 'Info-Plus :group 'faces) + +;;;###autoload +(defface info-single-quote ; For ' + '((((background dark)) (:inherit font-lock-keyword-face :foreground "Green")) + (t (:inherit font-lock-keyword-face :foreground "Magenta"))) + "*Face for isolated single-quote marks (') in `info'." + :group 'Info-Plus :group 'faces) + +;; Standard faces from vanilla Emacs `info.el', but without `:weight', `:height' and `:inherit'. +;;;###autoload +(defface info-title-1 + '((((type tty pc) (class color) (background dark)) :foreground "yellow" :weight bold) + (((type tty pc) (class color) (background light)) :foreground "brown" :weight bold)) + "*Face for info titles at level 1." + :group 'info) + +;;;###autoload +(defface info-title-2 + '((((type tty pc) (class color)) :foreground "lightblue" :weight bold)) + "*Face for info titles at level 2." + :group 'info) + +;;;###autoload +(defface info-title-3 + '((((type tty pc) (class color)) :weight bold)) + "*Face for info titles at level 3." + :group 'info) + +;;;###autoload +(defface info-title-4 + '((((type tty pc) (class color)) :weight bold)) + "*Face for info titles at level 4." + :group 'info) + +;;; Faces for highlighting reference items +;;;###autoload +(defface info-command-ref-item + '((((background dark)) (:foreground "#7474FFFF7474" :background "DimGray")) ; ~ light green + (t (:foreground "Blue" :background "LightGray"))) + "*Face used for \"Command:\" reference items in `info' manual." + :group 'Info-Plus :group 'faces) +;;;###autoload +(defface info-constant-ref-item + '((((background dark)) + (:foreground "DeepPink" :background "DimGray")) + (t (:foreground "DeepPink" :background "LightGray"))) + "*Face used for \"Constant:\" reference items in `info' manual." + :group 'Info-Plus :group 'faces) +;;;###autoload +(defface info-function-ref-item + '((((background dark)) + (:foreground "#4D4DDDDDDDDD" :background "DimGray")) ; ~ cyan + (t (:foreground "DarkBlue" :background "LightGray"))) + "*Face used for \"Function:\" reference items in `info' manual." + :group 'Info-Plus :group 'faces) +;;;###autoload +(defface info-macro-ref-item + '((((background dark)) + (:foreground "Yellow" :background "DimGray")) + (t (:foreground "DarkMagenta" :background "LightGray"))) + "*Face used for \"Macro:\" reference items in `info' manual." + :group 'Info-Plus :group 'faces) +;;;###autoload +(defface info-reference-item + '((((background dark)) (:background "DimGray")) + (t (:background "LightGray"))) + "*Face used for reference items in `info' manual." + :group 'Info-Plus :group 'faces) +;;;###autoload +(defface info-special-form-ref-item + '((((background dark)) + (:foreground "Yellow" :background "DimGray")) + (t (:foreground "DarkMagenta" :background "LightGray"))) + "*Face used for \"Special Form:\" reference items in `info' manual." + :group 'Info-Plus :group 'faces) +;;;###autoload +(defface info-syntax-class-item + '((((background dark)) + (:foreground "#FFFF9B9BFFFF" :background "DimGray")) ; ~ pink + (t (:foreground "DarkGreen" :background "LightGray"))) + "*Face used for \"Syntax Class:\" reference items in `info' manual." + :group 'Info-Plus :group 'faces) +;;;###autoload +(defface info-user-option-ref-item + '((((background dark)) (:foreground "Red" :background "DimGray")) + (t (:foreground "Red" :background "LightGray"))) + "*Face used for \"User Option:\" reference items in `info' manual." + :group 'Info-Plus :group 'faces) +;;;###autoload +(defface info-variable-ref-item + '((((background dark)) + (:foreground "Orange" :background "DimGray")) + (t (:foreground "FireBrick" :background "LightGray"))) + "*Face used for \"Variable:\" reference items in `info' manual." + :group 'Info-Plus :group 'faces) + +(when (and (require 'bookmark+ nil t) ; Emacs 24.2+ (do not bother for Emacs 23-24.1) + (or (> emacs-major-version 24) (and (= emacs-major-version 24) (> emacs-minor-version 1)))) + + (defface info-xref-bookmarked + '((((background dark)) (:foreground "violet")) + (t (:foreground "DarkGreen"))) + "Face for bookmarked Info nodes." + :group 'Info-Plus :group 'faces) + + ) + +;;(@* "User Options (Customizable)") +;;; User Options (Customizable) -------------------------------------- + +;;;###autoload +(defcustom Info-breadcrumbs-in-header-flag nil + "*Non-nil means breadcrumbs are shown in the header line." + :type 'boolean :group 'Info-Plus) + +;;;###autoload +(defcustom Info-display-node-header-fn 'Info-display-node-default-header + "*Function to insert header by `Info-merge-subnodes'." + :type 'function :group 'Info-Plus) + +;;;###autoload +(defcustom Info-emphasis-regexp + "_\\(\\(\\sw\\(\\s-\\|\\sw\\|\\s.\\)*\\)\\|\\(\\(\\s-\\|\\sw\\|\\s.\\)\\sw*\\)\\)_" + "Regexp to match text enclosed in underscore (`_') characters. + +The default value matches the following (enclosed in underscores): +word, punctuation, and whitespace characters, plus hyphens, with at +least one word character. Hyphen is included explicitly because it +generally has symbol syntax in Info. + +Some possible values include: + + _\\(\\(\\sw\\(\\s-\\|\\sw\\|\\s.\\)*\\)\\|\\(\\(\\s-\\|\\sw\\|\\s.\\)\\sw*\\)\\)_ (default) + _\\(\\(\\s-\\|\\sw\\|\\s.\\)+\\)_ (word, punctuation, whitespace) + _\\(\\sw+\\)_\t\t (single words) + _\\(\\s-*\\sw+\\s-*\\)_\t (single words, maybe whitespace-separated) + _\\([^_\\n]+\\)_\t\t (anything except newlines) + _\\([^_]+\\)_\t\t (anything) + +Note that any value can be problematic for some Info text - see +`Info-fontify-emphasis-flag'." + :type 'regexp :group 'Info-Plus) + +;;;###autoload +(defcustom Info-fit-frame-flag t + "*Non-nil means call `fit-frame' on Info buffer." + :type 'boolean :group 'Info-Plus :group 'Fit-Frame) + +(when (and (require 'bookmark+ nil t) ; Emacs 24.4+ + (or (> emacs-major-version 24) (and (= emacs-major-version 24) (> emacs-minor-version 3)))) + + (defcustom Info-node-access-invokes-bookmark-flag t + "*Non-nil means invoke the bookmark when you access an Info node. +This applies to Info bookmarks whose names correspond to the default +name. This is normally the full node name, `(MANUAL) NODE', where +MANUAL is the lowercase name of the Info manual. For example, node +`Modes' in the Emacs manual has full name `(emacs) Modes', and the +bookmark must have that same name. + +This automatic bookmark invocation can be useful to update the +bookmark data, such as the number of visits to the node." + :type 'boolean :group 'Info-Plus) + + ) + +;;;###autoload +(defcustom Info-fontify-angle-bracketed-flag t + "*Non-nil means `info' fontifies text within <...>. +A non-nil value has no effect unless `Info-fontify-quotations-flag' is +also non-nil. + +Note: This fontification can never be 100% reliable. It aims to be +useful in most Info texts, but it can occasionally result in +fontification that you might not expect. This is not a bug; it is +part of the design to be able to appropriately fontify a great variety +of texts. Set this flag to nil if you do not find this fontification +useful. You can use command `Info-toggle-fontify-angle-bracketed' to +toggle the option value." + :type 'boolean :group 'Info-Plus) + +(when (and (require 'bookmark+ nil t) ; Emacs 24.2+ (do not bother for prior) + (or (> emacs-major-version 24) (and (= emacs-major-version 24) (> emacs-minor-version 1)))) + + (defcustom Info-bookmarked-node-xref-faces '() + "List of faces to use to classify bookmarked nodes. +The faces are used for links to bookmarked nodes. They classify nodes +by serving as the values of bookmark tag \"bmkp-info-face\". + +You can use any face for such a link. The faces in this option list +are just provided as defaults when you are asked to enter a face for a +node link. " + :type '(repeat face) :group 'Info-Plus) + + (defcustom Info-fontify-bookmarked-xrefs-flag t + "Non-nil means fontify references to bookmarked nodes. +The face used is `info-xref-bookmarked'." + :type 'boolean :group 'Info-Plus) + + ) + +;;;###autoload +(defcustom Info-fontify-emphasis-flag t + "*Non-nil means `info' fontifies text between underscores (`_'). +The text that is highlighted matches the value of option +`Info-emphasis-regexp'. + +Note 1: +This fontification hides the underscores that surround text that is +emphasized. Because this fontification is not 100% reliable (see Note +2), in cases where it is inappropriate or unhelpful you might want to +see the hidden underscore characters. You can toggle showing all +hidden text (not just hidden underscores) using `M-x visible-mode'. +See (info) `Help-Inv' for more information about this. + +Note 2: +This fontification can never be 100% reliable. It aims to be useful +in most Info texts, but it can occasionally result in fontification +that you might not expect. This is not a bug; it is part of the +design to be able to appropriately fontify a great variety of texts. +Set this flag to nil if you do not find this fontification useful. +You can use command `Info-toggle-fontify-emphasis' to toggle the +option value. + +Note 3: +If internal variable `info-fontify-emphasis' is `nil' then emphasis is +never highlighted, and this option has no effect. This gives you a +way to turn off all matching of `Info-emphasis-regexp'." + :type 'boolean :group 'Info-Plus) + +;;;###autoload +(defcustom Info-fontify-quotations-flag t + "*Non-nil means `info' fontifies text between quotes. +This applies to double-quoted text (“...” or \"...\") and text +between single-quotes (‘...’ or `...'). + +Note: This fontification can never be 100% reliable. It aims to be +useful in most Info texts, but it can occasionally result in +fontification that you might not expect. This is not a bug; it is +part of the design to be able to appropriately fontify a great variety +of texts. Set this flag to nil if you do not find this fontification +useful. You can use command `Info-toggle-fontify-quotations' to +toggle the option value." + :type 'boolean :group 'Info-Plus) + +;;;###autoload +(defcustom Info-fontify-reference-items-flag t + "*Non-nil means `info' fontifies reference items such as \"Function:\"." + :type 'boolean :group 'Info-Plus) + +(when (fboundp 'advice-add) ; Emacs 24.4+ + + (defcustom Info-saved-history-file (locate-user-emacs-file "info-history" ".emacs.info-history") + "File where `Info-persist-history-mode' saves `Info-history-list'." + :type '(file :must-match t) :group 'Info-Plus) + + ) + +;;;###autoload +(defcustom Info-saved-nodes () + "*List of Info node names you can visit using `\\\\[Info-virtual-book]'. +Each node name is a string. The node name can be absolute, including +a filename, such as \"(emacs)Basic\", or it can be relative, such as +\"Basic\". +You can customize this option, but you can also add node names to it +easily using `\\\\[Info-save-current-node]'." + :type '(repeat (string :tag "Node name")) :group 'info) + +;;;###autoload +(defcustom Info-fontify-single-quote-flag t + "*Non-nil means `info' fontifies ' when not preceded by `.... +A non-nil value has no effect unless `Info-fontify-quotations-flag' is +also non-nil. + +Note: This fontification can never be 100% reliable. It aims to be +useful in most Info texts, but it can occasionally result in +fontification that you might not expect. This is not a bug; it is +part of the design to be able to appropriately fontify a great variety +of texts. Set this flag to nil if you do not find this fontification +useful. You can use command `Info-toggle-fontify-single-quote' to +toggle the option value." + :type 'boolean :group 'Info-Plus) + +;;;###autoload +(defcustom Info-subtree-separator "\n* " + "*A string used to separate Info node descriptions. +Inserted by `Info-merge-subnodes' just before each node title. +Setting this to a string that includes a form-feed (^L), such as +\"\\f\\n* \", will cause a page break before each node description. + +Use command `set-variable' to set this, quoting any control characters +you want to include, such as form-feed (^L) and newline (^J), with ^Q. +For example, type `^Q^L^Q^J* ' to set this to \"\\f\\n* \"." + :type 'string :group 'Info-Plus) + +;;;###autoload +(defcustom Info-toc-outline-no-redundancy-flag t + "Non-nil means `Info-toc-outline' TOC has no redundancy. +If nil then section headings from the TOC manual are included, and +nodes can be repeated because they are in more than one section." + :type 'boolean :group 'Info-Plus) + + +;;(@* "Internal Variables") +;;; Internal Variables ----------------------------------------------- + +(defvar info-fontify-emphasis t + "Non-nil means allow `Info-fontify-emphasis-flag' to work. +If nil then emphasis is never fontified, regardless of that flag.") + +;; I reported this as Emacs bug #3312. If it gets fixed, this can be removed. +(defvar Info-mode-syntax-table + (let ((table (copy-syntax-table text-mode-syntax-table))) + (modify-syntax-entry ?' "." table) ; Punctuation syntax for apostrophe ('). + (modify-syntax-entry ?\240 "." table) ; Punctuation syntax for non-breaking space. + table) + "Syntax table for `info'.") + +(defvar Info-merged-map nil "Keymap for merged Info buffer.") +(if Info-merged-map + nil + (setq Info-merged-map (make-keymap)) + (suppress-keymap Info-merged-map) + (define-key Info-merged-map "." 'beginning-of-buffer) + (define-key Info-merged-map "\t" 'Info-next-reference) + (define-key Info-merged-map "\e\t" 'Info-prev-reference) + (define-key Info-merged-map "b" 'beginning-of-buffer) + (define-key Info-merged-map "q" 'quit-window) + (define-key Info-merged-map "s" 'nonincremental-re-search-forward) + (define-key Info-merged-map "\M-s" 'nonincremental-re-search-forward)) + +(defvar Info-breadcrumbs-depth-internal Info-breadcrumbs-depth + "Current breadcrumbs depth for Info.") + +;; Match has, inside “...”, "...", ‘...’, or `...', zero or more of these characters: +;; - any character except ”, ", ’, or ', respectively +;; - \ followed by any character +;; +;; The `... in `...' is optional, so the regexp can also match just '. +;; +;; The regexp matches also ‘...’, `...', “...”, and "..." where at least one of the +;; ‘, ’, `, ', “, ”, or " is escaped by a backslash. +;; So we check those cases explicitly and do not highlight them. +;; +(defvar info-quotation-regexp + (concat + "\"\\(?:[^\\\"]\\|\\\\\\(?:.\\|[\n]\\)\\)*\"\\|" ; "..." + "`\\(?:[^\\']\\|\\\\\\(.\\|[\n]\\)\\)*'\\|" ; `...' + "‘\\(?:[^\\’]\\|\\\\\\(.\\|[\n]\\)\\)*’\\|" ; ‘...’ + "\“\\(?:[^\\”]\\|\\\\\\(.\\|[\n]\\)\\)*”" ; “...” + ) + "Regexp to match `...', ‘...’, “...”, \"...\", or just '. +If ... contains an end char then that char must be backslashed.") + + +(defvar info-quoted+<>-regexp + (concat + "\"\\(?:[^\\\"]\\|\\\\\\(?:.\\|[\n]\\)\\)*\"\\|" ; "..." + "`\\(?:[^\\']\\|\\\\\\(.\\|[\n]\\)\\)*'\\|" ; `...' + "‘\\(?:[^\\’]\\|\\\\\\(.\\|[\n]\\)\\)*’\\|" ; ‘...’ + "\“\\(?:[^\\”]\\|\\\\\\(.\\|[\n]\\)\\)*”\\|" ; “...” + "<\\(?:[[:alpha:]][^\\>]*\\|\\(\\\\\\(.\\|[\n]\\)\\)*\\)>" ; <...> + ) + "Same as `info-quotation-regexp', but matches also <...>. +If ... contains an end char then that char must be backslashed.") + +(defvar Info-toc-outline-map (let ((map (make-sparse-keymap))) (set-keymap-parent map Info-mode-map)) + "Keymap for Info TOC with outlining.") + +;;(@* "New Commands") +;;; New Commands ----------------------------------------------------- + +;; Make `Info-find-emacs-command-nodes' look for these commands in the Emacs manual. +;; In particular, don't look for command `info' in Info manual, because that has no index. +(put 'info 'info-file "emacs") +(put 'Info-goto-emacs-command-node 'info-file "emacs") +(put 'Info-goto-emacs-key-command-node 'info-file "emacs") + +;;;###autoload (autoload 'Info-mouse-follow-nearest-node-new-window "info+") +(defun Info-mouse-follow-nearest-node-new-window (click) + "Open the link at the mouse pointer in a new window." + (interactive "e") + (Info-mouse-follow-nearest-node click t)) + +;;;###autoload (autoload 'Info-follow-nearest-node-new-window "info+") +(defun Info-follow-nearest-node-new-window () + "Open the link near the text cursor in a new window." + (interactive) + (Info-follow-nearest-node t)) + +;;;###autoload (autoload 'Info-clear "info+") +(defun Info-history-clear (&optional msgp) + "Clear Info history and reload current manual." + (interactive (progn (unless (y-or-n-p "Clear the Info history? ") (info-user-error "OK, canceled")) + (list t))) + (setq Info-history () + Info-history-list ()) + (when (derived-mode-p 'Info-mode) (revert-buffer nil t)) + (when msgp (message "Info history cleared"))) + +(when (fboundp 'advice-add) ; Emacs 24.4+ + + (define-minor-mode Info-persist-history-mode + "Automatically persist the Info history in `Info-saved-history-file'." + :init-value nil :global t :group 'Info-Plus + (cond (Info-persist-history-mode + (add-hook 'kill-emacs-hook 'Info-save-history-list) + (advice-add 'Info-kill-buffer :before 'Info-save-history-list) + (advice-add 'Info-directory :after 'Info-restore-history-list)) + (t + (remove-hook 'kill-emacs-hook 'Info-save-history-list) + (advice-remove 'Info-kill-buffer 'Info-save-history-list) + (advice-remove 'Info-directory 'Info-restore-history-list)))) + + ) + +(when (> emacs-major-version 23) ; Emacs 23 `revert-buffer' invokes a brain-dead `kill-buffer' etc. + + (defun Info-change-visited-status (start end &optional arg) + "Change whether the nodes in the region have been visited. +If the region is not active then act on only the node at point. +No prefix arg means toggle the visited status of each node. +A non-negative prefix arg means consider the nodes visited. +A negative prefix arg means consider the nodes not visited." + (interactive "r\nP") + (let ((toggle (not arg)) + (visit (and arg (natnump (prefix-numeric-value arg)))) + (unvisit (and arg (not (natnump (prefix-numeric-value arg))))) + (opoint (point)) + (omark (mark)) + (active mark-active) + (file (Info-find-file Info-current-file)) + node visitedp trim) + (unless mark-active (setq start (setq end (point)))) + (save-excursion + (goto-char start) + (while (<= (point) end) + (unless (setq node (Info-node-name-at-point)) (Info-next-reference)) + (when (setq node (Info-node-name-at-point)) + (save-match-data + (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)" node) + (setq node (match-string 3 node)) + (setq trim (string-match "\\s +\\'" node))) + (when trim (setq node (substring node 0 trim))) + (when (or (not node) (string= node "")) (setq node "Top")) + (setq visitedp (member (list file node) Info-history-list)) + (if (and visitedp (or toggle unvisit)) + (setq Info-history-list (delete (list file node) Info-history-list)) + (if (and (not visitedp) (or toggle visit)) + (setq Info-history-list (cons (list file node) Info-history-list))))) + (when (> (forward-line 1) 0) (goto-char (point-max))))) + (when (derived-mode-p 'Info-mode) (revert-buffer nil t)) + (when omark (set-mark omark)) + (goto-char opoint) + (message (if toggle + "Node visited status toggled" + (format "Node visited status is now %s" (if visit 'VISITED 'UNvisited)))) + (if (not active) + (deactivate-mark) + (activate-mark) + (setq deactivate-mark nil)))) + + ) + +;; Not bound. Use `Info-change-visited-status' instead. +;; +;;;###autoload (autoload 'Info-make-node-unvisited "info+") +(defun Info-make-node-unvisited (node &optional msgp) + "Reset the visited status of NODE to unvisited." + (interactive (list (or (Info-node-name-at-point) (Info-read-node-name "Node: " Info-current-node)) + t)) + (let (file trim) + (save-match-data + (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)" node) + (setq file (if (= (match-beginning 1) (match-end 1)) "" (match-string 2 node)) + node (match-string 3 node) + trim (string-match "\\s +\\'" file)) + (when trim (setq file (substring file 0 trim))) + (setq trim (string-match "\\s +\\'" node))) + (when trim (setq node (substring node 0 trim))) + (when (or (not node) (string= node "")) (setq node "Top")) + (when (or (not file) (string= file "")) (setq file Info-current-file)) + (setq file (Info-find-file file) + Info-history-list (remove (list file (substring-no-properties node)) Info-history-list)) + ;; Emacs 23 has brain-dead `kill-buffer', which is invoked by `revert-buffer' and deletes the window/frame if dedicated. + (when (and (> emacs-major-version 23) (derived-mode-p 'Info-mode)) (revert-buffer nil t)) + (when msgp (message "Node %sis now unvisited" + (if (string= "dir" Info-current-file) "" + (format "`%s%s' " + (if (equal file Info-current-file) + "" + (format "(%s) " (file-name-nondirectory file))) + node)))))) + +;; I made this a global minor mode and turned it on by default, contrary to "the rules". +;; I did this so (a) users could easily customize it but (b) it would be on by default, otherwise. +;; +;;;###autoload (autoload 'Info-breadcrumbs-in-mode-line-mode "info+") +(define-minor-mode Info-breadcrumbs-in-mode-line-mode + "Toggle the use of breadcrumbs in Info mode line. +With arg, show breadcrumbs iff arg is positive. +Change the default behavior by customizing option +`Info-breadcrumbs-in-mode-line-mode'." + :init-value t :global t :group 'mode-line :group 'Info-Plus + (if (not Info-breadcrumbs-in-mode-line-mode) + (setq Info-breadcrumbs-depth-internal 0 + mode-line-format (default-value 'mode-line-format)) + (setq Info-breadcrumbs-depth-internal Info-breadcrumbs-depth) + (Info-insert-breadcrumbs-in-mode-line))) + +;;;###autoload (autoload 'Info-toggle-breadcrumbs-in-header "info+") +(defun Info-toggle-breadcrumbs-in-header (&optional msgp) + "Toggle option `Info-breadcrumbs-in-header-flag'. +Toggles showing breadcrumbs in the Info header (top of the node). +This means the area at the top of the node, not the separate header +line from non-nil `Info-use-header-line'." + (interactive "p") + (setq Info-breadcrumbs-in-header-flag (not Info-breadcrumbs-in-header-flag)) + (when msgp (message "Showing breadcrumbs in Info header is now %s" + (if Info-breadcrumbs-in-header-flag "ON" "OFF")))) + +(defalias 'Info-toggle-breadcrumbs-in-header-line 'Info-toggle-breadcrumbs-in-header) +(make-obsolete 'Info-toggle-breadcrumbs-in-header-line 'Info-toggle-breadcrumbs-in-header "2014/03/04") + + +(when (boundp 'Info-node-access-invokes-bookmark-flag) ; Emacs 24.4+ + + (defun Info-toggle-node-access-invokes-bookmark (&optional msgp) + "Toggle option `Info-node-access-invokes-bookmark-flag'." + (interactive "p") + (setq Info-node-access-invokes-bookmark-flag (not Info-node-access-invokes-bookmark-flag)) + (when (eq major-mode 'Info-mode) + (font-lock-defontify) + (let ((modp (buffer-modified-p)) + (inhibit-read-only t)) + (Info-fontify-node)) + (when msgp (message "`Info-node-access-invokes-bookmark-flag' is now %s" + (if Info-node-access-invokes-bookmark-flag 'ON 'OFF))))) + + ) + +(when (and (require 'bookmark+ nil t) ; Emacs 24.2+ (do not bother for prior) + (or (> emacs-major-version 24) (and (= emacs-major-version 24) (> emacs-minor-version 1)))) + + (defun Info-set-face-for-bookmarked-xref (node) + "Specify the face to use for Info links to bookmarked NODE. +Sets the value of bookmark tag \"bmkp-info-face\" to a face symbol you +name. + +If option `Info-bookmarked-node-xref-faces' is non-nil then only the +faces in that list are available for completion, but you can enter any +face name. If that option is nil then all faces are available for +completion. + +NODE defaults to the bookmarked node named at point. If none then you +are prompted for NODE." + (interactive (list (or (Info-bookmark-name-at-point) (Info-read-bookmarked-node-name)))) + (let* ((alist (bmkp-info-alist-only)) + (bmk (bmkp-get-bookmark-in-alist node t alist))) + (unless bmk (error "No Info bookmark for node `%s'" node)) + (bmkp-set-tag-value bmk "bmkp-info-face" + (if Info-bookmarked-node-xref-faces + (intern (completing-read "Face: " Info-bookmarked-node-xref-faces + (lambda (ff) (memq ff (face-list))))) + (read-face-name "Face" 'info-xref-bookmarked))))) + + (define-key Info-mode-map (kbd "C-x f") 'Info-set-face-for-bookmarked-xref) + + + (defun Info-toggle-fontify-bookmarked-xrefs (&optional msgp) + "Toggle option `Info-fontify-bookmarked-xrefs-flag'." + (interactive "p") + (setq Info-fontify-bookmarked-xrefs-flag (not Info-fontify-bookmarked-xrefs-flag)) + (when (eq major-mode 'Info-mode) + (font-lock-defontify) + (let ((modp (buffer-modified-p)) + (inhibit-read-only t)) + (Info-fontify-node)) + (when msgp (message "`Info-fontify-bookmarked-xrefs-flag' is now %s" + (if Info-fontify-bookmarked-xrefs-flag 'ON 'OFF))))) + + ) + +;;;###autoload (autoload 'Info-toggle-fontify-emphasis "info+") +(defun Info-toggle-fontify-emphasis (&optional msgp) + "Toggle option `Info-fontify-emphasis-flag'." + (interactive "p") + (unless info-fontify-emphasis (error "`info-fontify-emphasis' must be non-nil to use this command")) + (setq Info-fontify-emphasis-flag (not Info-fontify-emphasis-flag)) + (when (eq major-mode 'Info-mode) + (font-lock-defontify) + (let ((modp (buffer-modified-p)) + (inhibit-read-only t)) + (Info-fontify-node)) + (when msgp (message "`Info-fontify-emphasis-flag' is now %s" + (if Info-fontify-emphasis-flag 'ON 'OFF))))) + +;;;###autoload (autoload 'Info-toggle-fontify-quotations "info+") +(defun Info-toggle-fontify-quotations (&optional msgp) + "Toggle option `Info-fontify-quotations-flag'." + (interactive "p") + (setq Info-fontify-quotations-flag (not Info-fontify-quotations-flag)) + (when (eq major-mode 'Info-mode) + (font-lock-defontify) + (let ((modp (buffer-modified-p)) + (inhibit-read-only t)) + (Info-fontify-node)) + (when msgp (message "`Info-fontify-quotations-flag' is now %s" + (if Info-fontify-quotations-flag 'ON 'OFF))))) + +;;;###autoload (autoload 'Info-toggle-fontify-single-quote "info+") +(defun Info-toggle-fontify-single-quote (&optional msgp) + "Toggle option `Info-fontify-single-quote-flag'." + (interactive "p") + (setq Info-fontify-single-quote-flag (not Info-fontify-single-quote-flag)) + (when (eq major-mode 'Info-mode) + (font-lock-defontify) + (let ((modp (buffer-modified-p)) + (inhibit-read-only t)) + (Info-fontify-node)) + (when msgp (message "`Info-fontify-single-quote-flag' is now %s" + (if Info-fontify-single-quote-flag 'ON 'OFF))))) + +;;;###autoload (autoload 'Info-toggle-fontify-angle-bracketed "info+") +(defun Info-toggle-fontify-angle-bracketed (&optional msgp) + "Toggle option `Info-fontify-angle-bracketed-flag'." + (interactive "p") + (setq Info-fontify-angle-bracketed-flag (not Info-fontify-angle-bracketed-flag)) + (when (eq major-mode 'Info-mode) + (font-lock-defontify) + (let ((modp (buffer-modified-p)) + (inhibit-read-only t)) + (Info-fontify-node)) + (when msgp (message "`Info-fontify-angle-bracketed-flag' is now %s" + (if Info-fontify-angle-bracketed-flag 'ON 'OFF))))) + +;;;###autoload (autoload 'Info-save-current-node "info+") +(defun Info-save-current-node (&optional msgp) + "Save name of current Info node to list `Info-saved-nodes'." + (interactive "p") + (unless (eq major-mode 'Info-mode) (info-user-error "You must be in Info to use this command")) + (unless Info-current-node (info-user-error "No current Info node")) + (unless Info-current-file (info-user-error "No Info file")) + (add-to-list 'Info-saved-nodes (concat "(" (file-name-nondirectory Info-current-file) ")" + Info-current-node)) + (when msgp (message (format "Node `%s' saved" Info-current-node)))) + +(when (require 'bookmark+ nil t) + + (defun Info-describe-bookmark (&optional node show-definition-p) + "Describe bookmark for NODE (default: bookmarked node named at point). +With a prefix argument, show the internal definition of the bookmark. + +If there is no bookmarked node named at point then you are prompted +for the name of one. + +When called from Lisp, NODE is a full node name: `(MANUAL) NODE'. +That is, it corresponds to a default Info bookmark name." + (interactive + (list (or (Info-bookmark-name-at-point) (Info-read-bookmarked-node-name)) + current-prefix-arg)) + (let* ((alist (bmkp-info-alist-only)) + (bmk (or (bmkp-get-bookmark-in-alist node t alist) + (bmkp-read-bookmark-for-type "Info" alist nil nil 'bmkp-info-history "Describe ")))) + (bmkp-describe-bookmark bmk show-definition-p))) + + (defun Info-read-bookmarked-node-name (&optional localp) + "Read and return the name of a bookmarked Info node. +A bookmarked node name has the form \"(MANUAL) NODE\", referring to +NODE in MANUAL. +Optional arg LOCALP means read a node name from the current manual." + (let* ((completion-ignore-case t) + (bmks (remove-if-not + (lambda (bmk) (bmkp-string-match-p (if (and localp Info-current-file) + (format "\\`(%s) " + (file-name-sans-extension + (file-name-nondirectory Info-current-file))) + "(\\([^)]+\\)) \\([^)]*\\)") + (bmkp-bookmark-name-from-record bmk))) + (bmkp-info-alist-only))) + (bmk (completing-read "Bookmarked node: " bmks nil t nil 'bmkp-info-history))) + (while (equal bmk "") (setq bmk (completing-read "Bookmarked node: " bmks nil t nil 'bmkp-info-history))) + bmk)) + + ) + + +;;; Support for TOC with Outline support --------------------- + + +;; REPLACE ORIGINAL in `outline.el': +;; +;; See Emacs bug #28080. +;; +(defun outline-invisible-p (&optional pos) + "Non-nil if the character after point has been made invisible by Outline." + (eq (get-char-property (or pos (point)) 'invisible) 'outline)) + + +(when (boundp 'Info-virtual-nodes) ; Emacs 23.4+ + + (add-to-list 'Info-virtual-nodes '("\\`\\*TOC Outline\\* (.*)\\'" (find-node . Info-toc-outline-find-node))) + + (defun Info-toc-outline (&optional arg) + "Go to a node with a table of contents (TOC) in `outline-minor-mode'. +The TOC is created from the tree structure of Info menus. + +In this node you can use the commands and menu items of +`outline-minor-mode' to navigate, hide/show, delete, or rearrange +parts of the TOC. Start with menu-bar menu `Outline' to see what is +possible. + +* With no prefix arg: + + - If buffer `*TOC Outline* (MANUAL)' exists, where MANUAL is the + manual/file name for the current manual, then pop to it. + - Else create that buffer for the current manual, and pop to it. + +* With a plain prefix arg (`C-u'): + + Pop to a new TOC buffer, `*TOC Outline* (MANUAL)' (or `*TOC + Outline* (MANUAL)', N=1,2,3...), for the current MANUAL. + +* With any other prefix arg (e.g. `M--'): + + Reuse the current Info buffer, going to a node `*TOC Outline*' + for the current manual." + (interactive (list (if (consp current-prefix-arg) 'clone current-prefix-arg))) + (unless (derived-mode-p 'Info-mode) (info-user-error "You must be in Info to use this command")) + (unless Info-current-node (info-user-error "No current Info node")) + (unless Info-current-file (info-user-error "No Info file")) + (when (equal Info-current-file "dir") (info-user-error "No TOC for Info Directory - choose a manual")) + (if (and (not arg) (get-buffer (format "*TOC Outline* (%s)" (file-name-nondirectory Info-current-file)))) + (pop-to-buffer (format "*TOC Outline* (%s)" (file-name-nondirectory Info-current-file))) + (when (or (not arg) (eq arg 'clone)) + (clone-buffer (format "*TOC Outline* (%s)" (file-name-nondirectory Info-current-file)) t)) + (Info-breadcrumbs-in-mode-line-mode -1) + (setq mark-ring ()) ;`clone-buffer' causes this to be needed, if `*info*' buffer has no mark. + (Info-find-node Info-current-file (format "*TOC Outline* (%s)" (file-name-nondirectory Info-current-file))) + (let ((prev-node (nth 1 (car Info-history))) + prev-posn) + (goto-char (point-min)) + (when (setq prev-posn (search-forward (concat "*Note " prev-node ":") nil t)) + (setq prev-posn (- prev-posn (length prev-node) 2))) + (goto-char (or prev-posn (point-min)))))) + + (defun Info-toc-outline-find-node (filename nodename &optional _no-going-back) + "TOC-specific implementation of `Info-find-node-2'." + (let* ((curr-file (substring-no-properties (or filename Info-current-file))) + (curr-node (substring-no-properties (or nodename Info-current-node))) + (node-list (Info-toc-nodes curr-file))) + (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n" curr-file curr-node)) + (let ((title (format "Contents (%s)" (file-name-nondirectory curr-file)))) + (insert title "\n" (make-string (length title) ?*) "\n\n")) + (insert "*Note Top::\n") + (Info-toc-insert (nth 3 (assoc "Top" node-list)) node-list 0 curr-file) ; `Top' nodes + (unless (bobp) + (let ((Info-hide-note-references 'hide) + (Info-fontify-visited-nodes nil)) + (setq Info-current-file filename + Info-current-node (format "*TOC Outline* (%s)" (file-name-nondirectory curr-file))) + (goto-char (point-min)) + (narrow-to-region (or (re-search-forward "\n[\^_\f]\n" nil t) (point-min)) (point-max)) + (Info-fontify-node) + (widen)))) + (set (make-local-variable 'inhibit-read-only) t) + (goto-char (point-min)) + (search-forward "Contents" nil t) + (forward-line 3) + ;; If `Info-toc-outline-no-redundancy-flag' is non-nil then remove redundancies. Else give non-links face `info-title-4'. + (save-excursion + (let ((note-re "^[\t]*[*]Note ")) + (while (not (eobp)) + (if (re-search-forward note-re (line-end-position) t) + (if (and Info-toc-outline-no-redundancy-flag ; Remove node line if already listed. + (let ((node (buffer-substring-no-properties (point) (line-end-position)))) + (save-excursion (beginning-of-line) (re-search-backward (concat note-re node) nil t)))) + (delete-region (line-beginning-position) (line-beginning-position 2)) + (save-excursion ; Indent previous line to same column, if it was a heading. + (let ((col (current-column))) + (forward-line -1) + (unless (re-search-forward note-re (line-end-position) t) + (insert (propertize " " 'display `(space :align-to ,col)))))) + (forward-line 1)) + (if Info-toc-outline-no-redundancy-flag + (delete-region (line-beginning-position) (line-beginning-position 2)) + ;; The line is a section heading. Put face `info-title-4' on it. + (put-text-property (line-beginning-position 1) (line-end-position 1) 'face 'info-title-4) + (unless (looking-at "\\s-") (insert "\n")) + (forward-line 1)))))) + (outline-minor-mode 1) + (define-key Info-toc-outline-map [remap outline-promote] 'Info-outline-promote) + (define-key Info-toc-outline-map [remap outline-demote] 'Info-outline-demote) + (define-key Info-toc-outline-map "\C-x\M-l" 'Info-toc-outline-refontify-region) + (use-local-map Info-toc-outline-map) + (setq outline-regexp "[\t]*[*]Note ") ; Include no "^" here. + (set (make-local-variable 'Info-hide-note-references) 'hide) + (add-hook 'post-command-hook 'Info-toc-outline-refontify-region nil 'LOCAL) + (buffer-enable-undo)) + + (defun Info-toc-outline-refontify-region (&optional start end forcep) + "In Info `*TOC Outline*' buffer, refontify region. +Interactively, if region is not active or is empty, refontify buffer. +From Lisp: + * Do nothing if not in a `*TOC Outline* buffer or if buffer has not + been modified. + * START defaults to `point-min', END defaults to `point-max'." + (interactive (let* ((regionp (use-region-p)) + (st (if regionp (region-beginning) (point-min))) + (en (if regionp (region-end) (point-max)))) + (list st en t))) + (setq start (or start (point-min)) + end (or end (point-max))) + (let ((buff (buffer-name))) + (when (or forcep (and buff + (buffer-modified-p) + (string-match-p "\\`\\*TOC Outline\\* ([^)]+)" buff) + (derived-mode-p 'Info-mode))) + (Info-toc-outline-refontify-links start end)))) + + (defun Info-outline-promote (&optional which) + "Promote headings higher up the tree. +If `transient-mark-mode' is on and the mark is active, promote +headings in the region (from a Lisp program, pass the symbol `region' +for WHICH). +Otherwise: + * With no prefix arg, promote the current heading and all headings in + the subtree (from a Lisp program, pass symbol `subtree' for WHICH); + * with a prefix arg, promote just the current heading (from a Lisp + program, pass nil for WHICH, or do not pass any argument). + +This is a version of `outline-promote' for use with Info. It +refontifies the buffer to hide the link prefix `*Note'." + (interactive (list (if (and transient-mark-mode mark-active) + 'region + (outline-back-to-heading) + (and (not current-prefix-arg) 'subtree)))) + (let (start end) + (cond ((eq which 'region) + (outline-map-region 'Info-outline-promote + (setq start (copy-marker (region-beginning))) + (prog1 (region-end) + (setq end (save-excursion (goto-char (region-end)) (copy-marker (line-end-position))))))) + (which + (outline-map-region 'Info-outline-promote + (setq start (copy-marker (point))) + (save-excursion (outline-get-next-sibling) (setq end (copy-marker (point)))))) + (t + (outline-back-to-heading t) + (setq start (copy-marker (point)) + end (copy-marker (line-end-position))) + (let* ((head (match-string-no-properties 0)) + (level (save-match-data (funcall outline-level))) + (up-head (or (outline-head-from-level (1- level) head) + (save-excursion ; Use the parent heading, if it is really one level less. + (save-match-data + (outline-up-heading 1 t) + (and (= (1- level) (funcall outline-level)) (match-string-no-properties 0)))) + (error "Cannot promote - already at highest level")))) + (unless (rassoc level outline-heading-alist) (push (cons head level) outline-heading-alist)) + (replace-match up-head nil t)))) + (Info-toc-outline-refontify-links start end))) + + (defun Info-outline-demote (&optional which) + "Demote headings lower down the tree. +If `transient-mark-mode' is on and the mark isactive, demote headings +in the region (from a Lisp program, pass symbol `region' for WHICH). +Otherwise: + * Without a prefix arg, demote current heading and all headings in the + subtree (from a Lisp program, pass symbol `subtree' for WHICH). + * With a prefix arg, demote just the current heading (from a Lisp + program, pass nil for WHICH, or do not pass any argument). + +This is a version of `outline-demote' for use with Info. It +refontifies the buffer to hide link prefix `*Note'." + (interactive (list (if (and transient-mark-mode mark-active) + 'region + (outline-back-to-heading) + (and (not current-prefix-arg) 'subtree)))) + (let (start end) + (cond ((eq which 'region) + (outline-map-region 'Info-outline-demote + (setq start (copy-marker (region-beginning))) + (prog1 (region-end) + (setq end (save-excursion (goto-char (region-end)) (copy-marker (line-end-position))))))) + (which + (outline-map-region 'Info-outline-demote + (setq start (copy-marker (point))) + (save-excursion (outline-get-next-sibling) (setq end (copy-marker (point)))))) + (t + (setq start (copy-marker (point)) + end (copy-marker (line-end-position))) + (let* ((head (match-string-no-properties 0)) + (level (save-match-data (funcall outline-level))) + (down-head (or (outline-head-from-level (1+ level) head) + (save-excursion + (save-match-data + (while (and (progn (outline-next-heading) (not (eobp))) + (<= (funcall outline-level) level))) + (when (eobp) ; Try again from beginning of buffer. + (goto-char (point-min)) + (while (and (progn (outline-next-heading) (not (eobp))) + (<= (funcall outline-level) level)))) + (unless (eobp) + (looking-at outline-regexp) + (match-string-no-properties 0)))) + (error "Cannot demote - already at lowest level")))) + (unless (rassoc level outline-heading-alist) (push (cons head level) outline-heading-alist)) + (replace-match down-head nil t)))) + (Info-toc-outline-refontify-links start end))) + + (defun Info-toc-outline-refontify-links (begin end) + "Refontify TOC cross references between buffer positions BEGIN and END." + ;; (interactive "r") ; Not really intended as a command, but might be handy sometimes (?). + (save-excursion + (let* ((inhibit-read-only t) + (case-fold-search t) + (fontify-bookmarked-p (and (boundp 'Info-fontify-bookmarked-xrefs-flag) Info-fontify-bookmarked-xrefs-flag)) + (node-not-too-large (and (or fontify-bookmarked-p Info-fontify-visited-nodes) + Info-fontify-maximum-menu-size + (or (eq t Info-fontify-maximum-menu-size) + (< (- (point-max) (point-min)) Info-fontify-maximum-menu-size)))) + (fontify-bookmarked-p (and node-not-too-large fontify-bookmarked-p)) + (fontify-visited-p (and node-not-too-large Info-fontify-visited-nodes)) + paragraph-markers rbeg rend) + (goto-char begin) + (while (re-search-forward "\\(\\*Note[ \n\t]+\\)\\([^:]*\\)\\(:[ \t]*\\([^.,:(]*\\)\\(\\(([^)]\ +*)\\)[^.,:]*\\)?[,:]?\n?\\)" end t) + (let ((start (match-beginning 0)) + (next (point)) + other-tag) + (when Info-hide-note-references + (when (not (eq Info-hide-note-references 'hide)) ; *Note is often used where *note should have been. + (goto-char start) + (skip-syntax-backward " ") + (when (memq (char-before) '(?\( ?\[ ?\{)) + (skip-syntax-backward " (")) ; Check whether the paren is preceded by an end of sentence. + (setq other-tag (cond ((save-match-data (looking-back "\\