diff options
Diffstat (limited to 'lisp/help-fns.el')
-rw-r--r-- | lisp/help-fns.el | 484 |
1 files changed, 291 insertions, 193 deletions
diff --git a/lisp/help-fns.el b/lisp/help-fns.el index 8684a853af2..0b5c547d6b0 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el @@ -40,7 +40,21 @@ "List of functions to run in help buffer in `describe-function'. Those functions will be run after the header line and argument list was inserted, and before the documentation will be inserted. -The functions will receive the function name as argument.") +The functions will receive the function name as argument. +They can assume that a newline was output just before they were called, +and they should terminate any of their own output with a newline. +By convention they should indent their output by 2 spaces.") + +(defvar help-fns-describe-variable-functions nil + "List of functions to run in help buffer in `describe-variable'. +Those functions will be run after the header line and value was inserted, +and before the documentation will be inserted. +The functions will receive the variable name as argument. +They can assume that a newline was output just before they were called, +and they should terminate any of their own output with a newline. +By convention they should indent their output by 2 spaces. +Current buffer is the buffer in which we queried the variable, +and the output should go to `standard-output'.") ;; Functions @@ -68,12 +82,15 @@ The functions will receive the function name as argument.") (defun help--loaded-p (file) "Try and figure out if FILE has already been loaded." + ;; FIXME: this regexp business is not good enough: for file + ;; `toto', it will say `toto' is loaded when in reality it was + ;; just cedet/semantic/toto that has been loaded. (or (let ((feature (intern-soft file))) (and feature (featurep feature))) (let* ((re (load-history-regexp file)) (done nil)) (dolist (x load-history) - (and (car x) (string-match-p re (car x)) (setq done t))) + (and (stringp (car x)) (string-match-p re (car x)) (setq done t))) done))) (defun help--load-prefixes (prefixes) @@ -83,11 +100,9 @@ The functions will receive the function name as argument.") (dolist (file files) ;; FIXME: Should we scan help-definition-prefixes to remove ;; other prefixes of the same file? - ;; FIXME: this regexp business is not good enough: for file - ;; `toto', it will say `toto' is loaded when in reality it was - ;; just cedet/semantic/toto that has been loaded. (unless (help--loaded-p file) - (load file 'noerror 'nomessage))))) + (with-demoted-errors "while loading: %S" + (load file 'noerror 'nomessage)))))) (defcustom help-enable-completion-auto-load t "Whether completion for Help commands can perform autoloading. @@ -181,7 +196,8 @@ When called from lisp, FUNCTION may also be a function object." ;;;###autoload (defun help-C-file-name (subr-or-var kind) "Return the name of the C file where SUBR-OR-VAR is defined. -KIND should be `var' for a variable or `subr' for a subroutine." +KIND should be `var' for a variable or `subr' for a subroutine. +If we can't find the file name, nil is returned." (let ((docbuf (get-buffer-create " *DOC*")) (name (if (eq 'var kind) (concat "V" (symbol-name subr-or-var)) @@ -193,19 +209,24 @@ KIND should be `var' for a variable or `subr' for a subroutine." (expand-file-name internal-doc-file-name doc-directory))) (let ((file (catch 'loop (while t - (let ((pnt (search-forward (concat "" name "\n")))) - (re-search-backward "S\\(.*\\)") - (let ((file (match-string 1))) - (if (member file build-files) - (throw 'loop file) - (goto-char pnt)))))))) - (if (string-match "^ns.*\\(\\.o\\|obj\\)\\'" file) - (setq file (replace-match ".m" t t file 1)) - (if (string-match "\\.\\(o\\|obj\\)\\'" file) - (setq file (replace-match ".c" t t file)))) - (if (string-match "\\.\\(c\\|m\\)\\'" file) - (concat "src/" file) - file))))) + (let ((pnt (search-forward (concat "\^_" name "\n") + nil t))) + (if (not pnt) + (throw 'loop nil) + (re-search-backward "\^_S\\(.*\\)") + (let ((file (match-string 1))) + (if (member file build-files) + (throw 'loop file) + (goto-char pnt))))))))) + (if (not file) + nil + (if (string-match "^ns.*\\(\\.o\\|obj\\)\\'" file) + (setq file (replace-match ".m" t t file 1)) + (if (string-match "\\.\\(o\\|obj\\)\\'" file) + (setq file (replace-match ".c" t t file)))) + (if (string-match "\\.\\(c\\|m\\)\\'" file) + (concat "src/" file) + file)))))) (defcustom help-downcase-arguments nil "If non-nil, argument names in *Help* buffers are downcased." @@ -423,7 +444,7 @@ suitable file is found, return nil." (defun help-fns--compiler-macro (function) (let ((handler (function-get function 'compiler-macro))) (when handler - (insert "\nThis function has a compiler macro") + (insert " This function has a compiler macro") (if (symbolp handler) (progn (insert (format-message " `%s'" handler)) @@ -497,7 +518,7 @@ suitable file is found, return nil." (get function 'derived-mode-parent)))) (when parent-mode - (insert (substitute-command-keys "\nParent mode: `")) + (insert (substitute-command-keys " Parent mode: `")) (let ((beg (point))) (insert (format "%s" parent-mode)) (make-text-button beg (point) @@ -511,15 +532,15 @@ suitable file is found, return nil." (get function 'byte-obsolete-info))) (use (car obsolete))) (when obsolete - (insert "\nThis " + (insert " This " (if (eq (car-safe (symbol-function function)) 'macro) "macro" "function") " is obsolete") (when (nth 2 obsolete) (insert (format " since %s" (nth 2 obsolete)))) - (insert (cond ((stringp use) (concat ";\n" use)) - (use (format-message ";\nuse `%s' instead." use)) + (insert (cond ((stringp use) (concat ";\n " use)) + (use (format-message ";\n use `%s' instead." use)) (t ".")) "\n")))) @@ -532,7 +553,7 @@ FILE is the file where FUNCTION was probably defined." (target (cons t function)) found) (while (and load-hist (not found)) - (and (caar load-hist) + (and (stringp (caar load-hist)) (equal (file-name-sans-extension (caar load-hist)) file) (setq found (member target (cdar load-hist)))) (setq load-hist (cdr load-hist))) @@ -549,17 +570,71 @@ FILE is the file where FUNCTION was probably defined." (memq function byte-compile-interactive-only-functions))))) (when interactive-only - (insert "\nThis function is for interactive use only" + (insert " This function is for interactive use only" ;; Cf byte-compile-form. (cond ((stringp interactive-only) - (format ";\nin Lisp code %s" interactive-only)) + (format ";\n in Lisp code %s" interactive-only)) ((and (symbolp 'interactive-only) (not (eq interactive-only t))) - (format-message ";\nin Lisp code use `%s' instead." + (format-message ";\n in Lisp code use `%s' instead." interactive-only)) (t ".")) "\n"))))) +(add-hook 'help-fns-describe-function-functions #'help-fns--side-effects) +(defun help-fns--side-effects (function) + (when (and (symbolp function) + (or (function-get function 'pure) + (function-get function 'side-effect-free))) + (insert " This function does not change global state, " + "including the match data.\n"))) + +(defun help-fns--first-release (symbol) + "Return the likely first release that defined SYMBOL, or nil." + ;; Code below relies on the etc/NEWS* files. + ;; FIXME: Maybe we should also use the */ChangeLog* files when available. + ;; FIXME: Maybe we should also look for announcements of the addition + ;; of the *packages* in which the function is defined. + (let* ((name (symbol-name symbol)) + (re (concat "\\_<" (regexp-quote name) "\\_>")) + (news (directory-files data-directory t "\\`NEWS.[1-9]")) + (place nil) + (first nil)) + (with-temp-buffer + (dolist (f news) + (erase-buffer) + (insert-file-contents f) + (goto-char (point-min)) + (search-forward "\n*") + (while (re-search-forward re nil t) + (let ((pos (match-beginning 0))) + (save-excursion + ;; Almost all entries are of the form "* ... in Emacs NN.MM." + ;; but there are also a few in the form "* Emacs NN.MM is a bug + ;; fix release ...". + (if (not (re-search-backward "^\\*.* Emacs \\([0-9.]+[0-9]\\)" + nil t)) + (message "Ref found in non-versioned section in %S" + (file-name-nondirectory f)) + (let ((version (match-string 1))) + (when (or (null first) (version< version first)) + (setq place (list f pos)) + (setq first version))))))))) + (when first + (make-text-button first nil 'type 'help-news 'help-args place)) + first)) + +(add-hook 'help-fns-describe-function-functions + #'help-fns--mention-first-release) +(add-hook 'help-fns-describe-variable-functions + #'help-fns--mention-first-release) +(defun help-fns--mention-first-release (object) + (let ((first (if (symbolp object) (help-fns--first-release object)))) + (when first + (with-current-buffer standard-output + (insert (format " Probably introduced at or before Emacs version %s.\n" + first)))))) + (defun help-fns-short-filename (filename) (let* ((abbrev (abbreviate-file-name filename)) (short abbrev)) @@ -622,9 +697,9 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-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 ") + (concat + "an autoloaded " (if (commandp def) + "interactive ")) (if (commandp def) "an interactive " "a ")))) ;; Print what kind of function-like object FUNCTION is. @@ -638,14 +713,16 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)." (aliased (format-message "an alias for `%s'" real-def)) ((subrp def) - (if (eq 'unevalled (cdr (subr-arity def))) - (concat beg "special form") - (concat beg "built-in function"))) + (concat beg (if (eq 'unevalled (cdr (subr-arity def))) + "special form" + "built-in function"))) ((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")))) + (format "an autoloaded %s" + (cond + ((commandp def) "interactive Lisp function") + ((eq (nth 4 def) 'keymap) "keymap") + ((nth 4 def) "Lisp macro") + (t "Lisp function")))) ((or (eq (car-safe def) 'macro) ;; For advised macros, def is a lambda ;; expression or a byte-code-function-p, so we @@ -654,6 +731,8 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)." (concat beg "Lisp macro")) ((byte-code-function-p def) (concat beg "compiled Lisp function")) + ((module-function-p def) + (concat beg "module function")) ((eq (car-safe def) 'lambda) (concat beg "Lisp function")) ((eq (car-safe def) 'closure) @@ -694,6 +773,10 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)." (help-xref-button 1 'help-function-def function file-name)))) (princ ".")))) +(defun help-fns--ensure-empty-line () + (unless (eolp) (insert "\n")) + (unless (eq ?\n (char-before (1- (point)))) (insert "\n"))) + ;;;###autoload (defun describe-function-1 (function) (let ((pt1 (with-current-buffer (help-buffer) (point)))) @@ -731,8 +814,10 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)." real-function key-bindings-buffer) ;; E.g. an alias for a not yet defined function. ((invalid-function void-function) doc-raw)))) + (help-fns--ensure-empty-line) (run-hook-with-args 'help-fns-describe-function-functions function) - (insert "\n" (or doc "Not documented."))) + (help-fns--ensure-empty-line) + (insert (or doc "Not documented."))) ;; Avoid asking the user annoying questions if she decides ;; to save the help buffer, when her locale's codeset ;; isn't UTF-8. @@ -775,14 +860,15 @@ If ANY-SYMBOL is non-nil, don't insist the symbol be bound." (and (or any-symbol (boundp sym)) sym))))) 0))) -(defun describe-variable-custom-version-info (variable) +(defun describe-variable-custom-version-info (variable &optional type) (let ((custom-version (get variable 'custom-version)) (cpv (get variable 'custom-package-version)) + (type (or type "variable")) (output nil)) (if custom-version (setq output - (format "This variable was introduced, or its default value was changed, in\nversion %s of Emacs.\n" - custom-version)) + (format "This %s was introduced, or its default value was changed, in\nversion %s of Emacs.\n" + type custom-version)) (when cpv (let* ((package (car-safe cpv)) (version (if (listp (cdr-safe cpv)) @@ -792,11 +878,11 @@ If ANY-SYMBOL is non-nil, don't insist the symbol be bound." (emacsv (cdr (assoc version pkg-versions)))) (if (and package version) (setq output - (format (concat "This variable was introduced, or its default value was changed, in\nversion %s of the %s package" + (format (concat "This %s was introduced, or its default value was changed, in\nversion %s of the %s package" (if emacsv (format " that is part of Emacs %s" emacsv)) ".\n") - version package)))))) + type version package)))))) output)) ;;;###autoload @@ -835,7 +921,6 @@ it is displayed along with the global value." (message "You did not specify a 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. @@ -851,26 +936,26 @@ it is displayed along with the global value." (prin1 variable) (setq file-name (find-lisp-object-file-name variable 'defvar)) - (if file-name - (progn - (princ (format-message - " is a variable defined in `%s'.\n" - (if (eq file-name 'C-source) - "C source code" - (file-name-nondirectory file-name)))) - (with-current-buffer standard-output - (save-excursion - (re-search-backward (substitute-command-keys - "`\\([^`']+\\)'") - 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 (substitute-command-keys "'s "))))) + (princ (if file-name + (progn + (princ (format-message + " is a variable defined in `%s'.\n" + (if (eq file-name 'C-source) + "C source code" + (file-name-nondirectory file-name)))) + (with-current-buffer standard-output + (save-excursion + (re-search-backward (substitute-command-keys + "`\\([^`']+\\)'") + nil t) + (help-xref-button 1 'help-variable-def + variable file-name))) + (if valvoid + "It is void as a variable." + "Its ")) + (if valvoid + " is void as a variable." + (substitute-command-keys "'s "))))) (unless valvoid (with-current-buffer standard-output (setq val-start-pos (point)) @@ -899,7 +984,7 @@ it is displayed along with the global value." (let* ((sv (get variable 'standard-value)) (origval (and (consp sv) (condition-case nil - (eval (car sv)) + (eval (car sv) t) (error :help-eval-error)))) from) (when (and (consp sv) @@ -974,132 +1059,17 @@ it is displayed along with the global value." (let* ((alias (condition-case nil (indirect-variable variable) (error variable))) - (obsolete (get variable 'byte-obsolete-variable)) - (watchpoints (get-variable-watchers variable)) - (use (car obsolete)) - (safe-var (get variable 'safe-local-variable)) (doc (or (documentation-property variable 'variable-documentation) (documentation-property - alias 'variable-documentation))) - (extra-line nil)) + alias 'variable-documentation)))) - ;; Mention if it's a local variable. - (cond - ((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 ") - (if permanent-local - (princ "permanently ")) - (princ "buffer-local when set.\n")) - ((not permanent-local)) - ((bufferp locus) - (setq extra-line t) - (princ - (substitute-command-keys - " This variable's buffer-local value is permanent.\n"))) - (t - (setq extra-line t) - (princ (substitute-command-keys - " This variable's value is permanent \ -if it is given a local binding.\n")))) - - ;; Mention if it's an alias. - (unless (eq alias variable) - (setq extra-line t) - (princ (format-message - " This variable is an alias for `%s'.\n" - alias))) - - (when obsolete - (setq extra-line t) - (princ " This variable is obsolete") - (if (nth 2 obsolete) - (princ (format " since %s" (nth 2 obsolete)))) - (princ (cond ((stringp use) (concat ";\n " use)) - (use (format-message ";\n use `%s' instead." - (car obsolete))) - (t "."))) - (terpri)) - - (when watchpoints - (setq extra-line t) - (princ " Calls these functions when changed: ") - (princ watchpoints) - (terpri)) - - (when (member (cons variable val) - (with-current-buffer buffer - file-local-variables-alist)) - (setq extra-line t) - (if (member (cons variable val) - (with-current-buffer buffer - dir-local-variables-alist)) - (let ((file (and (buffer-file-name buffer) - (not (file-remote-p - (buffer-file-name buffer))) - (dir-locals-find-file - (buffer-file-name buffer)))) - (is-directory nil)) - (princ (substitute-command-keys - " This variable's value is directory-local")) - (when (consp file) ; result from cache - ;; If the cache element has an mtime, we - ;; assume it came from a file. - (if (nth 2 file) - ;; (car file) is a directory. - (setq file (dir-locals--all-files (car file))) - ;; Otherwise, assume it was set directly. - (setq file (car file) - is-directory t))) - (if (null file) - (princ ".\n") - (princ ", set ") - (princ (substitute-command-keys - (cond - (is-directory "for the directory\n `") - ;; Many files matched. - ((and (consp file) (cdr file)) - (setq file (file-name-directory (car file))) - (format "by one of the\n %s files in the directory\n `" - dir-locals-file)) - (t (setq file (car file)) - "by the file\n `")))) - (with-current-buffer standard-output - (insert-text-button - file 'type 'help-dir-local-var-def - 'help-args (list variable file))) - (princ (substitute-command-keys "'.\n")))) - (princ (substitute-command-keys - " This variable's value is file-local.\n")))) - - (when (memq variable ignored-local-variables) - (setq extra-line t) - (princ " This variable is ignored 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 may be risky if used as a \ -file-local variable.\n") - (when (assq variable safe-local-variable-values) - (princ (substitute-command-keys - " 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 a byte-compiled expression.\n" - (format-message "`%s'.\n" safe-var)))) - - (if extra-line (terpri)) + (with-current-buffer buffer + (run-hook-with-args 'help-fns-describe-variable-functions + variable)) + + (with-current-buffer standard-output + (help-fns--ensure-empty-line)) (princ "Documentation:\n") (with-current-buffer standard-output (insert (or doc "Not documented as a variable.")))) @@ -1126,6 +1096,134 @@ file-local variable.\n") ;; Return the text we displayed. (buffer-string)))))))) +(add-hook 'help-fns-describe-variable-functions #'help-fns--var-safe-local) +(defun help-fns--var-safe-local (variable) + (let ((safe-var (get variable 'safe-local-variable))) + (when safe-var + (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-message "`%s'.\n" safe-var)))))) + +(add-hook 'help-fns-describe-variable-functions #'help-fns--var-risky) +(defun help-fns--var-risky (variable) + ;; Can be both risky and safe, eg auto-fill-function. + (when (risky-local-variable-p variable) + (princ " This variable may be risky if used as a \ +file-local variable.\n") + (when (assq variable safe-local-variable-values) + (princ (substitute-command-keys + " However, you have added it to \ +`safe-local-variable-values'.\n"))))) + +(add-hook 'help-fns-describe-variable-functions #'help-fns--var-ignored-local) +(defun help-fns--var-ignored-local (variable) + (when (memq variable ignored-local-variables) + (princ " This variable is ignored as a file-local \ +variable.\n"))) + +(add-hook 'help-fns-describe-variable-functions #'help-fns--var-file-local) +(defun help-fns--var-file-local (variable) + (when (boundp variable) + (let ((val (symbol-value variable))) + (when (member (cons variable val) + file-local-variables-alist) + (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))) + (is-directory nil)) + (princ (substitute-command-keys + " This variable's value is directory-local")) + (when (consp file) ; result from cache + ;; If the cache element has an mtime, we + ;; assume it came from a file. + (if (nth 2 file) + ;; (car file) is a directory. + (setq file (dir-locals--all-files (car file))) + ;; Otherwise, assume it was set directly. + (setq file (car file) + is-directory t))) + (if (null file) + (princ ".\n") + (princ ", set ") + (princ (substitute-command-keys + (cond + (is-directory "for the directory\n `") + ;; Many files matched. + ((and (consp file) (cdr file)) + (setq file (file-name-directory (car file))) + (format "by one of the\n %s files in the directory\n `" + dir-locals-file)) + (t (setq file (car file)) + "by the file\n `")))) + (with-current-buffer standard-output + (insert-text-button + file 'type 'help-dir-local-var-def + 'help-args (list variable file))) + (princ (substitute-command-keys "'.\n")))) + (princ (substitute-command-keys + " This variable's value is file-local.\n"))))))) + +(add-hook 'help-fns-describe-variable-functions #'help-fns--var-watchpoints) +(defun help-fns--var-watchpoints (variable) + (let ((watchpoints (get-variable-watchers variable))) + (when watchpoints + (princ " Calls these functions when changed: ") + ;; FIXME: Turn function names into hyperlinks. + (princ watchpoints) + (terpri)))) + +(add-hook 'help-fns-describe-variable-functions #'help-fns--var-obsolete) +(defun help-fns--var-obsolete (variable) + (let* ((obsolete (get variable 'byte-obsolete-variable)) + (use (car obsolete))) + (when obsolete + (princ " This variable is obsolete") + (if (nth 2 obsolete) + (princ (format " since %s" (nth 2 obsolete)))) + (princ (cond ((stringp use) (concat ";\n " use)) + (use (format-message ";\n use `%s' instead." + (car obsolete))) + (t "."))) + (terpri)))) + +(add-hook 'help-fns-describe-variable-functions #'help-fns--var-alias) +(defun help-fns--var-alias (variable) + ;; Mention if it's an alias. + (let ((alias (condition-case nil + (indirect-variable variable) + (error variable)))) + (unless (eq alias variable) + (princ (format-message + " This variable is an alias for `%s'.\n" + alias))))) + +(add-hook 'help-fns-describe-variable-functions #'help-fns--var-bufferlocal) +(defun help-fns--var-bufferlocal (variable) + (let ((permanent-local (get variable 'permanent-local)) + (locus (variable-binding-locus variable))) + ;; Mention if it's a local variable. + (cond + ((and (local-variable-if-set-p variable) + (or (not (local-variable-p variable)) + (with-temp-buffer + (local-variable-if-set-p variable)))) + (princ " Automatically becomes ") + (if permanent-local + (princ "permanently ")) + (princ "buffer-local when set.\n")) + ((not permanent-local)) + ((bufferp locus) + (princ + (substitute-command-keys + " This variable's buffer-local value is permanent.\n"))) + (t + (princ (substitute-command-keys + " This variable's value is permanent \ +if it is given a local binding.\n")))))) (defvar help-xref-stack-item) @@ -1147,7 +1245,7 @@ current buffer and the selected frame, respectively." (format "Describe symbol (default %s): " v-or-f) "Describe symbol: ") - obarray + #'help--symbol-completion-table (lambda (vv) (cl-some (lambda (x) (funcall (nth 1 x) vv)) describe-symbol-backends)) @@ -1299,7 +1397,7 @@ BUFFER should be a buffer or a buffer name." ".AU Richard M. Stallman\n") (insert-file-contents file) (let (notfirst) - (while (search-forward "" nil 'move) + (while (search-forward "\^_" nil 'move) (if (= (following-char) ?S) (delete-region (1- (point)) (line-end-position)) (delete-char -1) @@ -1332,12 +1430,12 @@ BUFFER should be a buffer or a buffer name." (insert "@") (forward-char 1)) (goto-char (point-min)) - (while (search-forward "" nil t) + (while (search-forward "\^_" nil t) (when (/= (following-char) ?S) (setq type (char-after) name (buffer-substring (1+ (point)) (line-end-position)) doc (buffer-substring (line-beginning-position 2) - (if (search-forward "" nil 'move) + (if (search-forward "\^_" nil 'move) (1- (point)) (point))) alist (cons (list name type doc) alist)) |