
This reverts almost all my recent changes to use curved quotes in docstrings and/or strings used for error diagnostics. There are a few exceptions, e.g., Bahá’í proper names. * admin/unidata/unidata-gen.el (unidata-gen-table): * lisp/abbrev.el (expand-region-abbrevs): * lisp/align.el (align-region): * lisp/allout.el (allout-mode, allout-solicit-alternate-bullet) (outlineify-sticky): * lisp/apropos.el (apropos-library): * lisp/bookmark.el (bookmark-default-annotation-text): * lisp/button.el (button-category-symbol, button-put) (make-text-button): * lisp/calc/calc-aent.el (math-read-if, math-read-factor): * lisp/calc/calc-embed.el (calc-do-embedded): * lisp/calc/calc-ext.el (calc-user-function-list): * lisp/calc/calc-graph.el (calc-graph-show-dumb): * lisp/calc/calc-help.el (calc-describe-key) (calc-describe-thing, calc-full-help): * lisp/calc/calc-lang.el (calc-c-language) (math-parse-fortran-vector-end, math-parse-tex-sum) (math-parse-eqn-matrix, math-parse-eqn-prime) (calc-yacas-language, calc-maxima-language, calc-giac-language) (math-read-giac-subscr, math-read-math-subscr) (math-read-big-rec, math-read-big-balance): * lisp/calc/calc-misc.el (calc-help, report-calc-bug): * lisp/calc/calc-mode.el (calc-auto-why, calc-save-modes) (calc-auto-recompute): * lisp/calc/calc-prog.el (calc-fix-token-name) (calc-read-parse-table-part, calc-user-define-invocation) (math-do-arg-check): * lisp/calc/calc-store.el (calc-edit-variable): * lisp/calc/calc-units.el (math-build-units-table-buffer): * lisp/calc/calc-vec.el (math-read-brackets): * lisp/calc/calc-yank.el (calc-edit-mode): * lisp/calc/calc.el (calc, calc-do, calc-user-invocation): * lisp/calendar/appt.el (appt-display-message): * lisp/calendar/diary-lib.el (diary-check-diary-file) (diary-mail-entries, diary-from-outlook): * lisp/calendar/icalendar.el (icalendar-export-region) (icalendar--convert-float-to-ical) (icalendar--convert-date-to-ical) (icalendar--convert-ical-to-diary) (icalendar--convert-recurring-to-diary) (icalendar--add-diary-entry): * lisp/calendar/time-date.el (format-seconds): * lisp/calendar/timeclock.el (timeclock-mode-line-display) (timeclock-make-hours-explicit, timeclock-log-data): * lisp/calendar/todo-mode.el (todo-prefix, todo-delete-category) (todo-item-mark, todo-check-format) (todo-insert-item--next-param, todo-edit-item--next-key) (todo-mode): * lisp/cedet/ede/pmake.el (ede-proj-makefile-insert-dist-rules): * lisp/cedet/mode-local.el (describe-mode-local-overload) (mode-local-print-binding, mode-local-describe-bindings-2): * lisp/cedet/semantic/complete.el (semantic-displayor-show-request): * lisp/cedet/srecode/srt-mode.el (srecode-macro-help): * lisp/cus-start.el (standard): * lisp/cus-theme.el (describe-theme-1): * lisp/custom.el (custom-add-dependencies, custom-check-theme) (custom--sort-vars-1, load-theme): * lisp/descr-text.el (describe-text-properties-1, describe-char): * lisp/dired-x.el (dired-do-run-mail): * lisp/dired.el (dired-log): * lisp/emacs-lisp/advice.el (ad-read-advised-function) (ad-read-advice-class, ad-read-advice-name, ad-enable-advice) (ad-disable-advice, ad-remove-advice, ad-set-argument) (ad-set-arguments, ad--defalias-fset, ad-activate) (ad-deactivate): * lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand) (byte-compile-unfold-lambda, byte-optimize-form-code-walker) (byte-optimize-while, byte-optimize-apply): * lisp/emacs-lisp/byte-run.el (defun, defsubst): * lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode) (byte-compile-log-file, byte-compile-format-warn) (byte-compile-nogroup-warn, byte-compile-arglist-warn) (byte-compile-cl-warn) (byte-compile-warn-about-unresolved-functions) (byte-compile-file, byte-compile--declare-var) (byte-compile-file-form-defmumble, byte-compile-form) (byte-compile-normal-call, byte-compile-check-variable) (byte-compile-variable-ref, byte-compile-variable-set) (byte-compile-subr-wrong-args, byte-compile-setq-default) (byte-compile-negation-optimizer) (byte-compile-condition-case--old) (byte-compile-condition-case--new, byte-compile-save-excursion) (byte-compile-defvar, byte-compile-autoload) (byte-compile-lambda-form) (byte-compile-make-variable-buffer-local, display-call-tree) (batch-byte-compile): * lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use): * lisp/emacs-lisp/chart.el (chart-space-usage): * lisp/emacs-lisp/check-declare.el (check-declare-scan) (check-declare-warn, check-declare-file) (check-declare-directory): * lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine) (checkdoc-message-text-engine): * lisp/emacs-lisp/cl-extra.el (cl-parse-integer) (cl--describe-class): * lisp/emacs-lisp/cl-generic.el (cl-defgeneric) (cl--generic-describe, cl-generic-generalizers): * lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause, cl-tagbody) (cl-symbol-macrolet): * lisp/emacs-lisp/cl.el (cl-unload-function, flet): * lisp/emacs-lisp/copyright.el (copyright) (copyright-update-directory): * lisp/emacs-lisp/edebug.el (edebug-read-list): * lisp/emacs-lisp/eieio-base.el (eieio-persistent-read): * lisp/emacs-lisp/eieio-core.el (eieio--slot-override) (eieio-oref): * lisp/emacs-lisp/eieio-opt.el (eieio-help-constructor): * lisp/emacs-lisp/eieio-speedbar.el: (eieio-speedbar-child-make-tag-lines) (eieio-speedbar-child-description): * lisp/emacs-lisp/eieio.el (defclass, change-class): * lisp/emacs-lisp/elint.el (elint-file, elint-get-top-forms) (elint-init-form, elint-check-defalias-form) (elint-check-let-form): * lisp/emacs-lisp/ert.el (ert-get-test, ert-results-mode-menu) (ert-results-pop-to-backtrace-for-test-at-point) (ert-results-pop-to-messages-for-test-at-point) (ert-results-pop-to-should-forms-for-test-at-point) (ert-describe-test): * lisp/emacs-lisp/find-func.el (find-function-search-for-symbol) (find-function-library): * lisp/emacs-lisp/generator.el (iter-yield): * lisp/emacs-lisp/gv.el (gv-define-simple-setter): * lisp/emacs-lisp/lisp-mnt.el (lm-verify): * lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning): * lisp/emacs-lisp/map-ynp.el (map-y-or-n-p): * lisp/emacs-lisp/nadvice.el (advice--make-docstring) (advice--make, define-advice): * lisp/emacs-lisp/package-x.el (package-upload-file): * lisp/emacs-lisp/package.el (package-version-join) (package-disabled-p, package-activate-1, package-activate) (package--download-one-archive) (package--download-and-read-archives) (package-compute-transaction, package-install-from-archive) (package-install, package-install-selected-packages) (package-delete, package-autoremove, describe-package-1) (package-install-button-action, package-delete-button-action) (package-menu-hide-package, package-menu--list-to-prompt) (package-menu--perform-transaction) (package-menu--find-and-notify-upgrades): * lisp/emacs-lisp/pcase.el (pcase-exhaustive, pcase--u1): * lisp/emacs-lisp/re-builder.el (reb-enter-subexp-mode): * lisp/emacs-lisp/ring.el (ring-previous, ring-next): * lisp/emacs-lisp/rx.el (rx-check, rx-anything) (rx-check-any-string, rx-check-any, rx-check-not, rx-=) (rx-repeat, rx-check-backref, rx-syntax, rx-check-category) (rx-form): * lisp/emacs-lisp/smie.el (smie-config-save): * lisp/emacs-lisp/subr-x.el (internal--check-binding): * lisp/emacs-lisp/tabulated-list.el (tabulated-list-put-tag): * lisp/emacs-lisp/testcover.el (testcover-1value): * lisp/emacs-lisp/timer.el (timer-event-handler): * lisp/emulation/viper-cmd.el (viper-toggle-parse-sexp-ignore-comments) (viper-toggle-search-style, viper-kill-buffer) (viper-brac-function): * lisp/emulation/viper-macs.el (viper-record-kbd-macro): * lisp/env.el (setenv): * lisp/erc/erc-button.el (erc-nick-popup): * lisp/erc/erc.el (erc-cmd-LOAD, erc-handle-login, english): * lisp/eshell/em-dirs.el (eshell/cd): * lisp/eshell/em-glob.el (eshell-glob-regexp) (eshell-glob-entries): * lisp/eshell/em-pred.el (eshell-parse-modifiers): * lisp/eshell/esh-opt.el (eshell-show-usage): * lisp/facemenu.el (facemenu-add-new-face) (facemenu-add-new-color): * lisp/faces.el (read-face-name, read-face-font, describe-face) (x-resolve-font-name): * lisp/files-x.el (modify-file-local-variable): * lisp/files.el (locate-user-emacs-file, find-alternate-file) (set-auto-mode, hack-one-local-variable--obsolete) (dir-locals-set-directory-class, write-file, basic-save-buffer) (delete-directory, copy-directory, recover-session) (recover-session-finish, insert-directory) (file-modes-char-to-who, file-modes-symbolic-to-number) (move-file-to-trash): * lisp/filesets.el (filesets-add-buffer, filesets-remove-buffer): * lisp/find-cmd.el (find-generic, find-to-string): * lisp/finder.el (finder-commentary): * lisp/font-lock.el (font-lock-fontify-buffer): * lisp/format.el (format-write-file, format-find-file) (format-insert-file): * lisp/frame.el (get-device-terminal, select-frame-by-name): * lisp/fringe.el (fringe--check-style): * lisp/gnus/nnmairix.el (nnmairix-widget-create-query): * lisp/help-fns.el (help-fns--key-bindings) (help-fns--compiler-macro, help-fns--parent-mode) (help-fns--obsolete, help-fns--interactive-only) (describe-function-1, describe-variable): * lisp/help.el (describe-mode) (describe-minor-mode-from-indicator): * lisp/image.el (image-type): * lisp/international/ccl.el (ccl-dump): * lisp/international/fontset.el (x-must-resolve-font-name): * lisp/international/mule-cmds.el (prefer-coding-system) (select-safe-coding-system-interactively) (select-safe-coding-system, activate-input-method) (toggle-input-method, describe-current-input-method) (describe-language-environment): * lisp/international/mule-conf.el (code-offset): * lisp/international/mule-diag.el (describe-character-set) (list-input-methods-1): * lisp/mail/feedmail.el (feedmail-run-the-queue): * lisp/mouse.el (minor-mode-menu-from-indicator): * lisp/mpc.el (mpc-playlist-rename): * lisp/msb.el (msb--choose-menu): * lisp/net/ange-ftp.el (ange-ftp-shell-command): * lisp/net/imap.el (imap-interactive-login): * lisp/net/mairix.el (mairix-widget-create-query): * lisp/net/newst-backend.el (newsticker--sentinel-work): * lisp/net/newst-treeview.el (newsticker--treeview-load): * lisp/net/rlogin.el (rlogin): * lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer): * lisp/obsolete/otodo-mode.el (todo-more-important-p): * lisp/obsolete/pgg-gpg.el (pgg-gpg-process-region): * lisp/obsolete/pgg-pgp.el (pgg-pgp-process-region): * lisp/obsolete/pgg-pgp5.el (pgg-pgp5-process-region): * lisp/org/ob-core.el (org-babel-goto-named-src-block) (org-babel-goto-named-result): * lisp/org/ob-fortran.el (org-babel-fortran-ensure-main-wrap): * lisp/org/ob-ref.el (org-babel-ref-resolve): * lisp/org/org-agenda.el (org-agenda-prepare): * lisp/org/org-clock.el (org-clock-notify-once-if-expired) (org-clock-resolve): * lisp/org/org-ctags.el (org-ctags-ask-rebuild-tags-file-then-find-tag): * lisp/org/org-feed.el (org-feed-parse-atom-entry): * lisp/org/org-habit.el (org-habit-parse-todo): * lisp/org/org-mouse.el (org-mouse-popup-global-menu) (org-mouse-context-menu): * lisp/org/org-table.el (org-table-edit-formulas): * lisp/org/ox.el (org-export-async-start): * lisp/proced.el (proced-log): * lisp/progmodes/ada-mode.el (ada-get-indent-case) (ada-check-matching-start, ada-goto-matching-start): * lisp/progmodes/ada-prj.el (ada-prj-display-page): * lisp/progmodes/ada-xref.el (ada-find-executable): * lisp/progmodes/ebrowse.el (ebrowse-tags-apropos): * lisp/progmodes/etags.el (etags-tags-apropos-additional): * lisp/progmodes/flymake.el (flymake-parse-err-lines) (flymake-start-syntax-check-process): * lisp/progmodes/python.el (python-shell-get-process-or-error) (python-define-auxiliary-skeleton): * lisp/progmodes/sql.el (sql-comint): * lisp/progmodes/verilog-mode.el (verilog-load-file-at-point): * lisp/progmodes/vhdl-mode.el (vhdl-widget-directory-validate): * lisp/recentf.el (recentf-open-files): * lisp/replace.el (query-replace-read-from) (occur-after-change-function, occur-1): * lisp/scroll-bar.el (scroll-bar-columns): * lisp/server.el (server-get-auth-key): * lisp/simple.el (execute-extended-command) (undo-outer-limit-truncate, list-processes--refresh) (compose-mail, set-variable, choose-completion-string) (define-alternatives): * lisp/startup.el (site-run-file, tty-handle-args, command-line) (command-line-1): * lisp/subr.el (noreturn, define-error, add-to-list) (read-char-choice, version-to-list): * lisp/term/common-win.el (x-handle-xrm-switch) (x-handle-name-switch, x-handle-args): * lisp/term/x-win.el (x-handle-parent-id, x-handle-smid): * lisp/textmodes/reftex-ref.el (reftex-label): * lisp/textmodes/reftex-toc.el (reftex-toc-rename-label): * lisp/textmodes/two-column.el (2C-split): * lisp/tutorial.el (tutorial--describe-nonstandard-key) (tutorial--find-changed-keys): * lisp/type-break.el (type-break-noninteractive-query): * lisp/wdired.el (wdired-do-renames, wdired-do-symlink-changes) (wdired-do-perm-changes): * lisp/whitespace.el (whitespace-report-region): Prefer grave quoting in source-code strings used to generate help and diagnostics. * lisp/faces.el (face-documentation): No need to convert quotes, since the result is a docstring. * lisp/info.el (Info-virtual-index-find-node) (Info-virtual-index, info-apropos): Simplify by generating only curved quotes, since info files are typically that ways nowadays anyway. * lisp/international/mule-diag.el (list-input-methods): Don’t assume text quoting style is curved. * lisp/org/org-bibtex.el (org-bibtex-fields): Revert my recent changes, going back to the old quoting style.
890 lines
31 KiB
EmacsLisp
890 lines
31 KiB
EmacsLisp
;;; cl-extra.el --- Common Lisp features, part 2 -*- lexical-binding: t -*-
|
|
|
|
;; Copyright (C) 1993, 2000-2015 Free Software Foundation, Inc.
|
|
|
|
;; Author: Dave Gillespie <daveg@synaptics.com>
|
|
;; Keywords: extensions
|
|
;; Package: emacs
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
;;; Commentary:
|
|
|
|
;; These are extensions to Emacs Lisp that provide a degree of
|
|
;; Common Lisp compatibility, beyond what is already built-in
|
|
;; in Emacs Lisp.
|
|
;;
|
|
;; This package was written by Dave Gillespie; it is a complete
|
|
;; rewrite of Cesar Quiroz's original cl.el package of December 1986.
|
|
;;
|
|
;; Bug reports, comments, and suggestions are welcome!
|
|
|
|
;; This file contains portions of the Common Lisp extensions
|
|
;; package which are autoloaded since they are relatively obscure.
|
|
|
|
;;; Code:
|
|
|
|
(require 'cl-lib)
|
|
|
|
;;; Type coercion.
|
|
|
|
;;;###autoload
|
|
(defun cl-coerce (x type)
|
|
"Coerce OBJECT to type TYPE.
|
|
TYPE is a Common Lisp type specifier.
|
|
\n(fn OBJECT TYPE)"
|
|
(cond ((eq type 'list) (if (listp x) x (append x nil)))
|
|
((eq type 'vector) (if (vectorp x) x (vconcat x)))
|
|
((eq type 'string) (if (stringp x) x (concat x)))
|
|
((eq type 'array) (if (arrayp x) x (vconcat x)))
|
|
((and (eq type 'character) (stringp x) (= (length x) 1)) (aref x 0))
|
|
((and (eq type 'character) (symbolp x))
|
|
(cl-coerce (symbol-name x) type))
|
|
((eq type 'float) (float x))
|
|
((cl-typep x type) x)
|
|
(t (error "Can't coerce %s to type %s" x type))))
|
|
|
|
|
|
;;; Predicates.
|
|
|
|
;;;###autoload
|
|
(defun cl-equalp (x y)
|
|
"Return t if two Lisp objects have similar structures and contents.
|
|
This is like `equal', except that it accepts numerically equal
|
|
numbers of different types (float vs. integer), and also compares
|
|
strings case-insensitively."
|
|
(cond ((eq x y) t)
|
|
((stringp x)
|
|
(and (stringp y) (= (length x) (length y))
|
|
(or (string-equal x y)
|
|
(string-equal (downcase x) (downcase y))))) ;Lazy but simple!
|
|
((numberp x)
|
|
(and (numberp y) (= x y)))
|
|
((consp x)
|
|
(while (and (consp x) (consp y) (cl-equalp (car x) (car y)))
|
|
(setq x (cdr x) y (cdr y)))
|
|
(and (not (consp x)) (cl-equalp x y)))
|
|
((vectorp x)
|
|
(and (vectorp y) (= (length x) (length y))
|
|
(let ((i (length x)))
|
|
(while (and (>= (setq i (1- i)) 0)
|
|
(cl-equalp (aref x i) (aref y i))))
|
|
(< i 0))))
|
|
(t (equal x y))))
|
|
|
|
|
|
;;; Control structures.
|
|
|
|
;;;###autoload
|
|
(defun cl--mapcar-many (cl-func cl-seqs)
|
|
(if (cdr (cdr cl-seqs))
|
|
(let* ((cl-res nil)
|
|
(cl-n (apply 'min (mapcar 'length cl-seqs)))
|
|
(cl-i 0)
|
|
(cl-args (copy-sequence cl-seqs))
|
|
cl-p1 cl-p2)
|
|
(setq cl-seqs (copy-sequence cl-seqs))
|
|
(while (< cl-i cl-n)
|
|
(setq cl-p1 cl-seqs cl-p2 cl-args)
|
|
(while cl-p1
|
|
(setcar cl-p2
|
|
(if (consp (car cl-p1))
|
|
(prog1 (car (car cl-p1))
|
|
(setcar cl-p1 (cdr (car cl-p1))))
|
|
(aref (car cl-p1) cl-i)))
|
|
(setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2)))
|
|
(push (apply cl-func cl-args) cl-res)
|
|
(setq cl-i (1+ cl-i)))
|
|
(nreverse cl-res))
|
|
(let ((cl-res nil)
|
|
(cl-x (car cl-seqs))
|
|
(cl-y (nth 1 cl-seqs)))
|
|
(let ((cl-n (min (length cl-x) (length cl-y)))
|
|
(cl-i -1))
|
|
(while (< (setq cl-i (1+ cl-i)) cl-n)
|
|
(push (funcall cl-func
|
|
(if (consp cl-x) (pop cl-x) (aref cl-x cl-i))
|
|
(if (consp cl-y) (pop cl-y) (aref cl-y cl-i)))
|
|
cl-res)))
|
|
(nreverse cl-res))))
|
|
|
|
;;;###autoload
|
|
(defun cl-map (cl-type cl-func cl-seq &rest cl-rest)
|
|
"Map a FUNCTION across one or more SEQUENCEs, returning a sequence.
|
|
TYPE is the sequence type to return.
|
|
\n(fn TYPE FUNCTION SEQUENCE...)"
|
|
(let ((cl-res (apply 'cl-mapcar cl-func cl-seq cl-rest)))
|
|
(and cl-type (cl-coerce cl-res cl-type))))
|
|
|
|
;;;###autoload
|
|
(defun cl-maplist (cl-func cl-list &rest cl-rest)
|
|
"Map FUNCTION to each sublist of LIST or LISTs.
|
|
Like `cl-mapcar', except applies to lists and their cdr's rather than to
|
|
the elements themselves.
|
|
\n(fn FUNCTION LIST...)"
|
|
(if cl-rest
|
|
(let ((cl-res nil)
|
|
(cl-args (cons cl-list (copy-sequence cl-rest)))
|
|
cl-p)
|
|
(while (not (memq nil cl-args))
|
|
(push (apply cl-func cl-args) cl-res)
|
|
(setq cl-p cl-args)
|
|
(while cl-p (setcar cl-p (cdr (pop cl-p)) )))
|
|
(nreverse cl-res))
|
|
(let ((cl-res nil))
|
|
(while cl-list
|
|
(push (funcall cl-func cl-list) cl-res)
|
|
(setq cl-list (cdr cl-list)))
|
|
(nreverse cl-res))))
|
|
|
|
;;;###autoload
|
|
(defun cl-mapc (cl-func cl-seq &rest cl-rest)
|
|
"Like `cl-mapcar', but does not accumulate values returned by the function.
|
|
\n(fn FUNCTION SEQUENCE...)"
|
|
(if cl-rest
|
|
(progn (apply 'cl-map nil cl-func cl-seq cl-rest)
|
|
cl-seq)
|
|
(mapc cl-func cl-seq)))
|
|
|
|
;;;###autoload
|
|
(defun cl-mapl (cl-func cl-list &rest cl-rest)
|
|
"Like `cl-maplist', but does not accumulate values returned by the function.
|
|
\n(fn FUNCTION LIST...)"
|
|
(if cl-rest
|
|
(apply 'cl-maplist cl-func cl-list cl-rest)
|
|
(let ((cl-p cl-list))
|
|
(while cl-p (funcall cl-func cl-p) (setq cl-p (cdr cl-p)))))
|
|
cl-list)
|
|
|
|
;;;###autoload
|
|
(defun cl-mapcan (cl-func cl-seq &rest cl-rest)
|
|
"Like `cl-mapcar', but nconc's together the values returned by the function.
|
|
\n(fn FUNCTION SEQUENCE...)"
|
|
(apply 'nconc (apply 'cl-mapcar cl-func cl-seq cl-rest)))
|
|
|
|
;;;###autoload
|
|
(defun cl-mapcon (cl-func cl-list &rest cl-rest)
|
|
"Like `cl-maplist', but nconc's together the values returned by the function.
|
|
\n(fn FUNCTION LIST...)"
|
|
(apply 'nconc (apply 'cl-maplist cl-func cl-list cl-rest)))
|
|
|
|
;;;###autoload
|
|
(defun cl-some (cl-pred cl-seq &rest cl-rest)
|
|
"Return true if PREDICATE is true of any element of SEQ or SEQs.
|
|
If so, return the true (non-nil) value returned by PREDICATE.
|
|
\n(fn PREDICATE SEQ...)"
|
|
(if (or cl-rest (nlistp cl-seq))
|
|
(catch 'cl-some
|
|
(apply 'cl-map nil
|
|
(function (lambda (&rest cl-x)
|
|
(let ((cl-res (apply cl-pred cl-x)))
|
|
(if cl-res (throw 'cl-some cl-res)))))
|
|
cl-seq cl-rest) nil)
|
|
(let ((cl-x nil))
|
|
(while (and cl-seq (not (setq cl-x (funcall cl-pred (pop cl-seq))))))
|
|
cl-x)))
|
|
|
|
;;;###autoload
|
|
(defun cl-every (cl-pred cl-seq &rest cl-rest)
|
|
"Return true if PREDICATE is true of every element of SEQ or SEQs.
|
|
\n(fn PREDICATE SEQ...)"
|
|
(if (or cl-rest (nlistp cl-seq))
|
|
(catch 'cl-every
|
|
(apply 'cl-map nil
|
|
(function (lambda (&rest cl-x)
|
|
(or (apply cl-pred cl-x) (throw 'cl-every nil))))
|
|
cl-seq cl-rest) t)
|
|
(while (and cl-seq (funcall cl-pred (car cl-seq)))
|
|
(setq cl-seq (cdr cl-seq)))
|
|
(null cl-seq)))
|
|
|
|
;;;###autoload
|
|
(defun cl-notany (cl-pred cl-seq &rest cl-rest)
|
|
"Return true if PREDICATE is false of every element of SEQ or SEQs.
|
|
\n(fn PREDICATE SEQ...)"
|
|
(not (apply 'cl-some cl-pred cl-seq cl-rest)))
|
|
|
|
;;;###autoload
|
|
(defun cl-notevery (cl-pred cl-seq &rest cl-rest)
|
|
"Return true if PREDICATE is false of some element of SEQ or SEQs.
|
|
\n(fn PREDICATE SEQ...)"
|
|
(not (apply 'cl-every cl-pred cl-seq cl-rest)))
|
|
|
|
;;;###autoload
|
|
(defun cl--map-keymap-recursively (cl-func-rec cl-map &optional cl-base)
|
|
(or cl-base
|
|
(setq cl-base (copy-sequence [0])))
|
|
(map-keymap
|
|
(function
|
|
(lambda (cl-key cl-bind)
|
|
(aset cl-base (1- (length cl-base)) cl-key)
|
|
(if (keymapp cl-bind)
|
|
(cl--map-keymap-recursively
|
|
cl-func-rec cl-bind
|
|
(vconcat cl-base (list 0)))
|
|
(funcall cl-func-rec cl-base cl-bind))))
|
|
cl-map))
|
|
|
|
;;;###autoload
|
|
(defun cl--map-intervals (cl-func &optional cl-what cl-prop cl-start cl-end)
|
|
(or cl-what (setq cl-what (current-buffer)))
|
|
(if (bufferp cl-what)
|
|
(let (cl-mark cl-mark2 (cl-next t) cl-next2)
|
|
(with-current-buffer cl-what
|
|
(setq cl-mark (copy-marker (or cl-start (point-min))))
|
|
(setq cl-mark2 (and cl-end (copy-marker cl-end))))
|
|
(while (and cl-next (or (not cl-mark2) (< cl-mark cl-mark2)))
|
|
(setq cl-next (if cl-prop (next-single-property-change
|
|
cl-mark cl-prop cl-what)
|
|
(next-property-change cl-mark cl-what))
|
|
cl-next2 (or cl-next (with-current-buffer cl-what
|
|
(point-max))))
|
|
(funcall cl-func (prog1 (marker-position cl-mark)
|
|
(set-marker cl-mark cl-next2))
|
|
(if cl-mark2 (min cl-next2 cl-mark2) cl-next2)))
|
|
(set-marker cl-mark nil) (if cl-mark2 (set-marker cl-mark2 nil)))
|
|
(or cl-start (setq cl-start 0))
|
|
(or cl-end (setq cl-end (length cl-what)))
|
|
(while (< cl-start cl-end)
|
|
(let ((cl-next (or (if cl-prop (next-single-property-change
|
|
cl-start cl-prop cl-what)
|
|
(next-property-change cl-start cl-what))
|
|
cl-end)))
|
|
(funcall cl-func cl-start (min cl-next cl-end))
|
|
(setq cl-start cl-next)))))
|
|
|
|
;;;###autoload
|
|
(defun cl--map-overlays (cl-func &optional cl-buffer cl-start cl-end cl-arg)
|
|
(or cl-buffer (setq cl-buffer (current-buffer)))
|
|
(let (cl-ovl)
|
|
(with-current-buffer cl-buffer
|
|
(setq cl-ovl (overlay-lists))
|
|
(if cl-start (setq cl-start (copy-marker cl-start)))
|
|
(if cl-end (setq cl-end (copy-marker cl-end))))
|
|
(setq cl-ovl (nconc (car cl-ovl) (cdr cl-ovl)))
|
|
(while (and cl-ovl
|
|
(or (not (overlay-start (car cl-ovl)))
|
|
(and cl-end (>= (overlay-start (car cl-ovl)) cl-end))
|
|
(and cl-start (<= (overlay-end (car cl-ovl)) cl-start))
|
|
(not (funcall cl-func (car cl-ovl) cl-arg))))
|
|
(setq cl-ovl (cdr cl-ovl)))
|
|
(if cl-start (set-marker cl-start nil))
|
|
(if cl-end (set-marker cl-end nil))))
|
|
|
|
;;; Support for `setf'.
|
|
;;;###autoload
|
|
(defun cl--set-frame-visible-p (frame val)
|
|
(cond ((null val) (make-frame-invisible frame))
|
|
((eq val 'icon) (iconify-frame frame))
|
|
(t (make-frame-visible frame)))
|
|
val)
|
|
|
|
|
|
;;; Numbers.
|
|
|
|
;;;###autoload
|
|
(defun cl-gcd (&rest args)
|
|
"Return the greatest common divisor of the arguments."
|
|
(let ((a (or (pop args) 0)))
|
|
(dolist (b args)
|
|
(while (/= b 0)
|
|
(setq b (% a (setq a b)))))
|
|
(abs a)))
|
|
|
|
;;;###autoload
|
|
(defun cl-lcm (&rest args)
|
|
"Return the least common multiple of the arguments."
|
|
(if (memq 0 args)
|
|
0
|
|
(let ((a (or (pop args) 1)))
|
|
(dolist (b args)
|
|
(setq a (* (/ a (cl-gcd a b)) b)))
|
|
(abs a))))
|
|
|
|
;;;###autoload
|
|
(defun cl-isqrt (x)
|
|
"Return the integer square root of the argument."
|
|
(if (and (integerp x) (> x 0))
|
|
(let ((g (cond ((<= x 100) 10) ((<= x 10000) 100)
|
|
((<= x 1000000) 1000) (t x)))
|
|
g2)
|
|
(while (< (setq g2 (/ (+ g (/ x g)) 2)) g)
|
|
(setq g g2))
|
|
g)
|
|
(if (eq x 0) 0 (signal 'arith-error nil))))
|
|
|
|
;;;###autoload
|
|
(defun cl-floor (x &optional y)
|
|
"Return a list of the floor of X and the fractional part of X.
|
|
With two arguments, return floor and remainder of their quotient."
|
|
(let ((q (floor x y)))
|
|
(list q (- x (if y (* y q) q)))))
|
|
|
|
;;;###autoload
|
|
(defun cl-ceiling (x &optional y)
|
|
"Return a list of the ceiling of X and the fractional part of X.
|
|
With two arguments, return ceiling and remainder of their quotient."
|
|
(let ((res (cl-floor x y)))
|
|
(if (= (car (cdr res)) 0) res
|
|
(list (1+ (car res)) (- (car (cdr res)) (or y 1))))))
|
|
|
|
;;;###autoload
|
|
(defun cl-truncate (x &optional y)
|
|
"Return a list of the integer part of X and the fractional part of X.
|
|
With two arguments, return truncation and remainder of their quotient."
|
|
(if (eq (>= x 0) (or (null y) (>= y 0)))
|
|
(cl-floor x y) (cl-ceiling x y)))
|
|
|
|
;;;###autoload
|
|
(defun cl-round (x &optional y)
|
|
"Return a list of X rounded to the nearest integer and the remainder.
|
|
With two arguments, return rounding and remainder of their quotient."
|
|
(if y
|
|
(if (and (integerp x) (integerp y))
|
|
(let* ((hy (/ y 2))
|
|
(res (cl-floor (+ x hy) y)))
|
|
(if (and (= (car (cdr res)) 0)
|
|
(= (+ hy hy) y)
|
|
(/= (% (car res) 2) 0))
|
|
(list (1- (car res)) hy)
|
|
(list (car res) (- (car (cdr res)) hy))))
|
|
(let ((q (round (/ x y))))
|
|
(list q (- x (* q y)))))
|
|
(if (integerp x) (list x 0)
|
|
(let ((q (round x)))
|
|
(list q (- x q))))))
|
|
|
|
;;;###autoload
|
|
(defun cl-mod (x y)
|
|
"The remainder of X divided by Y, with the same sign as Y."
|
|
(nth 1 (cl-floor x y)))
|
|
|
|
;;;###autoload
|
|
(defun cl-rem (x y)
|
|
"The remainder of X divided by Y, with the same sign as X."
|
|
(nth 1 (cl-truncate x y)))
|
|
|
|
;;;###autoload
|
|
(defun cl-signum (x)
|
|
"Return 1 if X is positive, -1 if negative, 0 if zero."
|
|
(cond ((> x 0) 1) ((< x 0) -1) (t 0)))
|
|
|
|
;;;###autoload
|
|
(cl-defun cl-parse-integer (string &key start end radix junk-allowed)
|
|
"Parse integer from the substring of STRING from START to END.
|
|
STRING may be surrounded by whitespace chars (chars with syntax ` ').
|
|
Other non-digit chars are considered junk.
|
|
RADIX is an integer between 2 and 36, the default is 10. Signal
|
|
an error if the substring between START and END cannot be parsed
|
|
as an integer unless JUNK-ALLOWED is non-nil."
|
|
(cl-check-type string string)
|
|
(let* ((start (or start 0))
|
|
(len (length string))
|
|
(end (or end len))
|
|
(radix (or radix 10)))
|
|
(or (<= start end len)
|
|
(error "Bad interval: [%d, %d)" start end))
|
|
(cl-flet ((skip-whitespace ()
|
|
(while (and (< start end)
|
|
(= 32 (char-syntax (aref string start))))
|
|
(setq start (1+ start)))))
|
|
(skip-whitespace)
|
|
(let ((sign (cl-case (and (< start end) (aref string start))
|
|
(?+ (cl-incf start) +1)
|
|
(?- (cl-incf start) -1)
|
|
(t +1)))
|
|
digit sum)
|
|
(while (and (< start end)
|
|
(setq digit (cl-digit-char-p (aref string start) radix)))
|
|
(setq sum (+ (* (or sum 0) radix) digit)
|
|
start (1+ start)))
|
|
(skip-whitespace)
|
|
(cond ((and junk-allowed (null sum)) sum)
|
|
(junk-allowed (* sign sum))
|
|
((or (/= start end) (null sum))
|
|
(error "Not an integer string: `%s'" string))
|
|
(t (* sign sum)))))))
|
|
|
|
|
|
;; Random numbers.
|
|
|
|
;;;###autoload
|
|
(defun cl-random (lim &optional state)
|
|
"Return a random nonnegative number less than LIM, an integer or float.
|
|
Optional second arg STATE is a random-state object."
|
|
(or state (setq state cl--random-state))
|
|
;; Inspired by "ran3" from Numerical Recipes. Additive congruential method.
|
|
(let ((vec (aref state 3)))
|
|
(if (integerp vec)
|
|
(let ((i 0) (j (- 1357335 (abs (% vec 1357333)))) (k 1))
|
|
(aset state 3 (setq vec (make-vector 55 nil)))
|
|
(aset vec 0 j)
|
|
(while (> (setq i (% (+ i 21) 55)) 0)
|
|
(aset vec i (setq j (prog1 k (setq k (- j k))))))
|
|
(while (< (setq i (1+ i)) 200) (cl-random 2 state))))
|
|
(let* ((i (aset state 1 (% (1+ (aref state 1)) 55)))
|
|
(j (aset state 2 (% (1+ (aref state 2)) 55)))
|
|
(n (logand 8388607 (aset vec i (- (aref vec i) (aref vec j))))))
|
|
(if (integerp lim)
|
|
(if (<= lim 512) (% n lim)
|
|
(if (> lim 8388607) (setq n (+ (lsh n 9) (cl-random 512 state))))
|
|
(let ((mask 1023))
|
|
(while (< mask (1- lim)) (setq mask (1+ (+ mask mask))))
|
|
(if (< (setq n (logand n mask)) lim) n (cl-random lim state))))
|
|
(* (/ n '8388608e0) lim)))))
|
|
|
|
;;;###autoload
|
|
(defun cl-make-random-state (&optional state)
|
|
"Return a copy of random-state STATE, or of the internal state if omitted.
|
|
If STATE is t, return a new state object seeded from the time of day."
|
|
(cond ((null state) (cl-make-random-state cl--random-state))
|
|
((vectorp state) (copy-tree state t))
|
|
((integerp state) (vector 'cl--random-state-tag -1 30 state))
|
|
(t (cl-make-random-state (cl--random-time)))))
|
|
|
|
;;;###autoload
|
|
(defun cl-random-state-p (object)
|
|
"Return t if OBJECT is a random-state object."
|
|
(and (vectorp object) (= (length object) 4)
|
|
(eq (aref object 0) 'cl--random-state-tag)))
|
|
|
|
|
|
;; Implementation limits.
|
|
|
|
(defun cl--finite-do (func a b)
|
|
(condition-case _
|
|
(let ((res (funcall func a b))) ; check for IEEE infinity
|
|
(and (numberp res) (/= res (/ res 2)) res))
|
|
(arith-error nil)))
|
|
|
|
;;;###autoload
|
|
(defun cl-float-limits ()
|
|
"Initialize the Common Lisp floating-point parameters.
|
|
This sets the values of: `cl-most-positive-float', `cl-most-negative-float',
|
|
`cl-least-positive-float', `cl-least-negative-float', `cl-float-epsilon',
|
|
`cl-float-negative-epsilon', `cl-least-positive-normalized-float', and
|
|
`cl-least-negative-normalized-float'."
|
|
(or cl-most-positive-float (not (numberp '2e1))
|
|
(let ((x '2e0) y z)
|
|
;; Find maximum exponent (first two loops are optimizations)
|
|
(while (cl--finite-do '* x x) (setq x (* x x)))
|
|
(while (cl--finite-do '* x (/ x 2)) (setq x (* x (/ x 2))))
|
|
(while (cl--finite-do '+ x x) (setq x (+ x x)))
|
|
(setq z x y (/ x 2))
|
|
;; Now cl-fill in 1's in the mantissa.
|
|
(while (and (cl--finite-do '+ x y) (/= (+ x y) x))
|
|
(setq x (+ x y) y (/ y 2)))
|
|
(setq cl-most-positive-float x
|
|
cl-most-negative-float (- x))
|
|
;; Divide down until mantissa starts rounding.
|
|
(setq x (/ x z) y (/ 16 z) x (* x y))
|
|
(while (condition-case _ (and (= x (* (/ x 2) 2)) (> (/ y 2) 0))
|
|
(arith-error nil))
|
|
(setq x (/ x 2) y (/ y 2)))
|
|
(setq cl-least-positive-normalized-float y
|
|
cl-least-negative-normalized-float (- y))
|
|
;; Divide down until value underflows to zero.
|
|
(setq x (/ 1 z) y x)
|
|
(while (condition-case _ (> (/ x 2) 0) (arith-error nil))
|
|
(setq x (/ x 2)))
|
|
(setq cl-least-positive-float x
|
|
cl-least-negative-float (- x))
|
|
(setq x '1e0)
|
|
(while (/= (+ '1e0 x) '1e0) (setq x (/ x 2)))
|
|
(setq cl-float-epsilon (* x 2))
|
|
(setq x '1e0)
|
|
(while (/= (- '1e0 x) '1e0) (setq x (/ x 2)))
|
|
(setq cl-float-negative-epsilon (* x 2))))
|
|
nil)
|
|
|
|
|
|
;;; Sequence functions.
|
|
|
|
;;;###autoload
|
|
(defun cl-subseq (seq start &optional end)
|
|
"Return the subsequence of SEQ from START to END.
|
|
If END is omitted, it defaults to the length of the sequence.
|
|
If START or END is negative, it counts from the end.
|
|
Signal an error if START or END are outside of the sequence (i.e
|
|
too large if positive or too small if negative)."
|
|
(declare (gv-setter
|
|
(lambda (new)
|
|
(macroexp-let2 nil new new
|
|
`(progn (cl-replace ,seq ,new :start1 ,start :end1 ,end)
|
|
,new)))))
|
|
(cond ((or (stringp seq) (vectorp seq)) (substring seq start end))
|
|
((listp seq)
|
|
(let (len
|
|
(errtext (format "Bad bounding indices: %s, %s" start end)))
|
|
(and end (< end 0) (setq end (+ end (setq len (length seq)))))
|
|
(if (< start 0) (setq start (+ start (or len (setq len (length seq))))))
|
|
(unless (>= start 0)
|
|
(error "%s" errtext))
|
|
(when (> start 0)
|
|
(setq seq (nthcdr (1- start) seq))
|
|
(or seq (error "%s" errtext))
|
|
(setq seq (cdr seq)))
|
|
(if end
|
|
(let ((res nil))
|
|
(while (and (>= (setq end (1- end)) start) seq)
|
|
(push (pop seq) res))
|
|
(or (= (1+ end) start) (error "%s" errtext))
|
|
(nreverse res))
|
|
(copy-sequence seq))))
|
|
(t (error "Unsupported sequence: %s" seq))))
|
|
|
|
;;;###autoload
|
|
(defun cl-concatenate (type &rest sequences)
|
|
"Concatenate, into a sequence of type TYPE, the argument SEQUENCEs.
|
|
\n(fn TYPE SEQUENCE...)"
|
|
(pcase type
|
|
(`vector (apply #'vconcat sequences))
|
|
(`string (apply #'concat sequences))
|
|
(`list (apply #'append (append sequences '(nil))))
|
|
(_ (error "Not a sequence type name: %S" type))))
|
|
|
|
;;; List functions.
|
|
|
|
;;;###autoload
|
|
(defun cl-revappend (x y)
|
|
"Equivalent to (append (reverse X) Y)."
|
|
(nconc (reverse x) y))
|
|
|
|
;;;###autoload
|
|
(defun cl-nreconc (x y)
|
|
"Equivalent to (nconc (nreverse X) Y)."
|
|
(nconc (nreverse x) y))
|
|
|
|
;;;###autoload
|
|
(defun cl-list-length (x)
|
|
"Return the length of list X. Return nil if list is circular."
|
|
(let ((n 0) (fast x) (slow x))
|
|
(while (and (cdr fast) (not (and (eq fast slow) (> n 0))))
|
|
(setq n (+ n 2) fast (cdr (cdr fast)) slow (cdr slow)))
|
|
(if fast (if (cdr fast) nil (1+ n)) n)))
|
|
|
|
;;;###autoload
|
|
(defun cl-tailp (sublist list)
|
|
"Return true if SUBLIST is a tail of LIST."
|
|
(while (and (consp list) (not (eq sublist list)))
|
|
(setq list (cdr list)))
|
|
(if (numberp sublist) (equal sublist list) (eq sublist list)))
|
|
|
|
;;; Property lists.
|
|
|
|
;;;###autoload
|
|
(defun cl-get (sym tag &optional def)
|
|
"Return the value of SYMBOL's PROPNAME property, or DEFAULT if none.
|
|
\n(fn SYMBOL PROPNAME &optional DEFAULT)"
|
|
(declare (compiler-macro cl--compiler-macro-get)
|
|
(gv-setter (lambda (store) (ignore def) `(put ,sym ,tag ,store))))
|
|
(or (get sym tag)
|
|
(and def
|
|
;; Make sure `def' is really absent as opposed to set to nil.
|
|
(let ((plist (symbol-plist sym)))
|
|
(while (and plist (not (eq (car plist) tag)))
|
|
(setq plist (cdr (cdr plist))))
|
|
(if plist (car (cdr plist)) def)))))
|
|
(autoload 'cl--compiler-macro-get "cl-macs")
|
|
|
|
;;;###autoload
|
|
(defun cl-getf (plist tag &optional def)
|
|
"Search PROPLIST for property PROPNAME; return its value or DEFAULT.
|
|
PROPLIST is a list of the sort returned by `symbol-plist'.
|
|
\n(fn PROPLIST PROPNAME &optional DEFAULT)"
|
|
(declare (gv-expander
|
|
(lambda (do)
|
|
(gv-letplace (getter setter) plist
|
|
(macroexp-let2* nil ((k tag) (d def))
|
|
(funcall do `(cl-getf ,getter ,k ,d)
|
|
(lambda (v)
|
|
(macroexp-let2 nil val v
|
|
`(progn
|
|
,(funcall setter
|
|
`(cl--set-getf ,getter ,k ,val))
|
|
,val)))))))))
|
|
(setplist '--cl-getf-symbol-- plist)
|
|
(or (get '--cl-getf-symbol-- tag)
|
|
;; Originally we called cl-get here,
|
|
;; but that fails, because cl-get has a compiler macro
|
|
;; definition that uses getf!
|
|
(when def
|
|
;; Make sure `def' is really absent as opposed to set to nil.
|
|
(while (and plist (not (eq (car plist) tag)))
|
|
(setq plist (cdr (cdr plist))))
|
|
(if plist (car (cdr plist)) def))))
|
|
|
|
;;;###autoload
|
|
(defun cl--set-getf (plist tag val)
|
|
(let ((p plist))
|
|
(while (and p (not (eq (car p) tag))) (setq p (cdr (cdr p))))
|
|
(if p (progn (setcar (cdr p) val) plist) (cl-list* tag val plist))))
|
|
|
|
;;;###autoload
|
|
(defun cl--do-remf (plist tag)
|
|
(let ((p (cdr plist)))
|
|
(while (and (cdr p) (not (eq (car (cdr p)) tag))) (setq p (cdr (cdr p))))
|
|
(and (cdr p) (progn (setcdr p (cdr (cdr (cdr p)))) t))))
|
|
|
|
;;;###autoload
|
|
(defun cl-remprop (sym tag)
|
|
"Remove from SYMBOL's plist the property PROPNAME and its value.
|
|
\n(fn SYMBOL PROPNAME)"
|
|
(let ((plist (symbol-plist sym)))
|
|
(if (and plist (eq tag (car plist)))
|
|
(progn (setplist sym (cdr (cdr plist))) t)
|
|
(cl--do-remf plist tag))))
|
|
|
|
;;; Streams.
|
|
|
|
;;;###autoload
|
|
(defun cl-fresh-line (&optional stream)
|
|
"Output a newline unless already at the beginning of a line."
|
|
(terpri stream 'ensure))
|
|
|
|
;;; Some debugging aids.
|
|
|
|
(defun cl-prettyprint (form)
|
|
"Insert a pretty-printed rendition of a Lisp FORM in current buffer."
|
|
(let ((pt (point)) last)
|
|
(insert "\n" (prin1-to-string form) "\n")
|
|
(setq last (point))
|
|
(goto-char (1+ pt))
|
|
(while (search-forward "(quote " last t)
|
|
(delete-char -7)
|
|
(insert "'")
|
|
(forward-sexp)
|
|
(delete-char 1))
|
|
(goto-char (1+ pt))
|
|
(cl--do-prettyprint)))
|
|
|
|
(defun cl--do-prettyprint ()
|
|
(skip-chars-forward " ")
|
|
(if (looking-at "(")
|
|
(let ((skip (or (looking-at "((") (looking-at "(prog")
|
|
(looking-at "(unwind-protect ")
|
|
(looking-at "(function (")
|
|
(looking-at "(cl--block-wrapper ")))
|
|
(two (or (looking-at "(defun ") (looking-at "(defmacro ")))
|
|
(let (or (looking-at "(let\\*? ") (looking-at "(while ")))
|
|
(set (looking-at "(p?set[qf] ")))
|
|
(if (or skip let
|
|
(progn
|
|
(forward-sexp)
|
|
(and (>= (current-column) 78) (progn (backward-sexp) t))))
|
|
(let ((nl t))
|
|
(forward-char 1)
|
|
(cl--do-prettyprint)
|
|
(or skip (looking-at ")") (cl--do-prettyprint))
|
|
(or (not two) (looking-at ")") (cl--do-prettyprint))
|
|
(while (not (looking-at ")"))
|
|
(if set (setq nl (not nl)))
|
|
(if nl (insert "\n"))
|
|
(lisp-indent-line)
|
|
(cl--do-prettyprint))
|
|
(forward-char 1))))
|
|
(forward-sexp)))
|
|
|
|
;;;###autoload
|
|
(defun cl-prettyexpand (form &optional full)
|
|
"Expand macros in FORM and insert the pretty-printed result.
|
|
Optional argument FULL non-nil means to expand all macros,
|
|
including `cl-block' and `cl-eval-when'."
|
|
(message "Expanding...")
|
|
(let ((cl--compiling-file full)
|
|
(byte-compile-macro-environment nil))
|
|
(setq form (macroexpand-all form
|
|
(and (not full) '((cl-block) (cl-eval-when)))))
|
|
(message "Formatting...")
|
|
(prog1 (cl-prettyprint form)
|
|
(message ""))))
|
|
|
|
;;; Integration into the online help system.
|
|
|
|
(eval-when-compile (require 'cl-macs)) ;Explicitly, for cl--find-class.
|
|
(require 'help-mode)
|
|
|
|
;; FIXME: We could go crazy and add another entry so describe-symbol can be
|
|
;; used with the slot names of CL structs (and/or EIEIO objects).
|
|
(add-to-list 'describe-symbol-backends
|
|
`(nil ,#'cl-find-class ,(lambda (s _b _f) (cl-describe-type s))))
|
|
|
|
(defconst cl--typedef-regexp
|
|
(concat "(" (regexp-opt '("defclass" "defstruct" "cl-defstruct"
|
|
"cl-deftype" "deftype"))
|
|
"[ \t\r\n]+%s[ \t\r\n]+"))
|
|
(with-eval-after-load 'find-func
|
|
(defvar find-function-regexp-alist)
|
|
(add-to-list 'find-function-regexp-alist
|
|
`(define-type . cl--typedef-regexp)))
|
|
|
|
(define-button-type 'cl-help-type
|
|
:supertype 'help-function-def
|
|
'help-function #'cl-describe-type
|
|
'help-echo (purecopy "mouse-2, RET: describe this type"))
|
|
|
|
(define-button-type 'cl-type-definition
|
|
:supertype 'help-function-def
|
|
'help-echo (purecopy "mouse-2, RET: find type definition"))
|
|
|
|
(declare-function help-fns-short-filename "help-fns" (filename))
|
|
|
|
;;;###autoload
|
|
(defun cl-find-class (type) (cl--find-class type))
|
|
|
|
;;;###autoload
|
|
(defun cl-describe-type (type)
|
|
"Display the documentation for type TYPE (a symbol)."
|
|
(interactive
|
|
(let ((str (completing-read "Describe type: " obarray #'cl-find-class t)))
|
|
(if (<= (length str) 0)
|
|
(user-error "Abort!")
|
|
(list (intern str)))))
|
|
(help-setup-xref (list #'cl-describe-type type)
|
|
(called-interactively-p 'interactive))
|
|
(save-excursion
|
|
(with-help-window (help-buffer)
|
|
(with-current-buffer standard-output
|
|
(let ((class (cl-find-class type)))
|
|
(if class
|
|
(cl--describe-class type class)
|
|
;; FIXME: Describe other types (the built-in ones, or those from
|
|
;; cl-deftype).
|
|
(user-error "Unknown type %S" type))))
|
|
(with-current-buffer standard-output
|
|
;; Return the text we displayed.
|
|
(buffer-string)))))
|
|
|
|
(defun cl--describe-class (type &optional class)
|
|
(unless class (setq class (cl--find-class type)))
|
|
(let ((location (find-lisp-object-file-name type 'define-type))
|
|
;; FIXME: Add a `cl-class-of' or `cl-typeof' or somesuch.
|
|
(metatype (cl--class-name (symbol-value (aref class 0)))))
|
|
(insert (symbol-name type)
|
|
(substitute-command-keys " is a type (of kind `"))
|
|
(help-insert-xref-button (symbol-name metatype)
|
|
'cl-help-type metatype)
|
|
(insert (substitute-command-keys "')"))
|
|
(when location
|
|
(insert (substitute-command-keys " in `"))
|
|
(help-insert-xref-button
|
|
(help-fns-short-filename location)
|
|
'cl-type-definition type location 'define-type)
|
|
(insert (substitute-command-keys "'")))
|
|
(insert ".\n")
|
|
|
|
;; Parents.
|
|
(let ((pl (cl--class-parents class))
|
|
cur)
|
|
(when pl
|
|
(insert " Inherits from ")
|
|
(while (setq cur (pop pl))
|
|
(setq cur (cl--class-name cur))
|
|
(insert (substitute-command-keys "`"))
|
|
(help-insert-xref-button (symbol-name cur)
|
|
'cl-help-type cur)
|
|
(insert (substitute-command-keys (if pl "', " "'"))))
|
|
(insert ".\n")))
|
|
|
|
;; Children, if available. ¡For EIEIO!
|
|
(let ((ch (condition-case nil
|
|
(cl-struct-slot-value metatype 'children class)
|
|
(cl-struct-unknown-slot nil)))
|
|
cur)
|
|
(when ch
|
|
(insert " Children ")
|
|
(while (setq cur (pop ch))
|
|
(insert (substitute-command-keys "`"))
|
|
(help-insert-xref-button (symbol-name cur)
|
|
'cl-help-type cur)
|
|
(insert (substitute-command-keys (if ch "', " "'"))))
|
|
(insert ".\n")))
|
|
|
|
;; Type's documentation.
|
|
(let ((doc (cl--class-docstring class)))
|
|
(when doc
|
|
(insert "\n" doc "\n\n")))
|
|
|
|
;; Describe all the slots in this class.
|
|
(cl--describe-class-slots class)
|
|
|
|
;; Describe all the methods specific to this class.
|
|
(let ((generics (cl--generic-all-functions type)))
|
|
(when generics
|
|
(insert (propertize "Specialized Methods:\n\n" 'face 'bold))
|
|
(dolist (generic generics)
|
|
(insert (substitute-command-keys "`"))
|
|
(help-insert-xref-button (symbol-name generic)
|
|
'help-function generic)
|
|
(insert (substitute-command-keys "'"))
|
|
(pcase-dolist (`(,qualifiers ,args ,doc)
|
|
(cl--generic-method-documentation generic type))
|
|
(insert (format " %s%S\n" qualifiers args)
|
|
(or doc "")))
|
|
(insert "\n\n"))))))
|
|
|
|
(defun cl--describe-class-slot (slot)
|
|
(insert
|
|
(concat
|
|
(propertize "Slot: " 'face 'bold)
|
|
(prin1-to-string (cl--slot-descriptor-name slot))
|
|
(unless (eq (cl--slot-descriptor-type slot) t)
|
|
(concat " type = "
|
|
(prin1-to-string (cl--slot-descriptor-type slot))))
|
|
;; FIXME: The default init form is treated differently for structs and for
|
|
;; eieio objects: for structs, the default is nil, for eieio-objects
|
|
;; it's a special "unbound" value.
|
|
(unless nil ;; (eq (cl--slot-descriptor-initform slot) eieio-unbound)
|
|
(concat " default = "
|
|
(prin1-to-string (cl--slot-descriptor-initform slot))))
|
|
(when (alist-get :printer (cl--slot-descriptor-props slot))
|
|
(concat " printer = "
|
|
(prin1-to-string
|
|
(alist-get :printer (cl--slot-descriptor-props slot)))))
|
|
(when (alist-get :documentation (cl--slot-descriptor-props slot))
|
|
(concat "\n "
|
|
(substitute-command-keys
|
|
(alist-get :documentation (cl--slot-descriptor-props slot)))
|
|
"\n")))
|
|
"\n"))
|
|
|
|
(defun cl--describe-class-slots (class)
|
|
"Print help description for the slots in CLASS.
|
|
Outputs to the current buffer."
|
|
(let* ((slots (cl--class-slots class))
|
|
;; FIXME: Add a `cl-class-of' or `cl-typeof' or somesuch.
|
|
(metatype (cl--class-name (symbol-value (aref class 0))))
|
|
;; ¡For EIEIO!
|
|
(cslots (condition-case nil
|
|
(cl-struct-slot-value metatype 'class-slots class)
|
|
(cl-struct-unknown-slot nil))))
|
|
(insert (propertize "Instance Allocated Slots:\n\n"
|
|
'face 'bold))
|
|
(mapc #'cl--describe-class-slot slots)
|
|
(when (> (length cslots) 0)
|
|
(insert (propertize "\nClass Allocated Slots:\n\n" 'face 'bold))
|
|
(mapc #'cl--describe-class-slot cslots))))
|
|
|
|
|
|
(run-hooks 'cl-extra-load-hook)
|
|
|
|
;; Local variables:
|
|
;; byte-compile-dynamic: t
|
|
;; generated-autoload-file: "cl-loaddefs.el"
|
|
;; End:
|
|
|
|
(provide 'cl-extra)
|
|
;;; cl-extra.el ends here
|