Mercurial > hg > xemacs-beta
comparison lisp/hyperbole/kotl/klink.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 4103f0995bd7 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;!emacs | |
2 ;; | |
3 ;; FILE: klink.el | |
4 ;; SUMMARY: Implicit reference to a kcell action type, for use in koutlines. | |
5 ;; USAGE: GNU Emacs V19 Lisp Library | |
6 ;; KEYWORDS: extensions, hypermedia, outlines, wp | |
7 ;; | |
8 ;; AUTHOR: Bob Weiner & Kellie Clark | |
9 ;; | |
10 ;; ORIG-DATE: 15-Nov-93 at 12:15:16 | |
11 ;; LAST-MOD: 1-Nov-95 at 23:07:37 by Bob Weiner | |
12 ;; | |
13 ;; DESCRIPTION: | |
14 ;; | |
15 ;;; link = | |
16 ;; < pathname [, cell-ref] [, position] > | |
17 ;; < @ cell-ref > ;; In same buffer | |
18 ;; < journal-name, journal-item-number [, cell-ref] [, position] > | |
19 ;; | |
20 ;;; pathname = | |
21 ;; path ;; display path in Emacs buffer | |
22 ;; !path ;; execute pathname within a shell | |
23 ;; &path ;; execute path as a windowed program | |
24 ;; -path ;; Load as an Emacs Lisp program | |
25 ;; | |
26 ;;; cell-ref = | |
27 ;; cell - 1a, 012, 1.2, 1a=012 (both relative and absolute ids separated | |
28 ;; by an equal sign) | |
29 ;; range - 1a-5c, 1a-+3 (include 3 cells past 1a) (not yet implemented) | |
30 ;; tree - 1a+ (not yet implemented) | |
31 ;; | |
32 ;; optionally followed by a period and 1 or more relative position specs | |
33 ;; (not yet implemented): | |
34 ;; | |
35 ;; previous-cell - .b | |
36 ;; down-a-level - .d | |
37 ;; end-of-branch - .e | |
38 ;; follow-next-link - .l | |
39 ;; return-to-prev-location - .r | |
40 ;; return-to-prev-buffer - .rf | |
41 ;; sibling - .s, .2s for 2 siblings forward | |
42 ;; tail-of-tree - .t | |
43 ;; up-a-level - .u | |
44 ;; last char of cell - .f | |
45 ;; | |
46 ;; and then optionally followed by any amount of whitespace, a pipe `|' | |
47 ;; character and then one or more view specification characters. (Augment | |
48 ;; viewspec characters may be given instead, preceded by a colon. They are | |
49 ;; ignored for now.) | |
50 ;; | |
51 ;;; position (relative to cell start) = (not yet implemented) | |
52 ;; char-pos, e.g. 28 or C28 | |
53 ;; word-num, e.g. W5 | |
54 ;; line-num, e.g. L2 | |
55 ;; paragraph-num, e.g. P3 | |
56 ;; regexp-match, e.g. "regexp" | |
57 ;; | |
58 ;; DESCRIP-END. | |
59 | |
60 ;;; ************************************************************************ | |
61 ;;; Public functions | |
62 ;;; ************************************************************************ | |
63 | |
64 ;;;###autoload | |
65 (defun klink:create (reference) | |
66 "Insert at point an implicit link to REFERENCE. | |
67 REFERENCE should be a cell-ref or a string containing \"filename, cell-ref\". | |
68 See documentation for 'kcell:ref-to-id' for valid cell-ref formats." | |
69 (interactive | |
70 ;; Don't change the name or delete default-dir used here. It is referenced | |
71 ;; in "hargs.el" for argument getting. | |
72 (let ((default-dir default-directory)) | |
73 (barf-if-buffer-read-only) | |
74 (hargs:iform-read | |
75 (list 'interactive "*+LInsert link to <[file,] cell-id [|vspecs]>: ")))) | |
76 (barf-if-buffer-read-only) | |
77 ;; Reference generally is a string. It may be a list as a string, e.g. | |
78 ;; "(\"file\" \"cell\")", in which case, we remove the unneeded internal | |
79 ;; double quotes and then parse it with pattern matching. | |
80 (and (stringp reference) (> (length reference) 0) | |
81 (= (aref reference 0) ?\() | |
82 (setq reference (hypb:replace-match-string "\\\"" reference "" t))) | |
83 (let ((default-dir default-directory) | |
84 file-ref cell-ref) | |
85 (setq reference (klink:parse reference) | |
86 file-ref (car reference) | |
87 cell-ref (car (cdr reference))) | |
88 ;; Don't need filename if link is to a cell in current buffer. | |
89 (if (and file-ref (equal buffer-file-name | |
90 (expand-file-name file-ref default-directory))) | |
91 (setq file-ref nil)) | |
92 (cond (file-ref | |
93 (setq file-ref (hpath:relative-to file-ref)) | |
94 ;; "./" prefix, if any. | |
95 (if (string-match "^\\./" file-ref) | |
96 (setq file-ref (substring file-ref (match-end 0)))) | |
97 (insert "<" file-ref) | |
98 (if cell-ref (insert ", " cell-ref)) | |
99 (insert ">")) | |
100 (cell-ref (insert "<@ " cell-ref ">")) | |
101 (t (error "(klink:create) Invalid reference, '%s'" reference))))) | |
102 | |
103 (defun klink:at-p () | |
104 "Return non-nil iff point is within a klink. | |
105 See documentation for the `link-to-kotl' function for valid klink formats. | |
106 Value returned is a list of: link-label, link-start-position, and | |
107 link-end-position, (including delimiters)." | |
108 (let (bol klink referent) | |
109 (if (and | |
110 ;; If this is an OO-Browser listing buffer, ignore anything that | |
111 ;; looks like a klink, e.g. a C++ <template> class. | |
112 (if (fboundp 'br-browser-buffer-p) | |
113 (not (br-browser-buffer-p)) | |
114 t) | |
115 ;; Don't match to C/C++ lines like: #include < path > | |
116 (save-excursion | |
117 (beginning-of-line) | |
118 (setq bol (point)) | |
119 (require 'hmouse-tag) | |
120 (not (looking-at smart-c-include-regexp))) | |
121 (save-excursion | |
122 ;; Don't match Elisp print objects such as #<buffer> | |
123 (and (search-backward "<" bol t) | |
124 (/= (preceding-char) ?#) | |
125 ;; Don't match to \<(explicit)> Hyperbole buttons | |
126 (/= (char-after (1+ (point))) ?\())) | |
127 (setq klink (hbut:label-p t "<" ">" t)) | |
128 (stringp (setq referent (car klink))) | |
129 ;; Eliminate matches to e-mail address like, <user@domain>. | |
130 (not (string-match "[^<> \t\n][!&@]" referent))) | |
131 klink))) | |
132 | |
133 ;;; ************************************************************************ | |
134 ;;; Hyperbole type definitions | |
135 ;;; ************************************************************************ | |
136 | |
137 (defib klink () | |
138 "Follows a link delimited by <> to a koutline cell. | |
139 See documentation for the `link-to-kotl' function for valid klink formats." | |
140 (let* ((link-and-pos (klink:at-p)) | |
141 (link (car link-and-pos)) | |
142 (start-pos (car (cdr link-and-pos)))) | |
143 (if link | |
144 (progn (ibut:label-set link-and-pos) | |
145 (hact 'klink:act link start-pos))))) | |
146 | |
147 (defact link-to-kotl (link) | |
148 "Displays at the top of another window the referent pointed to by LINK. | |
149 LINK may be of any of the following forms, with or without delimiters: | |
150 < pathname [, cell-ref] > | |
151 < [-!&] pathname > | |
152 < @ cell-ref > | |
153 | |
154 See documentation for 'kcell:ref-to-id' for valid cell-ref formats." | |
155 | |
156 (interactive "sKotl link specifier: ") | |
157 (or (stringp link) (error "(link-to-kotl): Non-string link argument, %s" | |
158 link)) | |
159 (cond | |
160 ((or (string-match (format "\\`<?\\s *@\\s *\\(%s\\)\\s *>?\\'" | |
161 klink:cell-ref-regexp) link) | |
162 (string-match (format "\\`<?\\s *\\([|:]%s\\)\\s *>?\\'" | |
163 klink:cell-ref-regexp) link)) | |
164 ;; < @ cell-ref > or < |viewspec > or < :augment-viewspec > | |
165 (hact 'link-to-kcell | |
166 nil | |
167 (kcell:ref-to-id | |
168 (substring link (match-beginning 1) (match-end 1))))) | |
169 ((string-match | |
170 (format "\\`<?\\s *\\([^ \t\n,<>]+\\)\\s *\\(,\\s *\\(%s\\)\\)?\\s *>?\\'" | |
171 klink:cell-ref-regexp) | |
172 link) | |
173 ;; < pathname [, cell-ref] > | |
174 (hact 'link-to-kcell | |
175 (substring link (match-beginning 1) (match-end 1)) | |
176 (if (match-end 3) | |
177 (kcell:ref-to-id | |
178 (substring link (match-beginning 3) (match-end 3)))))) | |
179 ((string-match | |
180 "\\`<?\\s *\\(\\([-!&]\\)?\\s *[^ \t\n,<>]+\\)\\s *>?\\'" link) | |
181 ;; < [-!&] pathname > | |
182 (hpath:find-other-window | |
183 (substring link (match-beginning 1) (match-end 1)))) | |
184 (t (error "(link-to-kotl): Invalid link specifier, %s" link)))) | |
185 | |
186 ;;; ************************************************************************ | |
187 ;;; Private functions | |
188 ;;; ************************************************************************ | |
189 | |
190 (defun klink:act (link start-pos) | |
191 (let ((obuf (current-buffer))) | |
192 ;; Perform klink's action which is to jump to link referent. | |
193 (hact 'link-to-kotl link) | |
194 ;; Update klink label if need be, which might be in a different buffer | |
195 ;; than the current one. | |
196 (klink:update-label link start-pos obuf))) | |
197 | |
198 (defun klink:parse (reference) | |
199 "Returns (file-ref cell-ref) list parsed from REFERENCE string. | |
200 Either element of the list may be nil if REFERENCE does not contain that | |
201 element. REFERENCE should be one of the following forms (and may include an | |
202 optional pair of <> delimiters: | |
203 (pathname, cell-ref) | |
204 pathname, cell-ref | |
205 cell-ref | |
206 |viewspec | |
207 :augment-viewspec (ignored for now) | |
208 | |
209 See documentation for 'kcell:ref-to-id' for valid cell-ref formats." | |
210 | |
211 (or (stringp reference) | |
212 (error "(klink:parse): Non-string reference argument, %s" | |
213 reference)) | |
214 (cond | |
215 ((string-match | |
216 (format | |
217 "\\`\\s *[<\(]?\\s *\\([^|: \t\n\r,<>][^ \t\n\r,<>]*\\)\\s *,\\s *\\(%s\\)\\s *[\)>]?\\s *\\'" | |
218 klink:cell-ref-regexp) | |
219 reference) | |
220 ;; pathname cell-ref | |
221 (list (substring reference (match-beginning 1) (match-end 1)) | |
222 (substring reference (match-beginning 2) (match-end 2)))) | |
223 ((string-match (format "\\`\\s *<?\\s *\\(%s\\)\\s *>?\\s *\\'" | |
224 klink:cell-ref-regexp) | |
225 reference) | |
226 ;; cell-ref | |
227 (list nil (substring reference (match-beginning 1) (match-end 1)))) | |
228 (t (error "(klink:parse): Invalid reference specifier, %s" reference)))) | |
229 | |
230 (defun klink:replace-label (klink link-buf start new-label) | |
231 "Replace out of date relative id in a link reference of the form, relid=idstamp." | |
232 (save-excursion | |
233 (set-buffer link-buf) | |
234 (if buffer-read-only | |
235 (message "Relative label should be `%s' in klink <%s>." | |
236 new-label klink) | |
237 (goto-char start) | |
238 (cond ((or (looking-at "<\\s *@\\s *") | |
239 (looking-at "[^,]+,\\s *")) | |
240 (goto-char (match-end 0)) | |
241 (zap-to-char 1 ?=) | |
242 (insert new-label ?=)) | |
243 (t nil))))) | |
244 | |
245 (defun klink:update-label (klink start link-buf) | |
246 "Update label of KLINK if its relative cell id has changed. | |
247 Assume point is in klink referent buffer, where the klink points." | |
248 (if (and (stringp klink) | |
249 (string-match | |
250 "[@,]\\s *\\([*0-9][*.0-9a-zA-Z]*\\)\\s *=\\s *0[0-9]*" | |
251 klink)) | |
252 ;; Then klink has both relative and permanent ids. | |
253 (let* ((label (substring klink (match-beginning 1) (match-end 1))) | |
254 (new-label (kcell-view:label))) | |
255 (if (and new-label (not (equal label new-label))) | |
256 (klink:replace-label klink link-buf start new-label))))) | |
257 | |
258 ;;; ************************************************************************ | |
259 ;;; Private variables. | |
260 ;;; ************************************************************************ | |
261 | |
262 (defvar klink:cell-ref-regexp | |
263 "[|:0-9a-zA-Z][|:.*~=0-9a-zA-Z \t\n\r]*" | |
264 "Regexp matching a cell reference including relative and view specs. | |
265 Contains no groupings.") | |
266 | |
267 (provide 'klink) |