[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Jumping to C source from *Help*
From: |
Stefan Monnier |
Subject: |
Jumping to C source from *Help* |
Date: |
06 Apr 2004 18:35:24 -0400 |
User-agent: |
Gnus/5.09 (Gnus v5.9.0) Emacs/21.3.50 |
As has already been discussed in the past, it would be a good thing to be
able to jump from the *Help* buffer to the source of a var or fun that's
defined in C, just like we can do it when it's defined in Elisp.
Until recently I was using a hack based on TAGS, which was sadly too ugly
and fragile to be installed. I have re-implemented the feature now in
a much cleaner way.
The source-file-name info is placed directly in DOC by make-docfile.
Please review and tell me of anything that might need to be changed before
installing the change.
Stefan
Index: lib-src/make-docfile.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/make-docfile.c,v
retrieving revision 1.56
diff -u -r1.56 make-docfile.c
--- lib-src/make-docfile.c 24 Dec 2003 06:49:23 -0000 1.56
+++ lib-src/make-docfile.c 6 Apr 2004 22:33:59 -0000
@@ -1,5 +1,5 @@
/* Generate doc-string file for GNU Emacs from source files.
- Copyright (C) 1985, 86, 92, 93, 94, 97, 1999, 2000, 2001
+ Copyright (C) 1985, 86, 92, 93, 94, 97, 1999, 2000, 01, 2004
Free Software Foundation, Inc.
This file is part of GNU Emacs.
@@ -105,11 +105,11 @@
/* Like malloc but get fatal error if memory is exhausted. */
-long *
+void *
xmalloc (size)
unsigned int size;
{
- long *result = (long *) malloc (size);
+ void *result = (void *) malloc (size);
if (result == NULL)
fatal ("virtual memory exhausted", 0);
return result;
@@ -178,6 +178,35 @@
return (err_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
+/* Add a source file name boundary marker in the output file. */
+void
+put_filename (filename)
+ char *filename;
+{
+ char *tmp = filename;
+ int len;
+
+ while ((tmp = index (filename, '/')))
+ filename = tmp + 1;
+
+ len = strlen (filename);
+ tmp = xmalloc (len + 1);
+ strcpy (tmp, filename);
+ filename = tmp;
+
+ /* Turn object file names into source file names. */
+ if (len > 4 && !strcmp (filename + len - 4, ".elc"))
+ /* Truncate `.elc' to `.el'. */
+ filename[len - 1] = '\0';
+ else if (len > 2 && !strcmp (filename + len - 2, ".o"))
+ /* Switch `.o' to `.c'. */
+ filename[len - 1] = 'c';
+
+ putc (037, outfile);
+ putc ('S', outfile);
+ fprintf (outfile, "%s\n", filename);
+}
+
/* Read file FILENAME and output its doc strings to outfile. */
/* Return 1 if file is not found, 0 if it is found. */
@@ -186,6 +215,8 @@
char *filename;
{
int len = strlen (filename);
+
+ put_filename (filename);
if (len > 4 && !strcmp (filename + len - 4, ".elc"))
return scan_lisp_file (filename, READ_BINARY);
else if (len > 3 && !strcmp (filename + len - 3, ".el"))
Index: src/doc.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/doc.c,v
retrieving revision 1.103
diff -u -r1.103 doc.c
--- src/doc.c 2 Mar 2004 06:11:48 -0000 1.103
+++ src/doc.c 6 Apr 2004 22:33:59 -0000
@@ -1,5 +1,6 @@
/* Record indices of function doc strings stored in a file.
- Copyright (C) 1985, 86,93,94,95,97,98,99, 2000 Free Software Foundation,
Inc.
+ Copyright (C) 1985, 86,93,94,95,97,98,99,2000,04
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
@@ -612,8 +613,7 @@
*p = '_';
p++;
}
-#endif /* not VMS4_4 */
-#ifdef VMS4_4
+#else /* VMS4_4 */
strcpy (name, sys_translate_unix (name));
#endif /* VMS4_4 */
#endif /* VMS */
@@ -659,6 +659,9 @@
/* Attach a docstring to a function? */
else if (p[1] == 'F')
store_function_docstring (sym, pos + end + 1 - buf);
+
+ else if (p[1] == 'S')
+ ; /* Just a source file name boundary marker. Ignore it. */
else
error ("DOC file invalid at position %d", pos);
Index: lisp/help-fns.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/help-fns.el,v
retrieving revision 1.36
diff -u -r1.36 help-fns.el
--- lisp/help-fns.el 20 Feb 2004 03:48:32 -0000 1.36
+++ lisp/help-fns.el 6 Apr 2004 22:33:59 -0000
@@ -1,6 +1,6 @@
;;; help-fns.el --- Complex help functions
-;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000, 2001, 2002, 2003
+;; Copyright (C) 1985, 86, 93, 94, 98, 1999, 2000, 01, 02, 03, 2004
;; Free Software Foundation, Inc.
;; Maintainer: FSF
@@ -215,6 +215,56 @@
(intern (upcase name))))))
arglist)))
+(defvar help-C-source-directory
+ (let ((dir (expand-file-name "src" source-directory)))
+ (when (and (file-directory-p dir) (file-readable-p dir))
+ dir))
+ "Directory where the C source files of Emacs can be found.
+If nil, do not try to find the source code of functions and variables
+defined in C.")
+
+(defun help-subr-name (subr)
+ (let ((name (prin1-to-string subr)))
+ (if (string-match "\\`#<subr \\(.*\\)>\\'" name)
+ (match-string 1 name)
+ (error "Unexpected internal name: %s" name))))
+
+(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."
+ (let ((docbuf (get-buffer-create " *DOC*"))
+ (name (if (eq 'var kind)
+ (concat "V" (symbol-name subr-or-var))
+ (concat "F" (help-subr-name subr-or-var)))))
+ (with-current-buffer docbuf
+ (goto-char (point-min))
+ (if (eobp)
+ (insert-file-contents-literally
+ (expand-file-name internal-doc-file-name doc-directory)))
+ (search-forward (concat "" name "\n"))
+ (re-search-backward "S\\(.*\\)")
+ (match-string 1))))
+
+(defun help-find-C-source (fun-or-var file kind)
+ (setq file (expand-file-name file help-C-source-directory))
+ (unless (file-readable-p file)
+ (error "The C source file %s is not available"
+ (file-name-nondirectory file)))
+ (if (eq 'fun kind)
+ (setq fun-or-var (indirect-function fun-or-var)))
+ (with-current-buffer (find-file-noselect file)
+ (goto-char (point-min))
+ (unless (re-search-forward
+ (if (eq 'fun kind)
+ (concat "DEFUN[ \t\n]*([ \t\n]*\""
+ (regexp-quote (help-subr-name fun-or-var))
+ "\"")
+ (concat "DEFVAR[A-Z_]*[ \t\n]*([ \t\n]*\""
+ (regexp-quote (symbol-name fun-or-var))))
+ nil t)
+ (error "Can't find source for %s" fun))
+ (cons (current-buffer) (match-beginning 0))))
+
;;;###autoload
(defun describe-function-1 (function)
(let* ((def (if (symbolp function)
@@ -280,8 +330,11 @@
(when (re-search-backward
"^;;; Generated autoloads from \\(.*\\)" nil t)
(setq file-name (match-string 1)))))))
- (cond
- (file-name
+ (when (and (null file-name) (subrp def))
+ (if help-C-source-directory
+ (setq file-name (concat "src/" (help-C-file-name def 'subr)))
+ (princ " in core C code")))
+ (when file-name
(princ " in `")
;; We used to add .el to the file name,
;; but that's completely wrong when the user used load-file.
@@ -289,9 +342,9 @@
(princ "'")
;; Make a hyperlink to the library.
(with-current-buffer standard-output
- (save-excursion
+ (save-excursion
(re-search-backward "`\\([^`']+\\)'" nil t)
- (help-xref-button 1 'help-function-def function file-name)))))
+ (help-xref-button 1 'help-function-def function file-name))))
(princ ".")
(terpri)
(when (commandp function)
@@ -500,6 +553,13 @@
(when (re-search-backward
"^;;; Generated autoloads from \\(.*\\)" nil t)
(setq file-name (match-string 1)))))))
+ (when (and (null file-name)
+ (integerp (get variable 'variable-documentation)))
+ ;; It's a variable not defined in Elisp but in C.
+ (if help-C-source-directory
+ (setq file-name
+ (concat "src/" (help-C-file-name variable 'var)))
+ (princ "\n\nDefined in core C code.")))
(when file-name
(princ "\n\nDefined in `")
(princ file-name)
Index: lisp/help-mode.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/help-mode.el,v
retrieving revision 1.23
diff -u -r1.23 help-mode.el
--- lisp/help-mode.el 5 Apr 2004 12:09:53 -0000 1.23
+++ lisp/help-mode.el 6 Apr 2004 22:33:59 -0000
@@ -1,6 +1,6 @@
;;; help-mode.el --- `help-mode' used by *Help* buffers
-;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000, 2001, 2002
+;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000, 2001, 2002, 2004
;; Free Software Foundation, Inc.
;; Maintainer: FSF
@@ -150,8 +150,11 @@
;; Don't use find-function-noselect because it follows
;; aliases (which fails for built-in functions).
(let ((location
- (if (bufferp file) (cons file fun)
- (find-function-search-for-symbol fun nil file))))
+ (cond
+ ((bufferp file) (cons file fun))
+ ((string-match "\\`src/\\(.*\\.c\\)" file)
+ (help-find-C-source fun (match-string 1 file) 'fun))
+ (t (find-function-search-for-symbol fun nil file)))))
(pop-to-buffer (car location))
(goto-char (cdr location))))
'help-echo (purecopy "mouse-2, RET: find function's definition"))
@@ -160,7 +163,10 @@
:supertype 'help-xref
'help-function (lambda (var &optional file)
(let ((location
- (find-variable-noselect var file)))
+ (cond
+ ((string-match "\\`src/\\(.*\\.c\\)" file)
+ (help-find-C-source var (match-string 1 file) 'var))
+ (t (find-variable-noselect var file)))))
(pop-to-buffer (car location))
(goto-char (cdr location))))
'help-echo (purecopy"mouse-2, RET: find variable's definition"))
- Jumping to C source from *Help*,
Stefan Monnier <=