~ubuntu-branches/ubuntu/trusty/librep/trusty

« back to all changes in this revision

Viewing changes to lisp/rep/util/ispell.jl

  • Committer: Bazaar Package Importer
  • Author(s): Christian Marillat
  • Date: 2001-11-13 15:06:22 UTC
  • Revision ID: james.westby@ubuntu.com-20011113150622-vgmgmk6srj3kldr3
Tags: upstream-0.15.2
ImportĀ upstreamĀ versionĀ 0.15.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#| ispell.jl -- ispell wrapper
 
2
 
 
3
   $Id: ispell.jl,v 1.5 2000/09/10 20:03:17 john Exp $
 
4
 
 
5
   Copyright (C) 2000 John Harper <john@dcs.warwick.ac.uk>
 
6
 
 
7
   This file is part of librep.
 
8
 
 
9
   librep is free software; you can redistribute it and/or modify it
 
10
   under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation; either version 2, or (at your option)
 
12
   any later version.
 
13
 
 
14
   librep is distributed in the hope that it will be useful, but
 
15
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with librep; see the file COPYING.  If not, write to
 
21
   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
22
|#
 
23
 
 
24
(define-structure rep.util.ispell
 
25
 
 
26
    (export ispell-start
 
27
            ispell-stop
 
28
            ispell-word
 
29
            ispell-test-word
 
30
            ispell-set-dictionary
 
31
            ispell-add-word-to-dictionary
 
32
            ispell-add-word-for-session
 
33
            ispell-save-dictionary)
 
34
 
 
35
    (open rep
 
36
          rep.regexp
 
37
          rep.io.processes
 
38
          rep.system)
 
39
 
 
40
  (defvar *ispell-program* "ispell"
 
41
    "Filename of program used to start ispell(1).")
 
42
 
 
43
  (defvar *ispell-options* nil
 
44
    "List of options to pass to Ispell")
 
45
 
 
46
  (defvar *ispell-dictionary* nil
 
47
    "Name of dictionary to pass to Ispell, or nil for the default.")
 
48
 
 
49
  (defvar *ispell-timeout* 5
 
50
    "Seconds to wait for ispell output before giving up.")
 
51
 
 
52
  (defvar *ispell-echo-output* nil
 
53
    "Use for debugging only.")
 
54
 
 
55
  (define process nil
 
56
    "Subprocess that ispell is running in, or nil if ispell isn't running.")
 
57
 
 
58
  (define process-busy nil
 
59
    "When t, the process is being used to check a word, but not all
 
60
results have been received.")
 
61
 
 
62
  (define id-string nil
 
63
    "String sent by ispell identifying itself when it started executing.")
 
64
 
 
65
  (define pending-output nil
 
66
    "String of output received from ispell but not processed.")
 
67
 
 
68
  (define line-callback (make-fluid nil)
 
69
    "Function to call asynchronously with a single line of output from ispell.")
 
70
 
 
71
;;; Process management
 
72
 
 
73
  ;; Function to buffer output from Ispell
 
74
  (define (output-filter output)
 
75
    (when (integerp output)
 
76
      (setq output (make-string 1 output)))
 
77
    (and *ispell-echo-output*
 
78
         (stringp output)
 
79
         (let ((print-escape t))
 
80
           (format standard-error "Ispell: %S\n" output)))
 
81
    (setq pending-output (concat pending-output output))
 
82
    (while (and (fluid line-callback)
 
83
                pending-output
 
84
                (string-match "\n" pending-output))
 
85
      (let ((line (substring pending-output 0 (match-end))))
 
86
        (setq pending-output (substring pending-output (match-end)))
 
87
        ((fluid line-callback) line))))
 
88
 
 
89
  ;; Start the process if it isn't already
 
90
  (define (ispell-start)
 
91
    (unless process
 
92
      (setq process (make-process output-filter))
 
93
      (set-process-function process (lambda ()
 
94
                                      (setq process nil)
 
95
                                      (setq id-string nil)))
 
96
      ;; Use a pty if possible. This allow EOF to be sent via ^D
 
97
      (set-process-connection-type process 'pty)
 
98
      (apply start-process process *ispell-program* "-a"
 
99
             (nconc (and *ispell-dictionary*
 
100
                         (list "-d" *ispell-dictionary*))
 
101
                    *ispell-options*))
 
102
      (setq pending-output nil)
 
103
      (fluid-set line-callback nil)
 
104
      (setq id-string (ispell-read-line))
 
105
      (unless (string-match "ispell version" id-string 0 t)
 
106
        (ispell-stop)
 
107
        (error "Ispell: %s" id-string))))
 
108
 
 
109
  (define (ispell-stop)
 
110
    "Kill any subprocesses being used internally to run Ispell."
 
111
    (accept-process-output-1 process 0) ;in case the process already died
 
112
    (when process
 
113
      (ispell-save-dictionary)
 
114
      (if (eq (process-connection-type process) 'pty)
 
115
          (write process ?\^D)
 
116
        ;; Not so successful..
 
117
        (interrupt-process process))
 
118
      (let ((counter 0))
 
119
        (while (and (accept-process-output-1 process *ispell-timeout*) process)
 
120
          (if (< counter 2)
 
121
              (interrupt-process process)
 
122
            (kill-process process))
 
123
          (setq counter (1+ counter))))))
 
124
 
 
125
  ;; Read one whole line from the process (including newline)
 
126
  (define (ispell-read-line)
 
127
    (let ((out nil))
 
128
      (let-fluids ((line-callback (lambda (l)
 
129
                                    (setq out l)
 
130
                                    ;; Only want the first line
 
131
                                    (fluid-set line-callback nil))))
 
132
        ;; Flush any pending output
 
133
        (output-filter nil)
 
134
        (while (and (not out) process
 
135
                    (not (accept-process-output-1 process *ispell-timeout*))))
 
136
        (or out (error "Ispell timed out waiting for output")))))
 
137
 
 
138
  ;; put in the before-exit-hook
 
139
  (define (before-exit)
 
140
    (when process
 
141
      (ispell-stop)))
 
142
 
 
143
  (add-hook 'before-exit-hook before-exit)
 
144
 
 
145
  ;; Arbitrate access to the Ispell process, the mutex must be obtained
 
146
  ;; before sending a command that generates output. An error is signalled
 
147
  ;; if the process is busy
 
148
  (define (mutex grab)
 
149
    (if grab
 
150
        (if process-busy
 
151
            (error "Ispell process is busy!")
 
152
          (ispell-start)
 
153
          (setq process-busy t))
 
154
      (setq process-busy nil)))
 
155
 
 
156
  ;; Check a word with Ispell. Returns the raw (single-line) output
 
157
  ;; see ispell(1) for details (under the -a option)
 
158
  (define (ispell-word word)
 
159
    (let (response tem)
 
160
      (mutex t)
 
161
      (unwind-protect
 
162
          (progn
 
163
            (format process "%s\n" word)
 
164
            (setq response (ispell-read-line))
 
165
            (if (eq (aref response 0) ?\n)
 
166
                ;; This shouldn't happen
 
167
                (error "Null output from Ispell")
 
168
              ;; Gobble following blank line
 
169
              (setq tem (ispell-read-line))
 
170
              (unless (eq (aref tem 0) ?\n)
 
171
                (error "Non-null trailing line from Ispell"))))
 
172
        (mutex nil))
 
173
      response))
 
174
 
 
175
  ;; return true if WORD is spelt correctly
 
176
  (define (ispell-test-word word)
 
177
    (let ((response (ispell-word word)))
 
178
      (string-looking-at "^[*+-]" response)))
 
179
 
 
180
;;; Dictionary management
 
181
 
 
182
  (define (ispell-set-dictionary dict-name)
 
183
    "Set the name of the dictionary used by Ispell to DICT-NAME."
 
184
    (setq *ispell-dictionary* dict-name)
 
185
    (when process
 
186
      (ispell-stop)
 
187
      (ispell-start))
 
188
    (call-hook '*ispell-dictionary-changed*))
 
189
 
 
190
  (define (ispell-add-word-to-dictionary word)
 
191
    "Add the string WORD to your personal Ispell dictionary."
 
192
    (ispell-start)
 
193
    (format process "*%s\n" word)
 
194
    (call-hook '*ispell-dictionary-changed*))
 
195
 
 
196
  (define (ispell-add-word-for-session word)
 
197
    "Add the string WORD to Ispell's per-session dictionary."
 
198
    (ispell-start)
 
199
    (format process "@%s\n" word)
 
200
    (call-hook '*ispell-dictionary-changed*))
 
201
 
 
202
  (define (ispell-save-dictionary)
 
203
    "Make Ispell save the current personal dictionary to its file."
 
204
    (when process
 
205
      (write process "#\n"))))