From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Jumping to C source from *Help* Date: 06 Apr 2004 18:35:24 -0400 Sender: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Message-ID: NNTP-Posting-Host: deer.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1081291539 31226 80.91.224.253 (6 Apr 2004 22:45:39 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Tue, 6 Apr 2004 22:45:39 +0000 (UTC) Original-X-From: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Wed Apr 07 00:45:29 2004 Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by deer.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1BAzJw-0000vh-00 for ; Wed, 07 Apr 2004 00:45:28 +0200 Original-Received: from monty-python.gnu.org ([199.232.76.173]) by quimby.gnus.org with esmtp (Exim 3.35 #1 (Debian)) id 1BAzJw-0002C0-00 for ; Wed, 07 Apr 2004 00:45:28 +0200 Original-Received: from localhost ([127.0.0.1] helo=monty-python.gnu.org) by monty-python.gnu.org with esmtp (Exim 4.30) id 1BAzEG-00082O-53 for emacs-devel@quimby.gnus.org; Tue, 06 Apr 2004 18:39:36 -0400 Original-Received: from list by monty-python.gnu.org with tmda-scanned (Exim 4.30) id 1BAzDy-0007t6-AD for emacs-devel@gnu.org; Tue, 06 Apr 2004 18:39:18 -0400 Original-Received: from mail by monty-python.gnu.org with spam-scanned (Exim 4.30) id 1BAzDO-00071o-8y for emacs-devel@gnu.org; Tue, 06 Apr 2004 18:39:13 -0400 Original-Received: from [199.232.41.8] (helo=mx20.gnu.org) by monty-python.gnu.org with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.30) id 1BAzDN-00071g-Qx for emacs-devel@gnu.org; Tue, 06 Apr 2004 18:38:41 -0400 Original-Received: from [132.204.24.67] (helo=mercure.iro.umontreal.ca) by mx20.gnu.org with esmtp (Exim 4.30) id 1BAzAH-00072m-1z for emacs-devel@gnu.org; Tue, 06 Apr 2004 18:35:29 -0400 Original-Received: from asado.iro.umontreal.ca (asado.iro.umontreal.ca [132.204.24.84]) by mercure.iro.umontreal.ca (Postfix) with ESMTP id 5E37F20F54; Tue, 6 Apr 2004 18:35:24 -0400 (EDT) Original-Received: by asado.iro.umontreal.ca (Postfix, from userid 20848) id 497288B4C3; Tue, 6 Apr 2004 18:35:24 -0400 (EDT) Original-To: emacs-devel@gnu.org Original-Lines: 282 User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3.50 X-DIRO-MailScanner-Information: Please contact the ISP for more information X-DIRO-MailScanner: Found to be clean X-DIRO-MailScanner-SpamCheck: n'est pas un polluriel, SpamAssassin (score=-1.428, requis 5, BAYES_20 -1.43) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.4 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Xref: main.gmane.org gmane.emacs.devel:21302 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:21302 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 "\\`#\\'" 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"))