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")