Mercurial > hg > xemacs-beta
comparison lisp/packages/webster.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;; Copyright (C) 1989 Free Software Foundation | |
2 | |
3 ;; This file is part of GNU Emacs. | |
4 | |
5 ;; GNU Emacs is distributed in the hope that it will be useful, | |
6 ;; but WITHOUT ANY WARRANTY. No author or distributor | |
7 ;; accepts responsibility to anyone for the consequences of using it | |
8 ;; or for whether it serves any particular purpose or works at all, | |
9 ;; unless he says so in writing. Refer to the GNU Emacs General Public | |
10 ;; License for full details. | |
11 | |
12 ;; Everyone is granted permission to copy, modify and redistribute | |
13 ;; GNU Emacs, but only under the conditions described in the | |
14 ;; GNU Emacs General Public License. A copy of this license is | |
15 ;; supposed to have been given to you along with GNU Emacs so you | |
16 ;; can know your rights and responsibilities. It should be in a | |
17 ;; file named COPYING. Among other things, the copyright notice | |
18 ;; and this notice must be preserved on all copies. | |
19 ;; | |
20 ;;; Synched up with: Not in FSF. | |
21 | |
22 ;; Author Jason R. Glasgow (glasgow@cs.yale.edu) | |
23 ;; Modified from telnet.el by William F. Schelter | |
24 ;; But almost entirely different. | |
25 ;; | |
26 ;; Modified by Dirk Grunwald to maintain an open connection. | |
27 ;; | |
28 ;; 3/18/89 Ashwin Ram <Ram-Ashwin@yale.edu> | |
29 ;; Added webster-mode. | |
30 ;; Fixed documentation. | |
31 ;; | |
32 ;; 3/20/89 Dirk Grunwald <grunwald@flute.cs.uiuc.edu> | |
33 ;; Merged Rams changes with new additions: smarter window placement, | |
34 ;; correctly handles un-exposed webster windows, minor cleanups. | |
35 ;; Also, ``webster-word'', akin to ``spell-word''. | |
36 ;; | |
37 ;; To use this, you might want to add this line to your .emacs file: | |
38 ;; | |
39 ;; (autoload 'webster "webster" "look up a word in Webster's 7th edition" t) | |
40 ;; | |
41 ;; Then just hit M-x webster to look up a word. | |
42 ;; | |
43 ;; 3/21/89 Dave Sill <dsill@relay.nswc.navy.mil> | |
44 ;; Removed webster-word and webster-define, adding default of current word to | |
45 ;; webster, webster-spell, and webster-endings instead. | |
46 ;; | |
47 ;; 1/21/91 Jamie Zawinski <jwz@lucid.com> | |
48 ;; Added webster-reformat to produce better looking output. Made it notice | |
49 ;; references to other words in the definitions (all upper-case) and do | |
50 ;; completion on them in the string read by meta-x webster. | |
51 ;; | |
52 ;; 9/14/91 Jamie Zawinski <jwz@lucid.com> | |
53 ;; Improved the above. | |
54 ;; | |
55 ;; 4/15/92 Jamie Zawinski <jwz@lucid.com> | |
56 ;; Improved formatting some more, and added Lucid GNU Emacs font and mouse | |
57 ;; support (mostly cannibalized from webster-ucb.el.) | |
58 | |
59 (defvar webster-host "agate.berkeley.edu" ;"129.79.254.192" | |
60 "The host to use as a webster server.") | |
61 | |
62 (defvar webster-port "2627" | |
63 "The port to connect to. Either 103 or 2627") | |
64 | |
65 (defvar webster-process nil | |
66 "The current webster process") | |
67 | |
68 (defvar webster-process-name "webster" | |
69 "The current webster process") | |
70 | |
71 (defvar webster-buffer nil | |
72 "The current webster process") | |
73 | |
74 (defvar webster-running nil | |
75 "Used to determine when connection is established") | |
76 | |
77 ;;; | |
78 ;;; Initial filter for ignoring information until successfully connected | |
79 ;;; | |
80 (defun webster-initial-filter (proc string) | |
81 (let ((this-buffer (current-buffer))) | |
82 (set-buffer webster-buffer) | |
83 (goto-char (point-max)) | |
84 (cond ((not (eq (process-status webster-process) 'run)) | |
85 (setq webster-running t) | |
86 (message "Webster died")) | |
87 ((string-match "No such host" string) | |
88 (setq webster-running t) | |
89 (kill-buffer (process-buffer proc)) | |
90 (error "No such host.")) | |
91 ((string-match "]" string) | |
92 (setq webster-running t) | |
93 (set-process-filter proc 'webster-filter))) | |
94 (set-buffer this-buffer))) | |
95 | |
96 (defvar webster-reformat t | |
97 "*Set this to t if you want the webster output to be prettied up, and | |
98 for the \\[webster] prompt to do completion across the set of words known | |
99 to be in the dictionary (words you've looked up, or which appeared in | |
100 definitions as crossreferences.)") | |
101 | |
102 (defun webster-filter (proc string) | |
103 (let ((this-buffer (current-buffer)) | |
104 (endp nil)) | |
105 (set-buffer webster-buffer) | |
106 (cond ((not (eq (process-status webster-process) 'run)) | |
107 (message "Webster died")) | |
108 ((string-match "Connection closed" string) | |
109 (message "Closing webster connection...") | |
110 (kill-process proc) | |
111 (replace-regexp "Process webster killed" "" nil) | |
112 (goto-char 1) | |
113 (message "Closing webster connection...Done.")) | |
114 ((string-match "SPELLING 0" string) | |
115 (insert "...Word not found in webster\n")) | |
116 ((string-match "SPELLING 1" string) | |
117 (insert "...Spelled correctly\n")) | |
118 ((let ((end-def-message (or (string-match "\200" string) | |
119 (string-match "\0" string)))) | |
120 (if end-def-message | |
121 (progn | |
122 (webster-filter | |
123 proc | |
124 (concat (substring string 0 (- end-def-message 1)) "\n\n")) | |
125 (setq endp t) | |
126 (goto-char (point-max)) | |
127 t)))) | |
128 (t | |
129 (goto-char (point-max)) | |
130 (let ((now (point))) | |
131 (insert string) | |
132 (delete-char-in-region now (point) "\^M" " ")) | |
133 (if (process-mark proc) | |
134 (set-marker (process-mark proc) (point))))) | |
135 (if endp | |
136 ;; if the webster window is visible, move the last line to the | |
137 ;; bottom of that window | |
138 (let ((webster-window (get-buffer-window webster-buffer)) | |
139 (window (selected-window))) | |
140 (if webster-reformat (webster-reformat (process-mark proc))) | |
141 (if webster-window | |
142 (progn | |
143 (select-window webster-window) | |
144 (goto-char (point-max)) | |
145 (recenter (1- (window-height webster-window))) | |
146 (select-window window))))))) | |
147 | |
148 (defconst webster-completion-table (make-vector 511 0)) | |
149 | |
150 (defun webster-intern (string) | |
151 (while (string-match "\\." string) | |
152 (setq string (concat (substring string 0 (match-beginning 0)) | |
153 (substring string (match-end 0))))) | |
154 (intern (downcase string) webster-completion-table)) | |
155 | |
156 (defvar webster-fontify (string-match "XEmacs" emacs-version) | |
157 "*Set to t to use the XEmacs/Lucid Emacs font-change mechanism.") | |
158 | |
159 (cond ((fboundp 'make-face) | |
160 (or (find-face 'webster) | |
161 (face-differs-from-default-p (make-face 'webster)) | |
162 (copy-face 'default 'webster)) | |
163 (or (find-face 'webster-bold) | |
164 (face-differs-from-default-p (make-face 'webster-bold)) | |
165 (copy-face 'bold 'webster-bold)) | |
166 (or (find-face 'webster-italic) | |
167 (face-differs-from-default-p (make-face 'webster-italic)) | |
168 (copy-face 'italic 'webster-italic)) | |
169 (or (find-face 'webster-bold-italic) | |
170 (face-differs-from-default-p (make-face 'webster-bold-italic)) | |
171 (copy-face 'bold-italic 'webster-bold-italic)) | |
172 (or (find-face 'webster-small) | |
173 (face-differs-from-default-p (make-face 'webster-small)) | |
174 (copy-face 'webster-bold 'webster-small)) | |
175 )) | |
176 | |
177 (defun webster-fontify (start end face &optional highlight) | |
178 (let ((e (make-extent start end (current-buffer)))) | |
179 (set-extent-face e face) | |
180 (if highlight (set-extent-property e 'highlight t)))) | |
181 | |
182 | |
183 (defun webster-reformat (end) | |
184 "Clean up the output of the webster server, and gather words for the | |
185 completion table." | |
186 (if (not webster-reformat) nil | |
187 (goto-char end) | |
188 (let ((case-fold-search nil)) | |
189 (re-search-backward "^[A-Z]+" nil t) | |
190 (if webster-fontify | |
191 (save-excursion | |
192 (previous-line 1) | |
193 (if (looking-at "^DEFINE \\([^ \n]+\\)") | |
194 (webster-fontify (match-beginning 1) (match-end 1) | |
195 'webster-bold t)))) | |
196 (cond | |
197 ((or (looking-at "^DEFINITION [0-9]") | |
198 (looking-at "^SPELLING")) | |
199 (forward-line 1) | |
200 (let ((p (point)) | |
201 (indent 2)) | |
202 (search-forward "\n\n" nil 0) | |
203 (narrow-to-region p (point)) | |
204 (goto-char p) | |
205 (while (search-forward "\n" nil t) | |
206 (delete-char -1) | |
207 (just-one-space)) | |
208 (goto-char p) | |
209 (while (not (eobp)) | |
210 (if (looking-at " *\n") | |
211 (delete-region (match-beginning 0) (match-end 0))) | |
212 (cond ((looking-at "^[0-9]+ ") | |
213 (if webster-fontify | |
214 (webster-fontify (point) (match-end 0) | |
215 'webster-bold-italic)) | |
216 (goto-char (match-end 0)) | |
217 (if (looking-at "[^\n0-9]+ [0-9]") | |
218 (save-excursion | |
219 (goto-char (1- (match-end 0))) | |
220 (insert "\n"))) | |
221 (if (looking-at "[a-z]+\\( [a-z]+\\)*[ \n]") | |
222 (webster-intern | |
223 (buffer-substring (point) (1- (match-end 0))))) | |
224 (if webster-fontify | |
225 (webster-fontify (point) (1- (match-end 0)) | |
226 'webster-bold t)) | |
227 (goto-char (1- (match-end 0))) | |
228 (if (looking-at " *\n") (forward-line 1))) | |
229 ((looking-at " *[0-9]+\\. ") | |
230 (setq indent 5) | |
231 (delete-horizontal-space) | |
232 (insert (if (= (preceding-char) ?\n) " " "\n ")) | |
233 (skip-chars-forward "0-9. ") | |
234 (if webster-fontify | |
235 (webster-fontify | |
236 (save-excursion (beginning-of-line) (point)) | |
237 (point) | |
238 'webster-bold-italic))) | |
239 ((looking-at " *\\([0-9]+\\): *") | |
240 (let ((n (buffer-substring (match-beginning 1) | |
241 (match-end 1)))) | |
242 (delete-region (match-beginning 0) (match-end 0)) | |
243 (insert "\n") | |
244 (indent-to (- 6 (length n))) | |
245 (insert n " : ") | |
246 (setq indent 9) | |
247 (if webster-fontify | |
248 (webster-fontify | |
249 (save-excursion (beginning-of-line) (point)) | |
250 (point) | |
251 'webster-bold-italic)))) | |
252 ((looking-at " *\\([0-9]+\\)\\([a-z]+\\): *") | |
253 (let ((n (buffer-substring (match-beginning 1) | |
254 (match-end 1))) | |
255 (m (buffer-substring (match-beginning 2) | |
256 (match-end 2)))) | |
257 (if (not (equal m "a")) (setq n " ")) | |
258 (delete-region (match-beginning 0) (match-end 0)) | |
259 (insert "\n") | |
260 (indent-to (- 6 (length n))) | |
261 (insert n " ") | |
262 (insert m " : ") | |
263 (setq indent 12) | |
264 (if webster-fontify | |
265 (webster-fontify | |
266 (save-excursion (beginning-of-line) (point)) | |
267 (point) | |
268 'webster-bold-italic)))) | |
269 ((looking-at " *\\([0-9]+\\)\\([a-z]+\\)\\([0-9]+\\): *") | |
270 (let ((n (buffer-substring (match-beginning 1) | |
271 (match-end 1))) | |
272 (m (buffer-substring (match-beginning 2) | |
273 (match-end 2))) | |
274 (o (buffer-substring (match-beginning 3) | |
275 (match-end 3)))) | |
276 (if (not (equal o "1")) (setq m " ")) | |
277 (if (not (equal m "a")) (setq n " ")) | |
278 (delete-region (match-beginning 0) (match-end 0)) | |
279 (insert "\n") | |
280 (indent-to (- 6 (length n))) | |
281 (insert n " ") | |
282 (insert m " ") | |
283 (insert "(" o ") : ") | |
284 (setq indent 17) | |
285 (if webster-fontify | |
286 (webster-fontify | |
287 (save-excursion (beginning-of-line) (point)) | |
288 (point) | |
289 'webster-bold-italic)))) | |
290 ((looking-at " *\\\\") | |
291 (setq indent 5) | |
292 (setq p (point)) | |
293 (goto-char (match-end 0)) | |
294 (search-forward "\\") | |
295 (if (> (current-column) fill-column) | |
296 (progn | |
297 (goto-char p) | |
298 (insert "\n") | |
299 (indent-to 18) | |
300 (search-forward "\\"))) | |
301 (if webster-fontify | |
302 (webster-fontify p (point) 'webster-italic))) | |
303 ((looking-at " *\\[") | |
304 (setq indent 6) | |
305 (delete-horizontal-space) | |
306 (insert "\n") | |
307 (indent-to 5) | |
308 (forward-char 1)) | |
309 ((and (= (preceding-char) ?\]) | |
310 (looking-at " *:")) | |
311 (delete-horizontal-space) | |
312 (setq indent 5) | |
313 (insert "\n ")) | |
314 ((looking-at " *SYN *") | |
315 (delete-region (point) (match-end 0)) | |
316 (insert "\n") | |
317 (delete-horizontal-space) | |
318 (insert " ") | |
319 (setq indent 6) | |
320 (if (looking-at "syn ") | |
321 (progn | |
322 (if webster-fontify | |
323 (webster-fontify (point) (+ (point) 3) | |
324 'webster-bold)) | |
325 (goto-char (match-end 0)) | |
326 (insert "see ")))) | |
327 (t | |
328 (setq p (point)) | |
329 (skip-chars-forward " ,:;-") | |
330 (if (or (looking-at | |
331 "\\([A-Z][-A-Z]+[A-Z]\\)\\( [A-Z][-A-Z]*[A-Z]\\)*") | |
332 (looking-at "[a-z][-a-z]*\\(\\.[a-z][-a-z]*\\)+")) | |
333 (let ((s (buffer-substring (point) (match-end 0)))) | |
334 (if webster-fontify | |
335 (webster-fontify (point) (match-end 0) | |
336 'webster-bold t)) | |
337 (while (string-match "\\." s) | |
338 (setq s (concat (substring s 0 (match-beginning 0)) | |
339 (substring s (match-end 0))))) | |
340 (webster-intern s))) | |
341 (skip-chars-forward "^ \\") | |
342 (if (> (current-column) fill-column) | |
343 (progn | |
344 (goto-char p) | |
345 (insert "\n") | |
346 (delete-horizontal-space) | |
347 (indent-to indent) | |
348 (skip-chars-forward " ") | |
349 (skip-chars-forward "^ \\") | |
350 ))) | |
351 ))) | |
352 (goto-char (point-min)) | |
353 (while (looking-at "\n") (delete-char 1)) | |
354 (goto-char (point-max)) | |
355 (insert "\n\n") | |
356 (widen)))))) | |
357 | |
358 ;; " \\(\\(slang\\|cap\\|pl\\|aj\\|av\\|n\\|v\\|vt\\|vi\\)\\(,[ \n]+\\)?\\)+\n" | |
359 | |
360 ;;; | |
361 ;;; delete char1 and char2 if it precedes char1 | |
362 ;;; used to get rid of <space><return> | |
363 (defun delete-char-in-region (start end char1 char2) | |
364 (goto-char start) | |
365 (setq char2 (aref char2 0)) | |
366 (while (search-forward char1 end t) | |
367 (delete-char -1) | |
368 (if (= (char-after (- (point) 1)) char2) | |
369 (delete-char -1)))) | |
370 | |
371 ;;;###autoload | |
372 (defun webster (arg) | |
373 "Look up a word in the Webster's dictionary. | |
374 Open a network login connection to a webster host if necessary. | |
375 Communication with host is recorded in a buffer *webster*." | |
376 (interactive (list | |
377 (let ((prompt (concat "Look up word in webster (" | |
378 (current-word) "): ")) | |
379 (completion-ignore-case t)) | |
380 (downcase | |
381 (if webster-reformat | |
382 (completing-read prompt webster-completion-table | |
383 nil nil) | |
384 (read-string prompt)))))) | |
385 (if (equal "" arg) (setq arg (current-word))) | |
386 (webster-send-request "DEFINE" arg)) | |
387 | |
388 ;;;###autoload | |
389 (defun webster-endings (arg) | |
390 "Look up endings for a word in the Webster's dictionary. | |
391 Open a network login connection to a webster host if necessary. | |
392 Communication with host is recorded in a buffer *webster*." | |
393 (interactive (list | |
394 (read-string | |
395 (concat | |
396 "Find endings for word in webster (" (current-word) "): ")))) | |
397 (if (equal "" arg) (setq arg (current-word))) | |
398 (webster-send-request "ENDINGS" arg)) | |
399 | |
400 ;;;###autoload | |
401 (defun webster-spell (arg) | |
402 "Look spelling for a word in the Webster's dictionary. | |
403 Open a network login connection to a webster host if necessary. | |
404 Communication with host is recorded in a buffer *webster*." | |
405 (interactive (list | |
406 (read-string | |
407 (concat | |
408 "Try to spell word in webster (" (current-word) "): ")))) | |
409 (if (equal "" arg) (setq arg (current-word))) | |
410 (webster-send-request "SPELL" arg)) | |
411 | |
412 (defun webster-send-request (kind word) | |
413 (require 'shell) | |
414 (let | |
415 ((webster-command (concat "open " webster-host " " webster-port "\n"))) | |
416 | |
417 (if (or | |
418 (not webster-buffer) | |
419 (not webster-process) | |
420 (not (eq (process-status webster-process) 'run))) | |
421 (progn | |
422 (message | |
423 (concat "Attempting to connect to server " webster-host "...")) | |
424 (setq webster-buffer | |
425 (if (not (fboundp 'make-shell)) ;emacs19 | |
426 (make-comint webster-process-name "telnet") | |
427 (make-shell webster-process-name "telnet"))) | |
428 (let | |
429 ((this-buffer (current-buffer))) | |
430 (set-buffer webster-buffer) | |
431 (webster-mode) | |
432 (set-buffer this-buffer)) | |
433 | |
434 (setq webster-process (get-process webster-process-name)) | |
435 (set-process-filter webster-process 'webster-initial-filter) | |
436 (process-send-string webster-process webster-command) | |
437 (setq webster-running nil); | |
438 (while (not webster-running) ; wait for feedback | |
439 (accept-process-output)))) ; | |
440 (display-buffer webster-buffer nil) | |
441 (process-send-string webster-process (concat kind " " word "\n")))) | |
442 | |
443 (defun webster-quit () | |
444 "Close connection and quit webster-mode. Buffer is not deleted." | |
445 (interactive) | |
446 (message "Closing connection to %s..." webster-host) | |
447 (kill-process webster-process) | |
448 (message "Closing connection to %s...done" webster-host) | |
449 (bury-buffer)) | |
450 | |
451 (defvar webster-mode-map nil) | |
452 | |
453 (defun webster-mode () | |
454 "Major mode for interacting with on-line Webster's dictionary. | |
455 \\{webster-mode-map} | |
456 Use webster-mode-hook for customization." | |
457 (interactive) | |
458 (kill-all-local-variables) | |
459 (setq major-mode 'webster-mode) | |
460 (setq mode-name "Webster") | |
461 (use-local-map webster-mode-map) | |
462 (run-hooks 'webster-mode-hook)) | |
463 | |
464 (if webster-mode-map | |
465 nil | |
466 (setq webster-mode-map (make-sparse-keymap)) | |
467 (define-key webster-mode-map "?" 'describe-mode) | |
468 (define-key webster-mode-map "d" 'webster) | |
469 (define-key webster-mode-map "e" 'webster-endings) | |
470 (define-key webster-mode-map "q" 'webster-quit) | |
471 (define-key webster-mode-map "s" 'webster-spell) | |
472 (if (string-match "XEmacs" emacs-version) | |
473 (define-key webster-mode-map 'button2 'webster-xref-word))) | |
474 | |
475 ;; now in simple.el | |
476 ;(defun current-word () | |
477 ; "Word cursor is over, as a string." | |
478 ; (save-excursion | |
479 ; (let (beg end) | |
480 ; (re-search-backward "\\w" nil 2) | |
481 ; (re-search-backward "\\b" nil 2) | |
482 ; (setq beg (point)) | |
483 ; (re-search-forward "\\w*\\b" nil 2) | |
484 ; (setq end (point)) | |
485 ; (buffer-substring beg end)))) | |
486 | |
487 (defun webster-xref-word (event) | |
488 "Define the highlighted word under the mouse. | |
489 Words which are known to have definitions are highlighted when the mouse | |
490 moves over them. You may define any word by selecting it with the left | |
491 mouse button and then clicking middle." | |
492 (interactive "e") | |
493 (let* ((buffer (event-buffer event)) | |
494 (extent (extent-at (event-point event) buffer 'highlight)) | |
495 text) | |
496 (cond (extent | |
497 (setq text (save-excursion | |
498 (set-buffer buffer) | |
499 (buffer-substring | |
500 (extent-start-position extent) | |
501 (extent-end-position extent))))) | |
502 ((x-selection-owner-p) ; the selection is in this emacs process. | |
503 (setq text (x-get-selection))) | |
504 (t | |
505 (error "click on a highlighted word to define"))) | |
506 (while (string-match "\\." text) | |
507 (setq text (concat (substring text 0 (match-beginning 0)) | |
508 (substring text (match-end 0))))) | |
509 (message "looking up %s..." (upcase text)) | |
510 (goto-char (point-max)) | |
511 (webster text))) |