Mercurial > emacs
comparison lisp/help-fns.el @ 97916:904041a08605
(describe-simplify-lib-file-name, find-source-lisp-file): Removed.
(find-lisp-object-file-name): New function giving preference to
files found via load-path instead of loaddefs.el.
(describe-function-1): Use new function instead of the removed
ones. (Bugs #587, #669, #690)
author | Martin Rudalics <rudalics@gmx.at> |
---|---|
date | Mon, 01 Sep 2008 08:04:40 +0000 |
parents | 52bbade97925 |
children | 6e27d74c7d56 |
comparison
equal
deleted
inserted
replaced
97915:b533413d3d47 | 97916:904041a08605 |
---|---|
215 ;; Highlight arguments in the DOC string | 215 ;; Highlight arguments in the DOC string |
216 (setq doc (and doc (help-do-arg-highlight doc args)))))) | 216 (setq doc (and doc (help-do-arg-highlight doc args)))))) |
217 ;; Return value is like the one from help-split-fundoc, but highlighted | 217 ;; Return value is like the one from help-split-fundoc, but highlighted |
218 (cons usage doc)) | 218 (cons usage doc)) |
219 | 219 |
220 ;; The following function was compiled from the former functions | |
221 ;; `describe-simplify-lib-file-name' and `find-source-lisp-file' with | |
222 ;; some excerpts from `describe-function-1' and `describe-variable'. | |
223 ;; The only additional twists provided are (1) locate the defining file | |
224 ;; for autoloaded functions, and (2) give preference to files in the | |
225 ;; "install directory" (directories found via `load-path') rather than | |
226 ;; to files in the "compile directory" (directories found by searching | |
227 ;; the loaddefs.el file). We autoload it because it's also used by | |
228 ;; `describe-face' (instead of `describe-simplify-lib-file-name'). | |
229 | |
220 ;;;###autoload | 230 ;;;###autoload |
221 (defun describe-simplify-lib-file-name (file) | 231 (defun find-lisp-object-file-name (object type) |
222 "Simplify a library name FILE to a relative name, and make it a source file." | 232 "Guess the file that defined the Lisp object OBJECT, of type TYPE. |
223 (if file | 233 OBJECT should be a symbol associated with a function, variable, or face; |
224 ;; Try converting the absolute file name to a library name. | 234 alternatively, it can be a function definition. |
225 (let ((libname (file-name-nondirectory file))) | 235 If TYPE is `variable', search for a variable definition. |
226 ;; Now convert that back to a file name and see if we get | 236 If TYPE is `face', search for a face definition. |
227 ;; the original one. If so, they are equivalent. | 237 If TYPE is the value returned by `symbol-function' for a function symbol, |
228 (if (equal file (locate-file libname load-path '(""))) | 238 search for a function definition. |
229 (if (string-match "[.]elc\\'" libname) | 239 |
230 (substring libname 0 -1) | 240 The return value is the absolute name of a readable file where OBJECT is |
231 libname) | 241 defined. If several such files exist, preference is given to a file |
232 file)))) | 242 found via `load-path'. The return value can also be `C-source', which |
233 | 243 means that OBJECT is a function or variable defined in C. If no |
234 (defun find-source-lisp-file (file-name) | 244 suitable file is found, return nil." |
235 (let* ((elc-file (locate-file (concat file-name | 245 (let* ((autoloaded (eq (car-safe type) 'autoload)) |
236 (if (string-match "\\.el" file-name) | 246 (file-name (or (and autoloaded (nth 1 type)) |
237 "c" | 247 (symbol-file |
238 ".elc")) | 248 object (if (memq type (list 'defvar 'defface)) |
239 load-path)) | 249 type |
240 (str (if (and elc-file (file-readable-p elc-file)) | 250 'defun))))) |
241 (with-temp-buffer | 251 (cond |
242 (insert-file-contents-literally elc-file nil 0 256) | 252 (autoloaded |
243 (buffer-string)))) | 253 ;; An autoloaded function: Locate the file since `symbol-function' |
244 (src-file (and str | 254 ;; has only returned a bare string here. |
245 (string-match ";;; from file \\(.*\\.el\\)" str) | 255 (setq file-name |
246 (match-string 1 str)))) | 256 (locate-file file-name load-path '(".el" ".elc") 'readable))) |
247 (if (and src-file (file-readable-p src-file)) | 257 ((and (stringp file-name) |
248 src-file | 258 (string-match "[.]*loaddefs.el\\'" file-name)) |
249 file-name))) | 259 ;; An autoloaded variable or face. Visit loaddefs.el in a buffer |
260 ;; and try to extract the defining file. The following form is | |
261 ;; from `describe-function-1' and `describe-variable'. | |
262 (let ((location | |
263 (condition-case nil | |
264 (find-function-search-for-symbol object nil file-name) | |
265 (error nil)))) | |
266 (when location | |
267 (with-current-buffer (car location) | |
268 (goto-char (cdr location)) | |
269 (when (re-search-backward | |
270 "^;;; Generated autoloads from \\(.*\\)" nil t) | |
271 (setq file-name | |
272 (locate-file | |
273 (match-string-no-properties 1) | |
274 load-path nil 'readable)))))))) | |
275 | |
276 (cond | |
277 ((and (not file-name) (subrp type)) | |
278 ;; A built-in function. The form is from `describe-function-1'. | |
279 (if (get-buffer " *DOC*") | |
280 (help-C-file-name type 'subr) | |
281 'C-source)) | |
282 ((and (not file-name) (symbolp object) | |
283 (integerp (get object 'variable-documentation))) | |
284 ;; A variable defined in C. The form is from `describe-variable'. | |
285 (if (get-buffer " *DOC*") | |
286 (help-C-file-name object 'var) | |
287 'C-source)) | |
288 ((not (stringp file-name)) | |
289 ;; If we don't have a file-name string by now, we lost. | |
290 nil) | |
291 ((let ((lib-name | |
292 (if (string-match "[.]elc\\'" file-name) | |
293 (substring-no-properties file-name 0 -1) | |
294 file-name))) | |
295 ;; When the Elisp source file can be found in the install | |
296 ;; directory return the name of that file - `file-name' should | |
297 ;; have become an absolute file name ny now. | |
298 (and (file-readable-p lib-name) lib-name))) | |
299 ((let* ((lib-name (file-name-nondirectory file-name)) | |
300 ;; The next form is from `describe-simplify-lib-file-name'. | |
301 (file-name | |
302 ;; Try converting the absolute file name to a library | |
303 ;; name, convert that back to a file name and see if we | |
304 ;; get the original one. If so, they are equivalent. | |
305 (if (equal file-name (locate-file lib-name load-path '(""))) | |
306 (if (string-match "[.]elc\\'" lib-name) | |
307 (substring-no-properties lib-name 0 -1) | |
308 lib-name) | |
309 file-name)) | |
310 ;; The next three forms are from `find-source-lisp-file'. | |
311 (elc-file (locate-file | |
312 (concat file-name | |
313 (if (string-match "\\.el\\'" file-name) | |
314 "c" | |
315 ".elc")) | |
316 load-path nil 'readable)) | |
317 (str (when elc-file | |
318 (with-temp-buffer | |
319 (insert-file-contents-literally elc-file nil 0 256) | |
320 (buffer-string)))) | |
321 (src-file (and str | |
322 (string-match ";;; from file \\(.*\\.el\\)" str) | |
323 (match-string 1 str)))) | |
324 (and src-file (file-readable-p src-file) src-file)))))) | |
250 | 325 |
251 (declare-function ad-get-advice-info "advice" (function)) | 326 (declare-function ad-get-advice-info "advice" (function)) |
252 | 327 |
253 ;;;###autoload | 328 ;;;###autoload |
254 (defun describe-function-1 (function) | 329 (defun describe-function-1 (function) |
256 (ad-get-advice-info function))) | 331 (ad-get-advice-info function))) |
257 ;; If the function is advised, use the symbol that has the | 332 ;; If the function is advised, use the symbol that has the |
258 ;; real definition, if that symbol is already set up. | 333 ;; real definition, if that symbol is already set up. |
259 (real-function | 334 (real-function |
260 (or (and advised | 335 (or (and advised |
261 (cdr (assq 'origname advised)) | 336 (let ((origname (cdr (assq 'origname advised)))) |
262 (fboundp (cdr (assq 'origname advised))) | 337 (and (fboundp origname) origname))) |
263 (cdr (assq 'origname advised))) | |
264 function)) | 338 function)) |
265 ;; Get the real definition. | 339 ;; Get the real definition. |
266 (def (if (symbolp real-function) | 340 (def (if (symbolp real-function) |
267 (symbol-function real-function) | 341 (symbol-function real-function) |
268 function)) | 342 function)) |
269 file-name string | 343 file-name string |
270 (beg (if (commandp def) "an interactive " "a ")) | 344 (beg (if (commandp def) "an interactive " "a ")) |
271 (pt1 (with-current-buffer (help-buffer) (point))) | 345 (pt1 (with-current-buffer (help-buffer) (point))) |
272 errtype) | 346 errtype) |
273 (setq string | 347 (setq string |
274 (cond ((or (stringp def) | 348 (cond ((or (stringp def) |
275 (vectorp def)) | 349 (vectorp def)) |
276 "a keyboard macro") | 350 "a keyboard macro") |
290 ((eq (car-safe def) 'lambda) | 364 ((eq (car-safe def) 'lambda) |
291 (concat beg "Lisp function")) | 365 (concat beg "Lisp function")) |
292 ((eq (car-safe def) 'macro) | 366 ((eq (car-safe def) 'macro) |
293 "a Lisp macro") | 367 "a Lisp macro") |
294 ((eq (car-safe def) 'autoload) | 368 ((eq (car-safe def) 'autoload) |
295 (setq file-name (nth 1 def)) | |
296 (format "%s autoloaded %s" | 369 (format "%s autoloaded %s" |
297 (if (commandp def) "an interactive" "an") | 370 (if (commandp def) "an interactive" "an") |
298 (if (eq (nth 4 def) 'keymap) "keymap" | 371 (if (eq (nth 4 def) 'keymap) "keymap" |
299 (if (nth 4 def) "Lisp macro" "Lisp function")) | 372 (if (nth 4 def) "Lisp macro" "Lisp function")))) |
300 )) | |
301 ((keymapp def) | 373 ((keymapp def) |
302 (let ((is-full nil) | 374 (let ((is-full nil) |
303 (elts (cdr-safe def))) | 375 (elts (cdr-safe def))) |
304 (while elts | 376 (while elts |
305 (if (char-table-p (car-safe elts)) | 377 (if (char-table-p (car-safe elts)) |
314 (if (eq errtype 'alias) | 386 (if (eq errtype 'alias) |
315 (princ ",\nwhich is not defined. Please make a bug report.") | 387 (princ ",\nwhich is not defined. Please make a bug report.") |
316 (with-current-buffer standard-output | 388 (with-current-buffer standard-output |
317 (save-excursion | 389 (save-excursion |
318 (save-match-data | 390 (save-match-data |
319 (if (re-search-backward "alias for `\\([^`']+\\)'" nil t) | 391 (when (re-search-backward "alias for `\\([^`']+\\)'" nil t) |
320 (help-xref-button 1 'help-function def))))) | 392 (help-xref-button 1 'help-function def))))) |
321 (or file-name | 393 |
322 (setq file-name (symbol-file function 'defun))) | 394 (setq file-name (find-lisp-object-file-name function def)) |
323 (setq file-name (describe-simplify-lib-file-name file-name)) | |
324 (when (equal file-name "loaddefs.el") | |
325 ;; Find the real def site of the preloaded function. | |
326 ;; This is necessary only for defaliases. | |
327 (let ((location | |
328 (condition-case nil | |
329 (find-function-search-for-symbol function nil "loaddefs.el") | |
330 (error nil)))) | |
331 (when location | |
332 (with-current-buffer (car location) | |
333 (goto-char (cdr location)) | |
334 (when (re-search-backward | |
335 "^;;; Generated autoloads from \\(.*\\)" nil t) | |
336 (setq file-name (match-string 1))))))) | |
337 (when (and (null file-name) (subrp def)) | |
338 ;; Find the C source file name. | |
339 (setq file-name (if (get-buffer " *DOC*") | |
340 (help-C-file-name def 'subr) | |
341 'C-source))) | |
342 (when file-name | 395 (when file-name |
343 (princ " in `") | 396 (princ " in `") |
344 ;; We used to add .el to the file name, | 397 ;; We used to add .el to the file name, |
345 ;; but that's completely wrong when the user used load-file. | 398 ;; but that's completely wrong when the user used load-file. |
346 (princ (if (eq file-name 'C-source) "C source code" file-name)) | 399 (princ (if (eq file-name 'C-source) "C source code" file-name)) |
347 (princ "'") | 400 (princ "'") |
348 ;; See if lisp files are present where they where installed from. | |
349 (if (not (eq file-name 'C-source)) | |
350 (setq file-name (find-source-lisp-file file-name))) | |
351 | |
352 ;; Make a hyperlink to the library. | 401 ;; Make a hyperlink to the library. |
353 (with-current-buffer standard-output | 402 (with-current-buffer standard-output |
354 (save-excursion | 403 (save-excursion |
355 (re-search-backward "`\\([^`']+\\)'" nil t) | 404 (re-search-backward "`\\([^`']+\\)'" nil t) |
356 (help-xref-button 1 'help-function-def real-function file-name)))) | 405 (help-xref-button 1 'help-function-def real-function file-name)))) |
517 (get vv 'variable-documentation))) | 566 (get vv 'variable-documentation))) |
518 t nil nil | 567 t nil nil |
519 (if (symbolp v) (symbol-name v)))) | 568 (if (symbolp v) (symbol-name v)))) |
520 (list (if (equal val "") | 569 (list (if (equal val "") |
521 v (intern val))))) | 570 v (intern val))))) |
522 (unless (buffer-live-p buffer) (setq buffer (current-buffer))) | 571 (let (file-name) |
523 (unless (frame-live-p frame) (setq frame (selected-frame))) | 572 (unless (buffer-live-p buffer) (setq buffer (current-buffer))) |
524 (if (not (symbolp variable)) | 573 (unless (frame-live-p frame) (setq frame (selected-frame))) |
525 (message "You did not specify a variable") | 574 (if (not (symbolp variable)) |
526 (save-excursion | 575 (message "You did not specify a variable") |
527 (let ((valvoid (not (with-current-buffer buffer (boundp variable)))) | 576 (save-excursion |
528 val val-start-pos locus) | 577 (let ((valvoid (not (with-current-buffer buffer (boundp variable)))) |
529 ;; Extract the value before setting up the output buffer, | 578 val val-start-pos locus) |
530 ;; in case `buffer' *is* the output buffer. | 579 ;; Extract the value before setting up the output buffer, |
531 (unless valvoid | 580 ;; in case `buffer' *is* the output buffer. |
532 (with-selected-frame frame | 581 (unless valvoid |
582 (with-selected-frame frame | |
583 (with-current-buffer buffer | |
584 (setq val (symbol-value variable) | |
585 locus (variable-binding-locus variable))))) | |
586 (help-setup-xref (list #'describe-variable variable buffer) | |
587 (interactive-p)) | |
588 (with-help-window (help-buffer) | |
533 (with-current-buffer buffer | 589 (with-current-buffer buffer |
534 (setq val (symbol-value variable) | 590 (prin1 variable) |
535 locus (variable-binding-locus variable))))) | 591 (setq file-name (find-lisp-object-file-name variable 'defvar)) |
536 (help-setup-xref (list #'describe-variable variable buffer) | 592 |
537 (interactive-p)) | |
538 (with-help-window (help-buffer) | |
539 (with-current-buffer buffer | |
540 (prin1 variable) | |
541 ;; Make a hyperlink to the library if appropriate. (Don't | |
542 ;; change the format of the buffer's initial line in case | |
543 ;; anything expects the current format.) | |
544 (let ((file-name (symbol-file variable 'defvar))) | |
545 (setq file-name (describe-simplify-lib-file-name file-name)) | |
546 (when (equal file-name "loaddefs.el") | |
547 ;; Find the real def site of the preloaded variable. | |
548 (let ((location | |
549 (condition-case nil | |
550 (find-variable-noselect variable file-name) | |
551 (error nil)))) | |
552 (when location | |
553 (with-current-buffer (car location) | |
554 (when (cdr location) | |
555 (goto-char (cdr location))) | |
556 (when (re-search-backward | |
557 "^;;; Generated autoloads from \\(.*\\)" nil t) | |
558 (setq file-name (match-string 1))))))) | |
559 (when (and (null file-name) | |
560 (integerp (get variable 'variable-documentation))) | |
561 ;; It's a variable not defined in Elisp but in C. | |
562 (setq file-name | |
563 (if (get-buffer " *DOC*") | |
564 (help-C-file-name variable 'var) | |
565 'C-source))) | |
566 (if file-name | 593 (if file-name |
567 (progn | 594 (progn |
568 (princ " is a variable defined in `") | 595 (princ " is a variable defined in `") |
569 (princ (if (eq file-name 'C-source) "C source code" file-name)) | 596 (princ (if (eq file-name 'C-source) "C source code" file-name)) |
570 (princ "'.\n") | 597 (princ "'.\n") |