1 ;;; hibtypes.el --- Hyperbole System Implicit Button Types.
3 ;; Copyright (C) 2004, 2008 Free Software Foundation, Inc.
4 ;; Developed with support from Motorola Inc.
6 ;; Author: Bob Weiner, Brown U.
7 ;; Maintainer: Mats Lidell <matsl@contactor.se>
8 ;; Keywords: extensions, hypermedia
10 ;; This file is part of GNU Hyperbole.
12 ;; GNU Hyperbole is free software; you can redistribute it and/or
13 ;; modify it under the terms of the GNU General Public License as
14 ;; published by the Free Software Foundation; either version 3, or (at
15 ;; your option) any later version.
17 ;; GNU Hyperbole is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ;; General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
32 ;;; Other required Elisp libraries
38 ;;; Public implicit button types
41 (run-hooks 'hibtypes:begin-load-hook)
44 ;;; Follows URLs by invoking a browser.
50 ;;; Handles internal references within an annotated bibliography, delimiters=[]
54 "Displays annotated bibliography entries referenced internally.
55 References must be delimited by square brackets, must begin with a word
56 constituent character, and must not be in buffers whose names begin with a
57 ' ' or '*' character or which do not have an attached file."
60 (let ((chr (aref (buffer-name) 0)))
61 (not (or (= chr ? ) (= chr ?*))))
62 (let* ((ref-and-pos (hbut:label-p t "[" "]" t))
63 (ref (car ref-and-pos)))
64 (and ref (= ?w (char-syntax (aref ref 0)))
65 (progn (ibut:label-set ref-and-pos)
66 (hact 'annot-bib ref))))))
69 ;;; Summarizes an Internet rfc for random access browsing by section.
73 "Summarizes contents of an Internet rfc from anywhere within rfc buffer.
74 Each line in summary may be selected to jump to section."
75 (let ((case-fold-search t)
78 (if (and (string-match "rfc" (buffer-name))
79 (goto-char (point-min))
80 (progn (setq toc (search-forward "Table of Contents" nil t))
81 (re-search-forward "^[ \t]*1.0?[ \t]+[^ \t\n]" nil t
83 (progn (beginning-of-line)
84 (ibut:label-set (buffer-name))
85 (hact 'rfc-toc (buffer-name) opoint))
90 ;;; Jumps to C/C++ source line associated with Cscope C analyzer output line.
94 "Jumps to C/C++ source line associated with Cscope C analyzer output line.
95 Requires pre-loading of the cscope.el Lisp library available from the Emacs
96 Lisp archives and the commercial cscope program available from UNIX System
97 Laboratories. Otherwise, does nothing."
98 (and (boundp 'cscope:bname-prefix) ;; (featurep 'cscope)
99 (stringp cscope:bname-prefix)
100 (string-match (regexp-quote cscope:bname-prefix)
102 (= (match-beginning 0) 0)
105 (looking-at cscope-output-line-regexp))
107 (skip-chars-backward "^\n\^M")
109 (skip-chars-forward "^\n\^M")
111 (ibut:label-set (buffer-substring start end)
113 (hact 'cscope-interpret-output-line))))
116 ;;; Makes README table of contents entries jump to associated sections.
120 "Jumps to the text file section referenced by a table of contents entry at point.
121 File name must contain README and there must be a `Table of Contents' or
122 `Contents' label on a line by itself (it may begin with an asterisk),
123 preceding the table of contents. Each toc entry must begin with some
124 whitespace followed by one or more asterisk characters. Each file section
125 name line must start with one or more asterisk characters at the very
126 beginning of the line."
128 (if (and (string-match "README" (buffer-name))
132 "[ \t]+\\*+[ \t]+\\(.*[^ \t]\\)[ \t]*$")
133 (setq section (buffer-substring (match-beginning 1)
135 (progn (ibut:label-set section (match-beginning 1) (match-end 1))
137 (save-excursion (re-search-backward
138 "^\\**[ \t]*\\(\\|Table of \\)Contents[ \t]*$"
140 (hact 'text-toc section))))
143 ;;; Makes directory summaries into file list menus.
146 (defib dir-summary ()
147 "Detects filename buttons in files named \"MANIFEST\" or \"DIR\".
148 Displays selected files. Each file name must be at the beginning of the line
149 or may be preceded by some semicolons and must be followed by one or more
150 spaces and then another non-space, non-parenthesis, non-brace character."
152 (let ((file (file-name-nondirectory buffer-file-name))
154 (if (or (string= file "DIR") (string= file "MANIFEST"))
158 "\\(;+[ \t]*\\)?\\([^(){}* \t\n]+\\)[ \t]+[^(){}* \t\n]")
160 (setq entry (buffer-substring
161 (match-beginning 2) (match-end 2))
162 start (match-beginning 2)
164 (if (file-exists-p entry)
165 (progn (ibut:label-set entry start end)
166 (hact 'link-to-file entry))))))))))
169 ;;; Executes or documents command bindings of brace delimited key sequences.
175 ;;; Makes Internet RFC references retrieve the RFC.
179 "Retrieves and displays an Internet rfc referenced at point.
180 Requires ange-ftp or efs when needed for remote retrievals. The following
181 formats are recognized: RFC822, rfc-822, and RFC 822. The 'hpath:rfc'
182 variable specifies the location from which to retrieve RFCs."
183 (let ((case-fold-search t)
185 (and (not (memq major-mode '(dired-mode monkey-mode)))
189 (skip-chars-backward "-rRfFcC0-9")
190 (if (looking-at "rfc[- ]?\\([0-9]+\\)")
194 (match-beginning 1) (match-end 1)))
196 (buffer-substring (match-beginning 0) (match-end 0)))
198 ;; Ensure ange-ftp is available for retrieving a remote
200 (if (string-match "^/.+:" hpath:rfc)
201 ;; This is a remote path.
202 (hpath:ange-ftp-available-p)
205 (hact 'link-to-rfc rfc-num))))
208 ;;; Makes Hyperbole mail addresses output Hyperbole envir info.
211 (defib hyp-address ()
212 "Turns a Hyperbole e-mail list address into an implicit button which inserts Hyperbole environment information.
213 Useful when sending mail to a Hyperbole mail list.
214 See also the documentation for `actypes::hyp-config'."
215 (if (memq major-mode (list hmail:composer hnews:composer))
216 (let ((addr (find-tag-default)))
217 (cond ((set:member addr (list "hyperbole" "hyperbole-users@gnu.org"))
222 ;;; Makes source entries in Hyperbole reports selectable.
226 "Turns source location entries in Hyperbole reports into buttons that jump to the associated location."
229 (if (looking-at hbut:source-prefix)
230 (let ((src (hbut:source)))
232 (progn (if (not (stringp src)) (setq src (prin1-to-string src)))
233 (ibut:label-set src (point) (progn (end-of-line) (point)))
234 (hact 'hyp-source src)))))))
237 ;;; Shows man page associated with a man apropos entry.
240 (defib man-apropos ()
241 "Makes man apropos entries display associated man pages when selected."
244 (let ((nm "[^ \t\n!@,][^ \t\n,]*")
248 "^\\(\\*[ \t]+[!@]\\)?\\(" nm "[ \t]*,[ \t]*\\)*\\(" nm "\\)[ \t]*"
249 "\\(([-0-9a-zA-z]+)\\)\\(::\\)?[ \t]+-[ \t]+[^ \t\n]"))
251 (concat (buffer-substring (match-beginning 3) (match-end 3))
252 (buffer-substring (match-beginning 4) (match-end 4))))
253 (ibut:label-set topic (match-beginning 3) (match-end 4))
254 (hact 'man-show topic)))))
257 ;;; Follows links to Hyperbole outliner cells.
260 (if hyperb:kotl-p (require 'klink))
263 ;;; Displays files and directories when double quoted pathname is activated.
267 "Makes a delimited, valid pathname display the path entry.
268 Also works for delimited and non-delimited ange-ftp and efs pathnames.
269 See `hpath:at-p' function documentation for possible delimiters.
270 See `hpath:suffixes' variable documentation for suffixes that are added to or
271 removed from pathname when searching for a valid match.
272 See `hpath:find' function documentation and `hpath:display-alist' and
273 `hpath:find-alist' variable documentation for special file display options."
274 (let ((path (hpath:at-p)))
276 (progn (ibut:label-set path)
277 (hact 'link-to-file path)))))
280 ;;; Jumps to source line associated with debugger stack frame or breakpoint
281 ;;; lines. Supports gdb, dbx, and xdb.
284 (defib debugger-source ()
285 "Jumps to source line associated with debugger stack frame or breakpoint lines.
286 This works with gdb, dbx, and xdb. Such lines are recognized in any buffer."
289 (cond ((looking-at ".+ \\(at\\|file\\) \\([^ :]+\\):\\([0-9]+\\)\\.?$")
291 (let* ((file (buffer-substring (match-beginning 2)
293 (line-num (buffer-substring (match-beginning 3)
295 (but-label (concat file ":" line-num)))
296 (setq line-num (string-to-number line-num))
297 (ibut:label-set but-label)
298 (hact 'link-to-file-line file line-num)))
299 ((looking-at ".+ (file=[^\"\n]+\"\\([^\"\n]+\\)\", line=\\([0-9]+\\),")
300 ;; XEmacs assertion failure
301 (let* ((file (buffer-substring (match-beginning 1)
303 (line-num (buffer-substring (match-beginning 2)
305 (but-label (concat file ":" line-num)))
306 (setq line-num (string-to-number line-num))
307 (ibut:label-set but-label)
308 (hact 'link-to-file-line file line-num)))
309 ((looking-at ".+ line \\([0-9]+\\) in \"\\([^\"]+\\)\"$")
311 (let* ((file (buffer-substring (match-beginning 2)
313 (line-num (buffer-substring (match-beginning 1)
315 (but-label (concat file ":" line-num)))
316 (setq line-num (string-to-number line-num))
317 (ibut:label-set but-label)
318 (hact 'link-to-file-line file line-num)))
319 ((or (looking-at ".+ \\[\"\\([^\"]+\\)\":\\([0-9]+\\),") ;; Old DBX
320 (looking-at ".+ \\[\\([^: ]+\\): \\([0-9]+\\)\\]")) ;; HP-UX xdb
321 (let* ((file (buffer-substring (match-beginning 1)
323 (line-num (buffer-substring (match-beginning 2)
325 (but-label (concat file ":" line-num)))
326 (setq line-num (string-to-number line-num))
327 (ibut:label-set but-label)
328 (hact 'link-to-file-line file line-num))))))
331 ;;; Jumps to source line associated with grep or compilation error messages.
332 ;;; With credit to Michael Lipp and Mike Williams for the idea.
336 "Jumps to line associated with grep or compilation error msgs.
337 Messages are recognized in any buffer."
339 (if (equal (buffer-name) "*compilation*")
342 ;; Make sure we have a parsed error-list
343 (if (eq compilation-error-list t)
344 (progn (compilation-forget-errors)
345 (setq compilation-parsing-end 1)))
346 (if (not compilation-error-list)
348 (set-buffer-modified-p nil)
350 ;; Emacs V19 incompatibly adds two non-optional arguments
352 (compilation-parse-errors nil nil)
353 (error (compilation-parse-errors)))))))
354 ;; Locate and parse grep messages found in any buffer.
358 ;; UNIX C compiler and Introl 68HC11 C compiler errors
359 (looking-at "\\([^ \t\n\^M:]+\\): ?\\([0-9]+\\)[ :]")
360 ;; BSO/Tasking 68HC08 C compiler errors
362 "[a-zA-Z 0-9]+: \\([^ \t\n\^M]+\\) line \\([0-9]+\\)[ \t]*:")
364 (looking-at "[^:]+: \\([^ \t\n\^M:]+\\): line \\([0-9]+\\):")
365 ;; SparcWorks C compiler errors (ends with :)
366 ;; IBM AIX xlc C compiler errors (ends with .)
367 (looking-at "\"\\([^\"]+\\)\", line \\([0-9]+\\)[:.]")
368 ;; Introl as11 assembler errors
369 (looking-at " \\*+ \\([^ \t\n\^M]+\\) - \\([0-9]+\\) ")
370 ;; perl5: ... at file.c line 10
371 (looking-at ".+ at \\([^ \t\n]+\\) line +\\([0-9]+\\)")
373 (let* ((file (buffer-substring (match-beginning 1)
375 (line-num (buffer-substring (match-beginning 2)
377 (but-label (concat file ":" line-num))
378 (source-loc (hbut:key-src t)))
379 (if (stringp source-loc)
380 (setq file (expand-file-name
381 file (file-name-directory source-loc))))
382 (setq line-num (string-to-number line-num))
383 (ibut:label-set but-label)
384 (hact 'link-to-file-line file line-num))))))
387 ;;; Jumps to source of Emacs Lisp V19 byte-compiler error messages.
390 (defib elisp-compiler-msg ()
391 "Jumps to source code for definition associated with byte-compiler error message.
392 Works when activated anywhere within an error line."
393 (if (or (equal (buffer-name) "*Compile-Log*")
394 (equal (buffer-name) "*compilation*")
396 (and (re-search-backward "^[^ \t\n\r]" nil t)
397 (looking-at "While compiling"))))
398 (let (src buffer-p label)
401 "^While compiling [^\t\n]+ in \\(file\\|buffer\\) \\([^ \n]+\\):$"
404 (equal (buffer-substring (match-beginning 1) (match-end 1))
406 src (buffer-substring (match-beginning 2) (match-end 2)))
409 (re-search-backward "^While compiling \\([^ \n]+\\)\\(:$\\| \\)"
412 (setq label (buffer-substring
413 (match-beginning 1) (match-end 1)))
414 (ibut:label-set label (match-beginning 1) (match-end 1))
415 ;; Remove prefix generated by actype and ibtype definitions.
416 (setq label (hypb:replace-match-string "[^:]+::" label "" t))
417 (hact 'link-to-regexp-match
418 (concat "^\(def[a-z \t]+" (regexp-quote label)
423 ;;; Jumps to source associated with a line of output from 'patch'.
427 "Jumps to source code associated with output from the 'patch' program.
428 Patch applies diffs to source code."
431 (looking-at "Patching \\|Hunk "))
432 (let ((opoint (point))
435 (cond ((looking-at "Hunk .+ at \\([0-9]+\\)")
436 (setq line (buffer-substring (match-beginning 1)
438 (ibut:label-set line (match-beginning 1) (match-end 1))
439 (if (re-search-backward "^Patching file \\(\\S +\\)" nil t)
440 (setq file (buffer-substring (match-beginning 1)
442 ((looking-at "Patching file \\(\\S +\\)")
443 (setq file (buffer-substring (match-beginning 1)
446 (ibut:label-set file (match-beginning 1) (match-end 1))))
450 (setq line (string-to-number line))
451 (hact 'link-to-file-line file line)))))
454 ;;; Composes mail, in another window, to the e-mail address at point.
457 (defib mail-address ()
458 "If on an e-mail address in a specific buffer type, mail to that address in another window.
459 Applies to the rolodex match buffer, any buffer attached to a file in
460 'rolo-file-list', or any buffer with \"mail\" or \"rolo\" (case-insensitive)
462 (if (or (and (let ((case-fold-search t))
463 (string-match "mail\\|rolo" (buffer-name)))
464 ;; Don't want this to trigger in a mail/news summary buffer.
465 (not (or (hmail:lister-p) (hnews:lister-p))))
466 (if (boundp 'rolo-display-buffer)
467 (equal (buffer-name) rolo-display-buffer))
468 (and buffer-file-name
469 (boundp 'rolo-file-list)
470 (set:member (current-buffer)
471 (mapcar 'get-file-buffer rolo-file-list))))
472 (let ((address (mail-address-at-p)))
475 (ibut:label-set address (match-beginning 1) (match-end 1))
476 (hact 'mail-other-window nil address))))))
478 (defconst mail-address-regexp
479 "\\([_a-zA-Z][-_a-zA-Z0-9.!@+%]*@[-_a-zA-Z0-9.!@+%]+\\.[a-zA-Z][-_a-zA-Z][-_a-zA-Z]?\\|[a-zA-Z][-_a-zA-Z0-9.!+%]+@[-_a-zA-Z0-9@]+\\)\\($\\|[^a-zA-Z0-9.!@%]\\)"
480 "Regexp with group 1 matching an Internet email address.")
482 (defun mail-address-at-p ()
483 "Return e-mail address, a string, that point is within or nil."
485 (skip-chars-backward "^ \t\n\^M\"\'(){}[];<>|")
486 (if (looking-at mail-address-regexp)
487 (buffer-substring (match-beginning 1) (match-end 1)))))
490 ;;; Displays Info nodes when double quoted "(file)node" button is activated.
494 "Makes \"(file)node\" buttons display the associated Info node."
495 (let* ((node-ref-and-pos (hbut:label-p t "\"" "\"" t))
496 (node-ref (hpath:is-p (car node-ref-and-pos) nil t)))
497 (and node-ref (string-match "([^\)]+)" node-ref)
498 (ibut:label-set node-ref-and-pos)
499 (hact 'link-to-Info-node node-ref))))
502 ;;; Inserts completion into minibuffer or other window.
506 "Inserts completion at point into minibuffer or other window."
507 (let ((completion (hargs:completion t)))
509 (ibut:label-set completion)
510 (hact 'completion))))
513 (run-hooks 'hibtypes:end-load-hook)
516 ;;; hibtypes.el ends here