Commit | Line | Data |
---|---|---|
780ee65e NJ |
1 | ;;; docstring.el --- utilities for Guile docstring maintenance |
2 | ;;; | |
f3f16cf6 | 3 | ;;; Copyright (C) 2001, 2004 Neil Jerram |
780ee65e NJ |
4 | ;;; |
5 | ;;; This file is not part of GNU Emacs, but the same permissions apply. | |
6 | ;;; | |
7 | ;;; GNU Emacs is free software; you can redistribute it and/or modify | |
8 | ;;; it under the terms of the GNU General Public License as published by | |
9 | ;;; the Free Software Foundation; either version 2, or (at your option) | |
10 | ;;; any later version. | |
11 | ;;; | |
12 | ;;; GNU Emacs is distributed in the hope that it will be useful, | |
13 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;;; GNU General Public License for more details. | |
16 | ;;; | |
17 | ;;; You should have received a copy of the GNU General Public License | |
18 | ;;; along with GNU Emacs; see the file COPYING. If not, write to the | |
92205699 MV |
19 | ;;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | ;;; Boston, MA 02110-1301, USA. | |
780ee65e NJ |
21 | |
22 | ;;; Commentary: | |
23 | ||
24 | ;; The basic premise of these utilities is that - at least in the | |
25 | ;; short term - we can get a lot of reference manual mileage by | |
26 | ;; co-opting the docstrings that are snarfed automatically from | |
27 | ;; Guile's C and Scheme source code. But this leads to problems of | |
28 | ;; synchronization... How do you track when a docstring has been | |
29 | ;; updated in the source and so needs updating in the reference | |
30 | ;; manual. What if a procedure is removed from the Guile source? And | |
31 | ;; so on. To complicate matters, the exact snarfed docstring text | |
32 | ;; will probably need to be modified so that it fits into the flow of | |
33 | ;; the manual section in which it appears. Can we design solutions to | |
34 | ;; synchronization problems that continue to work even when the manual | |
35 | ;; text has been enhanced in this way? | |
36 | ;; | |
37 | ;; This file implements an approach to this problem that I have found | |
38 | ;; useful. It involves keeping track of three copies of each | |
39 | ;; docstring: | |
40 | ;; | |
41 | ;; "MANUAL" = the docstring as it appears in the reference manual. | |
42 | ;; | |
43 | ;; "SNARFED" = the docstring as snarfed from the current C or Scheme | |
44 | ;; source. | |
45 | ;; | |
46 | ;; "TRACKING" = the docstring as it appears in a tracking file whose | |
47 | ;; purpose is to record the most recent snarfed docstrings | |
48 | ;; that are known to be in sync with the reference manual. | |
49 | ;; | |
50 | ;; The approaches are as follows. | |
51 | ;; | |
52 | ;; 1. Comparison of MANUAL-DOC, SOURCE-DOC and TRACK-DOC, to produce a | |
f8be0483 TTN |
53 | ;; summary output buffer in which keystrokes are defined to bring up |
54 | ;; detailed comparisons. | |
780ee65e NJ |
55 | ;; |
56 | ;; 2. Comparison of MANUAL-DOC, SOURCE-DOC and TRACK-DOC using Ediff. | |
f8be0483 TTN |
57 | ;; |
58 | ;; Here is a brief list of commands available (via "M-x COMMAND"): | |
59 | ;; | |
60 | ;; docstring-process-current-buffer | |
61 | ;; docstring-process-current-region BEG END | |
62 | ;; docstring-process-module MODULE | |
63 | ;; docstring-ediff-this-line | |
64 | ;; docstring-show-source | |
780ee65e | 65 | |
780ee65e | 66 | |
697440cb | 67 | (defvar guile-core-dir (or (getenv "GUILE_MAINTAINER_GUILE_CORE_DIR") |
59afd555 GH |
68 | (error "GUILE_MAINTAINER_GUILE_CORE_DIR not set")) |
69 | "*Full path of guile-core source directory.") | |
70 | ||
71 | (defvar guile-build-dir (or (getenv "GUILE_MAINTAINER_BUILD_CORE_DIR") | |
72 | guile-core-dir) | |
73 | "*Full path of guile-core build directory. Defaults to guile-core-dir.") | |
697440cb TTN |
74 | |
75 | (defvar docstring-manual-directory (expand-file-name "doc/ref" guile-core-dir) | |
780ee65e NJ |
76 | "*The directory containing the Texinfo source for the Guile reference manual.") |
77 | ||
697440cb | 78 | (defvar docstring-tracking-root (expand-file-name "doc/maint" guile-core-dir) |
780ee65e NJ |
79 | "*Root directory for docstring tracking files. The tracking file |
80 | for module (a b c) is expected to be in the file | |
81 | <docstring-tracking-root>/a/b/c.texi.") | |
82 | ||
697440cb TTN |
83 | (defvar docstring-snarfed-roots (mapcar |
84 | #'(lambda (frag) | |
d2e13cf7 | 85 | (expand-file-name frag guile-build-dir)) |
697440cb | 86 | '("libguile" "ice-9" "oop")) |
780ee65e NJ |
87 | "*List of possible root directories for snarfed docstring files. |
88 | For each entry in this list, the snarfed docstring file for module (a | |
89 | b c) is looked for in the file <entry>/a/b/c.texi.") | |
90 | ||
9401323e NJ |
91 | (defvar docstring-manual-files |
92 | (directory-files docstring-manual-directory nil "\\.texi$" t) | |
780ee65e NJ |
93 | "List of Texinfo source files that comprise the Guile reference manual.") |
94 | ||
95 | (defvar docstring-new-docstrings-file "new-docstrings.texi" | |
96 | "The name of a file in the Guile reference manual source directory | |
97 | to which new docstrings should be added.") | |
98 | ||
99 | ;; Apply FN in turn to each element in the list CANDIDATES until the | |
100 | ;; first application that returns non-nil. | |
101 | (defun or-map (fn candidates args) | |
102 | (let ((result nil)) | |
103 | (while candidates | |
104 | (setq result (apply fn (car candidates) args)) | |
105 | (if result | |
106 | (setq result (cons (car candidates) result) | |
107 | candidates nil) | |
108 | (setq candidates (cdr candidates)))) | |
109 | result)) | |
110 | ||
111 | ;; Return t if the current buffer position is in the scope of the | |
87cc0e0c | 112 | ;; specified MODULE, as determined by "@c module-for-docstring ..." comments in the |
780ee65e NJ |
113 | ;; buffer. DEFAULT-OK specifies the return value in the case that |
114 | ;; there are no preceding module comments at all. | |
115 | (defun docstring-in-module (module default-ok) | |
116 | (save-excursion | |
87cc0e0c | 117 | (if (re-search-backward "^@c module-for-docstring " nil t) |
780ee65e | 118 | (progn |
87cc0e0c | 119 | (search-forward "@c module-for-docstring ") |
780ee65e NJ |
120 | (equal module (read (current-buffer)))) |
121 | default-ok))) | |
122 | ||
123 | ;; Find a docstring in the specified FILE-NAME for the item in module | |
124 | ;; MODULE and with description DESCRIPTION. MODULE should be a list | |
125 | ;; of symbols, Guile-style, for example: '(ice-9 session). | |
126 | ;; DESCRIPTION should be the string that is expected after the @deffn, | |
127 | ;; for example "primitive acons" or "syntax let*". | |
128 | (defun find-docstring (file-name module description) | |
129 | (and (file-exists-p file-name) | |
130 | (let ((buf (find-file-noselect file-name)) | |
131 | (deffn-regexp (concat "^@deffnx? " | |
132 | (regexp-quote description) | |
133 | "[ \n\t]")) | |
134 | found | |
135 | result) | |
136 | (save-excursion | |
137 | (set-buffer buf) | |
138 | (goto-char (point-min)) | |
139 | (while (and (not found) | |
140 | (re-search-forward deffn-regexp nil t)) | |
141 | (save-excursion | |
142 | (goto-char (match-beginning 0)) | |
143 | (beginning-of-line) | |
144 | (if (docstring-in-module module t) | |
145 | (setq found t)))) | |
146 | (if found | |
147 | (setq result | |
148 | (list (current-buffer) | |
149 | (progn | |
150 | (re-search-backward "^@deffn ") | |
151 | (beginning-of-line) | |
152 | (point)) | |
153 | (progn | |
154 | (re-search-forward "^@end deffn") | |
155 | (forward-line 1) | |
156 | (point)))))) | |
157 | result))) | |
158 | ||
159 | ;; Find the reference manual version of the specified docstring. | |
160 | ;; MODULE and DESCRIPTION specify the docstring as per | |
161 | ;; `find-docstring'. The set of files that `find-manual-docstring' | |
162 | ;; searches is determined by the value of the `docstring-manual-files' | |
163 | ;; variable. | |
164 | (defun find-manual-docstring (module description) | |
165 | (let* ((result | |
166 | (or-map 'find-docstring | |
167 | (mapcar (function (lambda (file-name) | |
168 | (concat docstring-manual-directory | |
169 | "/" | |
170 | file-name))) | |
171 | (cons docstring-new-docstrings-file | |
172 | docstring-manual-files)) | |
173 | (list module | |
174 | description))) | |
175 | (matched-file-name (and (cdr result) | |
176 | (file-name-nondirectory (car result))))) | |
177 | (if matched-file-name | |
178 | (setq docstring-manual-files | |
179 | (cons matched-file-name | |
180 | (delete matched-file-name docstring-manual-files)))) | |
181 | (cdr result))) | |
182 | ||
183 | ;; Convert MODULE to a directory subpath. | |
184 | (defun module-to-path (module) | |
185 | (mapconcat (function (lambda (component) | |
186 | (symbol-name component))) | |
187 | module | |
188 | "/")) | |
189 | ||
190 | ;; Find the current snarfed version of the specified docstring. | |
191 | ;; MODULE and DESCRIPTION specify the docstring as per | |
192 | ;; `find-docstring'. The file that `find-snarfed-docstring' looks in | |
193 | ;; is automatically generated from MODULE. | |
194 | (defun find-snarfed-docstring (module description) | |
195 | (let ((modpath (module-to-path module))) | |
196 | (cdr (or-map (function (lambda (root) | |
197 | (find-docstring (concat root | |
198 | "/" | |
199 | modpath | |
200 | ".texi") | |
201 | module | |
202 | description))) | |
203 | docstring-snarfed-roots | |
204 | nil)))) | |
205 | ||
206 | ;; Find the tracking version of the specified docstring. MODULE and | |
207 | ;; DESCRIPTION specify the docstring as per `find-docstring'. The | |
208 | ;; file that `find-tracking-docstring' looks in is automatically | |
209 | ;; generated from MODULE. | |
210 | (defun find-tracking-docstring (module description) | |
211 | (find-docstring (concat docstring-tracking-root | |
212 | "/" | |
213 | (module-to-path module) | |
214 | ".texi") | |
215 | module | |
216 | description)) | |
217 | ||
218 | ;; Extract an alist of modules and descriptions from the current | |
219 | ;; buffer. | |
220 | (defun make-module-description-list () | |
221 | (let ((alist nil) | |
222 | (module '(guile))) | |
223 | (save-excursion | |
224 | (goto-char (point-min)) | |
87cc0e0c | 225 | (while (re-search-forward "^\\(@c module-for-docstring \\|@deffnx? \\({[^}]+}\\|[^ ]+\\) \\([^ \n]+\\)\\)" |
780ee65e NJ |
226 | nil |
227 | t) | |
228 | (let ((matched (buffer-substring (match-beginning 1) | |
229 | (match-end 1)))) | |
87cc0e0c | 230 | (if (string-equal matched "@c module-for-docstring ") |
780ee65e | 231 | (setq module (read (current-buffer))) |
8f85c0c6 NJ |
232 | (let ((type (buffer-substring (match-beginning 2) |
233 | (match-end 2)))) | |
234 | (if (string-equal type "{C Function}") | |
235 | nil | |
236 | (setq matched | |
237 | (concat type | |
238 | " " | |
239 | (buffer-substring (match-beginning 3) | |
240 | (match-end 3)))) | |
241 | (message "Found docstring: %S: %s" module matched) | |
242 | (let ((descriptions (assoc module alist))) | |
243 | (setq alist | |
244 | (cons (cons module (cons matched (cdr-safe descriptions))) | |
245 | (if descriptions | |
246 | (delete descriptions alist) | |
247 | alist)))))))))) | |
780ee65e NJ |
248 | alist)) |
249 | ||
fc5c6d00 GH |
250 | ;; missing in some environments? |
251 | (defun caddr (list) | |
252 | (nth 2 list)) | |
253 | ||
780ee65e NJ |
254 | ;; Return the docstring from the specified LOCATION. LOCATION is a |
255 | ;; list of three elements: buffer, start position and end position. | |
256 | (defun location-to-docstring (location) | |
257 | (and location | |
258 | (save-excursion | |
259 | (set-buffer (car location)) | |
260 | (buffer-substring (cadr location) (caddr location))))) | |
261 | ||
262 | ;; Perform a comparison of the specified docstring. MODULE and | |
263 | ;; DESCRIPTION are as per usual. | |
264 | (defun docstring-compare (module description) | |
265 | (let* ((manual-location (find-manual-docstring module description)) | |
266 | (snarf-location (find-snarfed-docstring module description)) | |
267 | (track-location (find-tracking-docstring module description)) | |
268 | ||
269 | (manual-docstring (location-to-docstring manual-location)) | |
270 | (snarf-docstring (location-to-docstring snarf-location)) | |
271 | (track-docstring (location-to-docstring track-location)) | |
272 | ||
273 | action | |
274 | issue) | |
275 | ||
276 | ;; Decide what to do. | |
277 | (cond ((null snarf-location) | |
278 | (setq action nil | |
279 | issue (if manual-location | |
280 | 'consider-removal | |
697440cb | 281 | nil))) |
780ee65e NJ |
282 | |
283 | ((null manual-location) | |
284 | (setq action 'add-to-manual issue nil)) | |
285 | ||
286 | ((null track-location) | |
287 | (setq action nil | |
288 | issue (if (string-equal manual-docstring snarf-docstring) | |
289 | nil | |
290 | 'check-needed))) | |
291 | ||
292 | ((string-equal track-docstring snarf-docstring) | |
293 | (setq action nil issue nil)) | |
294 | ||
295 | ((string-equal track-docstring manual-docstring) | |
296 | (setq action 'auto-update-manual issue nil)) | |
297 | ||
298 | (t | |
299 | (setq action nil issue 'update-needed))) | |
300 | ||
301 | ;; Return a pair indicating any automatic action that can be | |
302 | ;; taken, and any issue for resolution. | |
303 | (cons action issue))) | |
304 | ||
305 | ;; Add the specified docstring to the manual. | |
306 | (defun docstring-add-to-manual (module description) | |
307 | (let ((buf (find-file-noselect (concat docstring-manual-directory | |
308 | "/" | |
309 | docstring-new-docstrings-file)))) | |
310 | (save-excursion | |
311 | (set-buffer buf) | |
312 | (goto-char (point-max)) | |
313 | (or (docstring-in-module module nil) | |
87cc0e0c | 314 | (insert "\n@c module-for-docstring " (prin1-to-string module) "\n")) |
780ee65e NJ |
315 | (insert "\n" (location-to-docstring (find-snarfed-docstring module |
316 | description)))))) | |
317 | ||
318 | ;; Auto-update the specified docstring in the manual. | |
319 | (defun docstring-auto-update-manual (module description) | |
320 | (let ((manual-location (find-manual-docstring module description)) | |
321 | (track-location (find-tracking-docstring module description))) | |
322 | (save-excursion | |
323 | (set-buffer (car manual-location)) | |
324 | (goto-char (cadr manual-location)) | |
325 | (delete-region (cadr manual-location) (caddr manual-location)) | |
326 | (insert (location-to-docstring (find-snarfed-docstring module | |
327 | description)))))) | |
328 | ||
329 | ;; Process an alist of modules and descriptions, and produce a summary | |
330 | ;; buffer describing actions taken and issues to be resolved. | |
331 | (defun docstring-process-alist (alist) | |
332 | (let (check-needed-list | |
333 | update-needed-list | |
334 | consider-removal-list | |
335 | added-to-manual-list | |
336 | auto-updated-manual-list) | |
337 | ||
338 | (mapcar | |
339 | (function (lambda (module-list) | |
340 | (let ((module (car module-list))) | |
341 | (message "Module: %S" module) | |
342 | (mapcar | |
343 | (function (lambda (description) | |
344 | (message "Comparing docstring: %S: %s" module description) | |
345 | (let* ((ai (docstring-compare module description)) | |
346 | (action (car ai)) | |
347 | (issue (cdr ai))) | |
348 | ||
349 | (cond ((eq action 'add-to-manual) | |
350 | (docstring-add-to-manual module description) | |
351 | (setq added-to-manual-list | |
352 | (cons (cons module description) | |
353 | added-to-manual-list))) | |
354 | ||
355 | ((eq action 'auto-update-manual) | |
356 | (docstring-auto-update-manual module description) | |
357 | (setq auto-updated-manual-list | |
358 | (cons (cons module description) | |
359 | auto-updated-manual-list)))) | |
360 | ||
361 | (cond ((eq issue 'check-needed) | |
362 | (setq check-needed-list | |
363 | (cons (cons module description) | |
364 | check-needed-list))) | |
365 | ||
366 | ((eq issue 'update-needed) | |
367 | (setq update-needed-list | |
368 | (cons (cons module description) | |
369 | update-needed-list))) | |
370 | ||
371 | ((eq issue 'consider-removal) | |
372 | (setq consider-removal-list | |
373 | (cons (cons module description) | |
374 | consider-removal-list))))))) | |
f3f16cf6 | 375 | (reverse (cdr module-list)))))) |
780ee65e NJ |
376 | alist) |
377 | ||
378 | ;; Prepare a buffer describing the results. | |
379 | (set-buffer (get-buffer-create "*Docstring Results*")) | |
380 | (erase-buffer) | |
381 | ||
382 | (insert " | |
383 | The following items have been automatically added to the manual in | |
384 | file `" docstring-manual-directory "/" docstring-new-docstrings-file "'.\n\n") | |
385 | (if added-to-manual-list | |
386 | (mapcar (function (lambda (moddesc) | |
387 | (insert (prin1-to-string (car moddesc)) | |
388 | ": " | |
389 | (cdr moddesc) | |
390 | "\n"))) | |
391 | added-to-manual-list) | |
392 | (insert "(none)\n")) | |
393 | ||
394 | (insert " | |
395 | The following items have been automatically updated in the manual.\n\n") | |
396 | (if auto-updated-manual-list | |
397 | (mapcar (function (lambda (moddesc) | |
398 | (insert (prin1-to-string (car moddesc)) | |
399 | ": " | |
400 | (cdr moddesc) | |
401 | "\n"))) | |
402 | auto-updated-manual-list) | |
403 | (insert "(none)\n")) | |
404 | ||
405 | (insert " | |
406 | The following items are already documented in the manual but are not | |
407 | mentioned in the reference copy of the snarfed docstrings file. | |
408 | You should check that the manual documentation matches the docstring | |
409 | in the current snarfed docstrings file.\n\n") | |
410 | (if check-needed-list | |
411 | (mapcar (function (lambda (moddesc) | |
412 | (insert (prin1-to-string (car moddesc)) | |
413 | ": " | |
414 | (cdr moddesc) | |
415 | "\n"))) | |
416 | check-needed-list) | |
417 | (insert "(none)\n")) | |
418 | ||
419 | (insert " | |
420 | The following items have manual documentation that is different from | |
421 | the docstring in the reference copy of the snarfed docstrings file, | |
422 | and the snarfed docstring has changed. You need to update the manual | |
423 | documentation by hand with reference to the snarfed docstring changes.\n\n") | |
424 | (if update-needed-list | |
425 | (mapcar (function (lambda (moddesc) | |
426 | (insert (prin1-to-string (car moddesc)) | |
427 | ": " | |
428 | (cdr moddesc) | |
429 | "\n"))) | |
430 | update-needed-list) | |
431 | (insert "(none)\n")) | |
432 | ||
433 | (insert " | |
434 | The following items are documented in the manual but are no longer | |
435 | present in the snarfed docstrings file. You should consider whether | |
436 | the existing manual documentation is still pertinent. If it is, its | |
437 | docstring module comment may need updating, to connect it with a | |
438 | new snarfed docstring file.\n\n") | |
439 | (if consider-removal-list | |
440 | (mapcar (function (lambda (moddesc) | |
441 | (insert (prin1-to-string (car moddesc)) | |
442 | ": " | |
443 | (cdr moddesc) | |
444 | "\n"))) | |
445 | consider-removal-list) | |
446 | (insert "(none)\n")) | |
447 | (insert "\n") | |
448 | ||
449 | (goto-char (point-min)) | |
8f85c0c6 | 450 | (local-set-key "d" 'docstring-ediff-this-line) |
780ee65e NJ |
451 | |
452 | ;; Popup the issues buffer. | |
453 | (let ((pop-up-frames t)) | |
454 | (set-window-point (display-buffer (current-buffer)) | |
455 | (point-min))))) | |
456 | ||
457 | (defun docstring-process-current-buffer () | |
458 | (interactive) | |
459 | (docstring-process-alist (make-module-description-list))) | |
460 | ||
461 | (defun docstring-process-current-region (beg end) | |
462 | (interactive "r") | |
463 | (narrow-to-region beg end) | |
464 | (unwind-protect | |
465 | (save-excursion | |
466 | (docstring-process-alist (make-module-description-list))) | |
467 | (widen))) | |
468 | ||
469 | (defun docstring-process-module (module) | |
470 | (interactive "xModule: ") | |
471 | (let ((modpath (module-to-path module)) | |
472 | (mdlist nil)) | |
473 | (mapcar (function (lambda (root) | |
474 | (let ((fn (concat root | |
475 | "/" | |
476 | modpath | |
477 | ".texi"))) | |
478 | (if (file-exists-p fn) | |
479 | (save-excursion | |
480 | (find-file fn) | |
481 | (message "Getting docstring list from %s" fn) | |
482 | (setq mdlist | |
483 | (append mdlist | |
484 | (make-module-description-list)))))))) | |
485 | docstring-snarfed-roots) | |
486 | (docstring-process-alist mdlist))) | |
487 | ||
488 | (defun docstring-ediff-this-line () | |
489 | (interactive) | |
490 | (let (module | |
491 | description) | |
492 | (save-excursion | |
493 | (beginning-of-line) | |
494 | (setq module (read (current-buffer))) | |
495 | (forward-char 2) | |
496 | (setq description (buffer-substring (point) | |
497 | (progn | |
498 | (end-of-line) | |
499 | (point))))) | |
500 | ||
501 | (message "Ediff docstring: %S: %s" module description) | |
502 | ||
503 | (let ((track-location (or (find-tracking-docstring module description) | |
504 | (docstring-temp-location "No docstring in tracking file"))) | |
505 | (snarf-location (or (find-snarfed-docstring module description) | |
506 | (docstring-temp-location "No docstring in snarfed file"))) | |
507 | (manual-location (or (find-manual-docstring module description) | |
508 | (docstring-temp-location "No docstring in manual")))) | |
509 | ||
510 | (setq docstring-ediff-buffers | |
511 | (list (car track-location) | |
512 | (car snarf-location) | |
513 | (car manual-location))) | |
514 | ||
515 | (docstring-narrow-to-location track-location) | |
516 | (docstring-narrow-to-location snarf-location) | |
517 | (docstring-narrow-to-location manual-location) | |
518 | ||
519 | (add-hook 'ediff-quit-hook 'docstring-widen-ediff-buffers) | |
697440cb | 520 | |
780ee65e NJ |
521 | (ediff-buffers3 (nth 0 docstring-ediff-buffers) |
522 | (nth 1 docstring-ediff-buffers) | |
523 | (nth 2 docstring-ediff-buffers))))) | |
524 | ||
525 | (defun docstring-narrow-to-location (location) | |
526 | (save-excursion | |
527 | (set-buffer (car location)) | |
528 | (narrow-to-region (cadr location) (caddr location)))) | |
529 | ||
530 | (defun docstring-temp-location (str) | |
531 | (let ((buf (generate-new-buffer "*Docstring Temp*"))) | |
532 | (save-excursion | |
533 | (set-buffer buf) | |
534 | (erase-buffer) | |
535 | (insert str "\n") | |
536 | (list buf (point-min) (point-max))))) | |
537 | ||
538 | (require 'ediff) | |
539 | ||
540 | (defvar docstring-ediff-buffers '()) | |
541 | ||
542 | (defun docstring-widen-ediff-buffers () | |
543 | (remove-hook 'ediff-quit-hook 'docstring-widen-ediff-buffers) | |
544 | (save-excursion | |
545 | (mapcar (function (lambda (buffer) | |
546 | (set-buffer buffer) | |
547 | (widen))) | |
548 | docstring-ediff-buffers))) | |
549 | ||
550 | ||
551 | ;;; Tests: | |
552 | ||
553 | ;(find-docstring "/home/neil/Guile/cvs/guile-core/doc/maint/guile.texi" nil "primitive sloppy-assq") | |
554 | ;(find-manual-docstring '(guile) "primitive sloppy-assq") | |
555 | ;(find-tracking-docstring '(guile) "primitive sloppy-assq") | |
556 | ;(find-snarfed-docstring '(guile) "primitive sloppy-assq") | |
557 | ||
ecfeac8c NJ |
558 | (defvar docstring-libguile-directory (expand-file-name "libguile" |
559 | guile-core-dir) | |
560 | "*The directory containing the C source for libguile.") | |
561 | ||
59afd555 GH |
562 | (defvar docstring-libguile-build-directory (expand-file-name "libguile" |
563 | guile-build-dir) | |
564 | "*The directory containing the libguile build directory.") | |
565 | ||
ecfeac8c NJ |
566 | (defun docstring-display-location (file line) |
567 | (let ((buffer (find-file-noselect | |
568 | (expand-file-name file docstring-libguile-directory)))) | |
569 | (if buffer | |
570 | (let* ((window (or (get-buffer-window buffer) | |
571 | (display-buffer buffer))) | |
572 | (pos (save-excursion | |
573 | (set-buffer buffer) | |
574 | (goto-line line) | |
575 | (point)))) | |
576 | (set-window-point window pos))))) | |
577 | ||
578 | (defun docstring-show-source () | |
579 | "Given that point is sitting in a docstring in one of the Texinfo | |
580 | source files for the Guile manual, and that that docstring may be | |
581 | snarfed automatically from a libguile C file, determine whether the | |
582 | docstring is from libguile and, if it is, display the relevant C file | |
583 | at the line from which the docstring was snarfed. | |
584 | ||
585 | Why? When updating snarfed docstrings, you should usually edit the C | |
586 | source rather than the Texinfo source, so that your updates benefit | |
587 | Guile's online help as well. This function locates the C source for a | |
588 | docstring so that it is easy for you to do this." | |
589 | (interactive) | |
590 | (let* ((deffn-line | |
591 | (save-excursion | |
592 | (end-of-line) | |
593 | (or (re-search-backward "^@deffn " nil t) | |
594 | (error "No docstring here!")) | |
595 | (buffer-substring (point) | |
596 | (progn | |
597 | (end-of-line) | |
598 | (point))))) | |
599 | (guile-texi-file | |
59afd555 | 600 | (expand-file-name "guile.texi" docstring-libguile-build-directory)) |
ecfeac8c NJ |
601 | (source-location |
602 | (save-excursion | |
603 | (set-buffer (find-file-noselect guile-texi-file)) | |
604 | (save-excursion | |
605 | (goto-char (point-min)) | |
606 | (or (re-search-forward (concat "^" | |
607 | (regexp-quote deffn-line) | |
608 | "$") | |
609 | nil t) | |
610 | (error "Docstring not from libguile")) | |
611 | (forward-line -1) | |
612 | (if (looking-at "^@c snarfed from \\([^:]+\\):\\([0-9]+\\)$") | |
613 | (cons (match-string 1) | |
614 | (string-to-int (match-string 2))) | |
615 | (error "Corrupt docstring entry in guile.texi")))))) | |
616 | (docstring-display-location (car source-location) | |
617 | (cdr source-location)))) | |
618 | ||
619 | ||
780ee65e | 620 | (provide 'docstring) |
697440cb TTN |
621 | |
622 | ;;; docstring.el ends here |