[gforth] / gforth / gforth.el  

gforth: gforth/gforth.el


1 : anton 1.17 ;; Forth mode for Emacs
2 : anton 1.31
3 :     ;; Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
4 :    
5 :     ;; This file is part of Gforth.
6 : anton 1.1
7 : anton 1.17 ;; GForth is distributed in the hope that it will be useful,
8 : anton 1.1 ;; but WITHOUT ANY WARRANTY. No author or distributor
9 :     ;; accepts responsibility to anyone for the consequences of using it
10 :     ;; or for whether it serves any particular purpose or works at all,
11 :     ;; unless he says so in writing. Refer to the GNU Emacs General Public
12 :     ;; License for full details.
13 :    
14 :     ;; Everyone is granted permission to copy, modify and redistribute
15 :     ;; GNU Emacs, but only under the conditions described in the
16 :     ;; GNU Emacs General Public License. A copy of this license is
17 : anton 1.17 ;; supposed to have been given to you along with Gforth so you
18 : anton 1.1 ;; can know your rights and responsibilities. It should be in a
19 :     ;; file named COPYING. Among other things, the copyright notice
20 :     ;; and this notice must be preserved on all copies.
21 : anton 1.31
22 :     ;; Changes by anton
23 :     ;; This is a variant of forth.el that came with TILE.
24 :     ;; I left most of this stuff untouched and made just a few changes for
25 :     ;; the things I use (mainly indentation and syntax tables).
26 :     ;; So there is still a lot of work to do to adapt this to gforth.
27 : anton 1.1
28 :     ;;-------------------------------------------------------------------
29 :     ;; A Forth indentation, documentation search and interaction library
30 :     ;;-------------------------------------------------------------------
31 :     ;;
32 :     ;; Written by Goran Rydqvist, gorry@ida.liu.se, Summer 1988
33 :     ;; Started: 16 July 88
34 :     ;; Version: 2.10
35 :     ;; Last update: 5 December 1989 by Mikael Patel, mip@ida.liu.se
36 :     ;; Last update: 25 June 1990 by Goran Rydqvist, gorry@ida.liu.se
37 :     ;;
38 :     ;; Documentation: See forth-mode (^HF forth-mode)
39 :     ;;-------------------------------------------------------------------
40 :    
41 :    
42 :     (defvar forth-positives
43 : anton 1.36 " : :noname m: :m code interpretation: ;code does> begin do ?do +do -do u+do u-do while if ?dup-if ?dup-0=-if else case of struct [if] [ifdef] [ifundef] [else] with public: private: class try recover "
44 : anton 1.34 "*Contains all words which will cause the indent-level to be incremented
45 : anton 1.1 on the next line.
46 :     OBS! All words in forth-positives must be surrounded by spaces.")
47 :    
48 :     (defvar forth-negatives
49 : anton 1.36 " ; ;m end-code ;code does> until repeat while +loop loop -loop s+loop else then endif again endcase endof end-struct [then] [else] [endif] endwith end-class class; how: recover endtry "
50 : anton 1.34 "*Contains all words which will cause the indent-level to be decremented
51 : anton 1.1 on the current line.
52 :     OBS! All words in forth-negatives must be surrounded by spaces.")
53 :    
54 :     (defvar forth-zeroes
55 : pazsan 1.29 " : :noname code interpretation: public: private: how: implements class class; "
56 : anton 1.34 "*Contains all words which causes the indent to go to zero")
57 : anton 1.1
58 : pazsan 1.21 (setq forth-zero 0)
59 :    
60 :     (defvar forth-zup
61 : pazsan 1.25 " how: implements "
62 : pazsan 1.21 "Contains all words which causes zero indent level to change")
63 :    
64 :     (defvar forth-zdown
65 :     " class; how: class public: private: "
66 :     "Contains all words which causes zero indent level to change")
67 :    
68 : anton 1.6 (defvar forth-prefixes
69 :     " postpone [compile] ['] [char] "
70 :     "words that prefix and escape other words")
71 :    
72 : anton 1.1 (defvar forth-mode-abbrev-table nil
73 :     "Abbrev table in use in Forth-mode buffers.")
74 :    
75 :     (define-abbrev-table 'forth-mode-abbrev-table ())
76 :    
77 :     (defvar forth-mode-map nil
78 :     "Keymap used in Forth mode.")
79 :    
80 :     (if (not forth-mode-map)
81 :     (setq forth-mode-map (make-sparse-keymap)))
82 :    
83 : anton 1.9 ;(define-key forth-mode-map "\M-\C-x" 'compile)
84 : anton 1.7 (define-key forth-mode-map "\C-x\\" 'comment-region)
85 :     (define-key forth-mode-map "\C-x~" 'forth-remove-tracers)
86 : anton 1.1 (define-key forth-mode-map "\e\C-m" 'forth-send-paragraph)
87 :     (define-key forth-mode-map "\eo" 'forth-send-buffer)
88 :     (define-key forth-mode-map "\C-x\C-m" 'forth-split)
89 :     (define-key forth-mode-map "\e " 'forth-reload)
90 :     (define-key forth-mode-map "\t" 'forth-indent-command)
91 :     (define-key forth-mode-map "\C-m" 'reindent-then-newline-and-indent)
92 : anton 1.7 (define-key forth-mode-map "\M-q" 'forth-fill-paragraph)
93 : pazsan 1.13 (define-key forth-mode-map "\e." 'forth-find-tag)
94 : anton 1.1
95 : anton 1.35 ;setup for C-h C-i to work
96 :     (if (fboundp 'info-lookup-add-help)
97 :     (info-lookup-add-help
98 :     :topic 'symbol
99 :     :mode 'forth-mode
100 :     :regexp "[^
101 :     ]+"
102 :     :ignore-case t
103 :     :doc-spec '(("(gforth)Name Index" nil "`" "' "))))
104 :    
105 : anton 1.22 (load "etags")
106 : pazsan 1.13
107 :     (defun forth-find-tag (tagname &optional next-p regexp-p)
108 :     (interactive (find-tag-interactive "Find tag: "))
109 :     (switch-to-buffer
110 :     (find-tag-noselect (concat " " tagname " ") next-p regexp-p)))
111 :    
112 : anton 1.1 (defvar forth-mode-syntax-table nil
113 :     "Syntax table in use in Forth-mode buffers.")
114 :    
115 :     (if (not forth-mode-syntax-table)
116 :     (progn
117 :     (setq forth-mode-syntax-table (make-syntax-table))
118 : anton 1.6 (let ((char 0))
119 :     (while (< char ?!)
120 :     (modify-syntax-entry char " " forth-mode-syntax-table)
121 :     (setq char (1+ char)))
122 :     (while (< char 256)
123 :     (modify-syntax-entry char "w" forth-mode-syntax-table)
124 :     (setq char (1+ char))))
125 :     (modify-syntax-entry ?\" "\"" forth-mode-syntax-table)
126 :     (modify-syntax-entry ?\\ "<" forth-mode-syntax-table)
127 :     (modify-syntax-entry ?\n ">" forth-mode-syntax-table)
128 :     ))
129 :     ;I do not define '(' and ')' as comment delimiters, because emacs
130 :     ;only supports one comment syntax (and a hack to accomodate C++); I
131 :     ;use '\' for natural language comments and '(' for formal comments
132 :     ;like stack comments, so for me it's better to have emacs treat '\'
133 : pazsan 1.13 ;comments as comments. If you want it different, make the appropriate
134 : anton 1.6 ;changes (best in your .emacs file).
135 :     ;
136 :     ;Hmm, the C++ hack could be used to support both comment syntaxes: we
137 :     ;can have different comment styles, if both comments start with the
138 :     ;same character. we could use ' ' as first and '(' and '\' as second
139 :     ;character. However this would fail for G\ comments.
140 : anton 1.1
141 :     (defconst forth-indent-level 4
142 :     "Indentation of Forth statements.")
143 :    
144 :     (defun forth-mode-variables ()
145 :     (set-syntax-table forth-mode-syntax-table)
146 :     (setq local-abbrev-table forth-mode-abbrev-table)
147 :     (make-local-variable 'paragraph-start)
148 :     (setq paragraph-start (concat "^$\\|" page-delimiter))
149 :     (make-local-variable 'paragraph-separate)
150 :     (setq paragraph-separate paragraph-start)
151 :     (make-local-variable 'indent-line-function)
152 :     (setq indent-line-function 'forth-indent-line)
153 : anton 1.6 ; (make-local-variable 'require-final-newline)
154 :     ; (setq require-final-newline t)
155 : anton 1.1 (make-local-variable 'comment-start)
156 : anton 1.3 (setq comment-start "\\ ")
157 :     ;(make-local-variable 'comment-end)
158 :     ;(setq comment-end " )")
159 : anton 1.1 (make-local-variable 'comment-column)
160 :     (setq comment-column 40)
161 :     (make-local-variable 'comment-start-skip)
162 : anton 1.3 (setq comment-start-skip "\\ ")
163 : anton 1.1 (make-local-variable 'comment-indent-hook)
164 :     (setq comment-indent-hook 'forth-comment-indent)
165 :     (make-local-variable 'parse-sexp-ignore-comments)
166 :     (setq parse-sexp-ignore-comments t))
167 :    
168 : anton 1.2 ;;;###autoload
169 : anton 1.1 (defun forth-mode ()
170 :     "
171 :     Major mode for editing Forth code. Tab indents for Forth code. Comments
172 : anton 1.9 are delimited with \\ and newline. Paragraphs are separated by blank lines
173 : anton 1.23 only.
174 : anton 1.1 \\{forth-mode-map}
175 :     Forth-split
176 :     Positions the current buffer on top and a forth-interaction window
177 :     below. The window size is controlled by the forth-percent-height
178 :     variable (see below).
179 :     Forth-reload
180 :     Reloads the forth library and restarts the forth process.
181 :     Forth-send-buffer
182 :     Sends the current buffer, in text representation, as input to the
183 :     forth process.
184 :     Forth-send-paragraph
185 :     Sends the previous or the current paragraph to the forth-process.
186 :     Note that the cursor only need to be with in the paragraph to be sent.
187 :     forth-documentation
188 :     Search for documentation of forward adjacent to cursor. Note! To use
189 :     this mode you have to add a line, to your .emacs file, defining the
190 :     directories to search through for documentation files (se variable
191 :     forth-help-load-path below) e.g. (setq forth-help-load-path '(nil)).
192 :    
193 :     Variables controlling interaction and startup
194 :     forth-percent-height
195 :     Tells split how high to make the edit portion, in percent of the
196 :     current screen height.
197 :     forth-program-name
198 :     Tells the library which program name to execute in the interation
199 :     window.
200 :    
201 :     Variables controlling indentation style:
202 :     forth-positives
203 :     A string containing all words which causes the indent-level of the
204 :     following line to be incremented.
205 :     OBS! Each word must be surronded by spaces.
206 :     forth-negatives
207 :     A string containing all words which causes the indentation of the
208 :     current line to be decremented, if the word begin the line. These
209 :     words also has a cancelling effect on the indent-level of the
210 :     following line, independent of position.
211 :     OBS! Each word must be surronded by spaces.
212 :     forth-zeroes
213 :     A string containing all words which causes the indentation of the
214 :     current line to go to zero, if the word begin the line.
215 :     OBS! Each word must be surronded by spaces.
216 :     forth-indent-level
217 :     Indentation increment/decrement of Forth statements.
218 :    
219 :     Note! A word which decrements the indentation of the current line, may
220 :     also be mentioned in forth-positives to cause the indentation to
221 :     resume the previous level.
222 :    
223 :     Variables controling documentation search
224 :     forth-help-load-path
225 :     List of directories to search through to find *.doc
226 :     (forth-help-file-suffix) files. Nil means current default directory.
227 :     The specified directories must contain at least one .doc file. If it
228 :     does not and you still want the load-path to scan that directory, create
229 :     an empty file dummy.doc.
230 :     forth-help-file-suffix
231 :     The file names to search for in each directory specified by
232 :     forth-help-load-path. Defaulted to '*.doc'.
233 :     "
234 :     (interactive)
235 :     (kill-all-local-variables)
236 :     (use-local-map forth-mode-map)
237 :     (setq mode-name "Forth")
238 :     (setq major-mode 'forth-mode)
239 :     (forth-mode-variables)
240 :     ; (if (not (forth-process-running-p))
241 :     ; (run-forth forth-program-name))
242 :     (run-hooks 'forth-mode-hook))
243 :    
244 : anton 1.6 (setq forth-mode-hook
245 : anton 1.9 '(lambda ()
246 :     (make-local-variable 'compile-command)
247 :     (setq compile-command "gforth ")))
248 : anton 1.6
249 : anton 1.7 (defun forth-fill-paragraph ()
250 :     "Fill comments (starting with '\'; do not fill code (block style
251 :     programmers who tend to fill code won't use emacs anyway:-)."
252 : anton 1.9 ; Currently only comments at the start of the line are filled.
253 :     ; Something like lisp-fill-paragraph may be better. We cannot use
254 :     ; fill-paragraph, because it removes the \ from the first comment
255 :     ; line. Therefore we have to look for the first line of the comment
256 :     ; and use fill-region.
257 : anton 1.7 (interactive)
258 :     (save-excursion
259 :     (beginning-of-line)
260 : anton 1.9 (while (and
261 :     (= (forward-line -1) 0)
262 : anton 1.14 (looking-at "[ \t]*\\\\g?[ \t]+")))
263 :     (if (not (looking-at "[ \t]*\\\\g?[ \t]+"))
264 : anton 1.9 (forward-line 1))
265 :     (let ((from (point))
266 :     (to (save-excursion (forward-paragraph) (point))))
267 : anton 1.14 (if (looking-at "[ \t]*\\\\g?[ \t]+")
268 : anton 1.9 (progn (goto-char (match-end 0))
269 :     (set-fill-prefix)
270 :     (fill-region from to nil))))))
271 : anton 1.7
272 : anton 1.1 (defun forth-comment-indent ()
273 :     (save-excursion
274 :     (beginning-of-line)
275 :     (if (looking-at ":[ \t]*")
276 :     (progn
277 :     (end-of-line)
278 :     (skip-chars-backward " \t\n")
279 :     (1+ (current-column)))
280 :     comment-column)))
281 :    
282 :     (defun forth-current-indentation ()
283 :     (save-excursion
284 :     (beginning-of-line)
285 :     (back-to-indentation)
286 :     (current-column)))
287 :    
288 :     (defun forth-delete-indentation ()
289 :     (let ((b nil) (m nil))
290 :     (save-excursion
291 :     (beginning-of-line)
292 :     (setq b (point))
293 :     (back-to-indentation)
294 :     (setq m (point)))
295 :     (delete-region b m)))
296 :    
297 :     (defun forth-indent-line (&optional flag)
298 :     "Correct indentation of the current Forth line."
299 :     (let ((x (forth-calculate-indent)))
300 :     (forth-indent-to x)))
301 :    
302 :     (defun forth-indent-command ()
303 :     (interactive)
304 :     (forth-indent-line t))
305 :    
306 :     (defun forth-indent-to (x)
307 :     (let ((p nil))
308 :     (setq p (- (current-column) (forth-current-indentation)))
309 :     (forth-delete-indentation)
310 :     (beginning-of-line)
311 :     (indent-to x)
312 :     (if (> p 0) (forward-char p))))
313 :    
314 :     ;;Calculate indent
315 :     (defun forth-calculate-indent ()
316 :     (let ((w1 nil) (indent 0) (centre 0))
317 :     (save-excursion
318 :     (beginning-of-line)
319 :     (skip-chars-backward " \t\n")
320 :     (beginning-of-line)
321 :     (back-to-indentation)
322 :     (setq indent (current-column))
323 :     (setq centre indent)
324 :     (setq indent (+ indent (forth-sum-line-indentation))))
325 :     (save-excursion
326 :     (beginning-of-line)
327 :     (back-to-indentation)
328 :     (let ((p (point)))
329 :     (skip-chars-forward "^ \t\n")
330 :     (setq w1 (buffer-substring p (point)))))
331 :     (if (> (- indent centre) forth-indent-level)
332 :     (setq indent (+ centre forth-indent-level)))
333 :     (if (> (- centre indent) forth-indent-level)
334 :     (setq indent (- centre forth-indent-level)))
335 :     (if (< indent 0) (setq indent 0))
336 :     (setq indent (- indent
337 :     (if (string-match
338 :     (regexp-quote (concat " " w1 " "))
339 :     forth-negatives)
340 :     forth-indent-level 0)))
341 : pazsan 1.21 (if (string-match (regexp-quote (concat " " w1 " ")) forth-zdown)
342 :     (setq forth-zero 0))
343 : anton 1.1 (if (string-match (regexp-quote (concat " " w1 " ")) forth-zeroes)
344 : pazsan 1.21 (setq indent forth-zero))
345 :     (if (string-match (regexp-quote (concat " " w1 " ")) forth-zup)
346 :     (setq forth-zero 4))
347 : anton 1.1 indent))
348 :    
349 :     (defun forth-sum-line-indentation ()
350 :     "Add upp the positive and negative weights of all words on the current line."
351 :     (let ((b (point)) (e nil) (sum 0) (w nil) (t1 nil) (t2 nil) (first t))
352 :     (end-of-line) (setq e (point))
353 :     (goto-char b)
354 :     (while (< (point) e)
355 :     (setq w (forth-next-word))
356 :     (setq t1 (string-match (regexp-quote (concat " " w " "))
357 :     forth-positives))
358 :     (setq t2 (string-match (regexp-quote (concat " " w " "))
359 :     forth-negatives))
360 :     (if t1
361 :     (setq sum (+ sum forth-indent-level)))
362 :     (if (and t2 (not first))
363 :     (setq sum (- sum forth-indent-level)))
364 :     (skip-chars-forward " \t")
365 :     (setq first nil))
366 :     sum))
367 :    
368 :    
369 :     (defun forth-next-word ()
370 : anton 1.6 "Return the next forth-word. Skip anything that the forth-word takes from
371 :     the input stream (comments, arguments, etc.)"
372 :     ;actually, it would be better to use commands based on the
373 :     ;syntax-table or comment-start etc.
374 : anton 1.1 (let ((w1 nil))
375 :     (while (not w1)
376 :     (skip-chars-forward " \t\n")
377 :     (let ((p (point)))
378 :     (skip-chars-forward "^ \t\n")
379 :     (setq w1 (buffer-substring p (point))))
380 :     (cond ((string-match "\"" w1)
381 :     (progn
382 : anton 1.6 (skip-chars-forward "^\"\n")
383 :     (forward-char)))
384 :     ((string-match "\\\\" w1)
385 :     (progn
386 :     (end-of-line)
387 :     ))
388 :     ((or (equal "(" w1) (equal ".(" w1))
389 : anton 1.1 (progn
390 : anton 1.6 (skip-chars-forward "^)\n")
391 :     (forward-char)))
392 :     ((string-match (regexp-quote (concat " " w1 " ")) forth-prefixes)
393 :     (progn (skip-chars-forward " \t\n")
394 :     (skip-chars-forward "^ \t\n")))
395 : anton 1.1 (t nil)))
396 :     w1))
397 :    
398 :    
399 :     ;; Forth commands
400 :    
401 : anton 1.7 (defun forth-remove-tracers ()
402 :     "Remove tracers of the form `~~ '. Queries the user for each occurrence."
403 :     (interactive)
404 : anton 1.16 (query-replace-regexp "\\(~~ \\| ~~$\\)" "" nil))
405 : anton 1.7
406 : anton 1.5 (defvar forth-program-name "gforth"
407 : anton 1.1 "*Program invoked by the `run-forth' command.")
408 :    
409 :     (defvar forth-band-name nil
410 :     "*Band loaded by the `run-forth' command.")
411 :    
412 :     (defvar forth-program-arguments nil
413 :     "*Arguments passed to the Forth program by the `run-forth' command.")
414 :    
415 :     (defun run-forth (command-line)
416 :     "Run an inferior Forth process. Output goes to the buffer `*forth*'.
417 :     With argument, asks for a command line. Split up screen and run forth
418 :     in the lower portion. The current-buffer when called will stay in the
419 :     upper portion of the screen, and all other windows are deleted.
420 :     Call run-forth again to make the *forth* buffer appear in the lower
421 :     part of the screen."
422 :     (interactive
423 :     (list (let ((default
424 :     (or forth-process-command-line
425 :     (forth-default-command-line))))
426 :     (if current-prefix-arg
427 :     (read-string "Run Forth: " default)
428 :     default))))
429 :     (setq forth-process-command-line command-line)
430 :     (forth-start-process command-line)
431 :     (forth-split)
432 :     (forth-set-runlight forth-runlight:input))
433 :    
434 : anton 1.28 (defun run-forth-if-not ()
435 :     (if (not (forth-process-running-p))
436 :     (run-forth forth-program-name)))
437 :    
438 : anton 1.1 (defun reset-forth ()
439 :     "Reset the Forth process."
440 :     (interactive)
441 :     (let ((process (get-process forth-program-name)))
442 :     (cond ((or (not process)
443 :     (not (eq (process-status process) 'run))
444 :     (yes-or-no-p
445 :     "The Forth process is running, are you SURE you want to reset it? "))
446 :     (message "Resetting Forth process...")
447 :     (forth-reload)
448 :     (message "Resetting Forth process...done")))))
449 :    
450 :     (defun forth-default-command-line ()
451 : pazsan 1.13 (concat forth-program-name
452 : anton 1.1 (if forth-program-arguments
453 :     (concat " " forth-program-arguments)
454 :     "")))
455 :    
456 :     ;;;; Internal Variables
457 :    
458 :     (defvar forth-process-command-line nil
459 :     "Command used to start the most recent Forth process.")
460 :    
461 :     (defvar forth-previous-send ""
462 :     "Most recent expression transmitted to the Forth process.")
463 :    
464 :     (defvar forth-process-filter-queue '()
465 :     "Queue used to synchronize filter actions properly.")
466 :    
467 :     (defvar forth-prompt "ok"
468 :     "The current forth prompt string.")
469 :    
470 :     (defvar forth-start-hook nil
471 :     "If non-nil, a procedure to call when the Forth process is started.
472 :     When called, the current buffer will be the Forth process-buffer.")
473 :    
474 :     (defvar forth-signal-death-message nil
475 :     "If non-nil, causes a message to be generated when the Forth process dies.")
476 :    
477 : anton 1.9 (defvar forth-percent-height 50
478 : anton 1.1 "Tells run-forth how high the upper window should be in percent.")
479 :    
480 :     (defconst forth-runlight:input ?I
481 :     "The character displayed when the Forth process is waiting for input.")
482 :    
483 :     (defvar forth-mode-string ""
484 :     "String displayed in the mode line when the Forth process is running.")
485 :    
486 :     ;;;; Evaluation Commands
487 :    
488 :     (defun forth-send-string (&rest strings)
489 :     "Send the string arguments to the Forth process.
490 :     The strings are concatenated and terminated by a newline."
491 :     (cond ((forth-process-running-p)
492 :     (forth-send-string-1 strings))
493 :     ((yes-or-no-p "The Forth process has died. Reset it? ")
494 :     (reset-forth)
495 :     (goto-char (point-max))
496 :     (forth-send-string-1 strings))))
497 :    
498 :     (defun forth-send-string-1 (strings)
499 :     (let ((string (apply 'concat strings)))
500 :     (forth-send-string-2 string)))
501 :    
502 :     (defun forth-send-string-2 (string)
503 :     (let ((process (get-process forth-program-name)))
504 :     (if (not (eq (current-buffer) (get-buffer forth-program-name)))
505 :     (progn
506 :     (forth-process-filter-output string)
507 :     (forth-process-filter:finish)))
508 :     (send-string process (concat string "\n"))
509 :     (if (eq (current-buffer) (process-buffer process))
510 :     (set-marker (process-mark process) (point)))))
511 :    
512 :    
513 :     (defun forth-send-region (start end)
514 :     "Send the current region to the Forth process.
515 :     The region is sent terminated by a newline."
516 :     (interactive "r")
517 :     (let ((process (get-process forth-program-name)))
518 :     (if (and process (eq (current-buffer) (process-buffer process)))
519 :     (progn (goto-char end)
520 :     (set-marker (process-mark process) end))))
521 :     (forth-send-string "\n" (buffer-substring start end) "\n"))
522 :    
523 :     (defun forth-end-of-paragraph ()
524 :     (if (looking-at "[\t\n ]+") (skip-chars-backward "\t\n "))
525 :     (if (not (re-search-forward "\n[ \t]*\n" nil t))
526 :     (goto-char (point-max))))
527 :    
528 :     (defun forth-send-paragraph ()
529 :     "Send the current or the previous paragraph to the Forth process"
530 :     (interactive)
531 :     (let (end)
532 :     (save-excursion
533 :     (forth-end-of-paragraph)
534 :     (skip-chars-backward "\t\n ")
535 :     (setq end (point))
536 :     (if (re-search-backward "\n[ \t]*\n" nil t)
537 :     (setq start (point))
538 :     (goto-char (point-min)))
539 :     (skip-chars-forward "\t\n ")
540 :     (forth-send-region (point) end))))
541 :    
542 :     (defun forth-send-buffer ()
543 :     "Send the current buffer to the Forth process."
544 :     (interactive)
545 :     (if (eq (current-buffer) (forth-process-buffer))
546 :     (error "Not allowed to send this buffer's contents to Forth"))
547 :     (forth-send-region (point-min) (point-max)))
548 :    
549 :    
550 :     ;;;; Basic Process Control
551 :    
552 :     (defun forth-start-process (command-line)
553 :     (let ((buffer (get-buffer-create "*forth*")))
554 :     (let ((process (get-buffer-process buffer)))
555 :     (save-excursion
556 :     (set-buffer buffer)
557 :     (progn (if process (delete-process process))
558 :     (goto-char (point-max))
559 :     (setq mode-line-process '(": %s"))
560 :     (add-to-global-mode-string 'forth-mode-string)
561 :     (setq process
562 :     (apply 'start-process
563 :     (cons forth-program-name
564 :     (cons buffer
565 :     (forth-parse-command-line
566 :     command-line)))))
567 :     (set-marker (process-mark process) (point-max))
568 :     (forth-process-filter-initialize t)
569 :     (forth-modeline-initialize)
570 :     (set-process-sentinel process 'forth-process-sentinel)
571 :     (set-process-filter process 'forth-process-filter)
572 :     (run-hooks 'forth-start-hook)))
573 :     buffer)))
574 :    
575 :     (defun forth-parse-command-line (string)
576 :     (setq string (substitute-in-file-name string))
577 :     (let ((start 0)
578 :     (result '()))
579 :     (while start
580 :     (let ((index (string-match "[ \t]" string start)))
581 :     (setq start
582 :     (cond ((not index)
583 :     (setq result
584 :     (cons (substring string start)
585 :     result))
586 :     nil)
587 :     ((= index start)
588 :     (string-match "[^ \t]" string start))
589 :     (t
590 :     (setq result
591 :     (cons (substring string start index)
592 :     result))
593 :     (1+ index))))))
594 :     (nreverse result)))
595 :    
596 :    
597 :     (defun forth-process-running-p ()
598 :     "True iff there is a Forth process whose status is `run'."
599 :     (let ((process (get-process forth-program-name)))
600 :     (and process
601 :     (eq (process-status process) 'run))))
602 :    
603 :     (defun forth-process-buffer ()
604 :     (let ((process (get-process forth-program-name)))
605 :     (and process (process-buffer process))))
606 :    
607 :     ;;;; Process Filter
608 :    
609 :     (defun forth-process-sentinel (proc reason)
610 :     (let ((inhibit-quit nil))
611 :     (forth-process-filter-initialize (eq reason 'run))
612 :     (if (eq reason 'run)
613 :     (forth-modeline-initialize)
614 :     (setq forth-mode-string "")))
615 :     (if (and (not (memq reason '(run stop)))
616 :     forth-signal-death-message)
617 :     (progn (beep)
618 :     (message
619 :     "The Forth process has died! Do M-x reset-forth to restart it"))))
620 :    
621 :     (defun forth-process-filter-initialize (running-p)
622 :     (setq forth-process-filter-queue (cons '() '()))
623 :     (setq forth-prompt "ok"))
624 :    
625 :    
626 :     (defun forth-process-filter (proc string)
627 :     (forth-process-filter-output string)
628 :     (forth-process-filter:finish))
629 :    
630 :     (defun forth-process-filter:enqueue (action)
631 :     (let ((next (cons action '())))
632 :     (if (cdr forth-process-filter-queue)
633 :     (setcdr (cdr forth-process-filter-queue) next)
634 :     (setcar forth-process-filter-queue next))
635 :     (setcdr forth-process-filter-queue next)))
636 :    
637 :     (defun forth-process-filter:finish ()
638 :     (while (car forth-process-filter-queue)
639 :     (let ((next (car forth-process-filter-queue)))
640 :     (setcar forth-process-filter-queue (cdr next))
641 :     (if (not (cdr next))
642 :     (setcdr forth-process-filter-queue '()))
643 :     (apply (car (car next)) (cdr (car next))))))
644 :    
645 :     ;;;; Process Filter Output
646 :    
647 :     (defun forth-process-filter-output (&rest args)
648 :     (if (not (and args
649 :     (null (cdr args))
650 :     (stringp (car args))
651 :     (string-equal "" (car args))))
652 :     (forth-process-filter:enqueue
653 :     (cons 'forth-process-filter-output-1 args))))
654 :    
655 :     (defun forth-process-filter-output-1 (&rest args)
656 :     (save-excursion
657 :     (forth-goto-output-point)
658 :     (apply 'insert-before-markers args)))
659 :    
660 :     (defun forth-guarantee-newlines (n)
661 :     (save-excursion
662 :     (forth-goto-output-point)
663 :     (let ((stop nil))
664 :     (while (and (not stop)
665 :     (bolp))
666 :     (setq n (1- n))
667 :     (if (bobp)
668 :     (setq stop t)
669 :     (backward-char))))
670 :     (forth-goto-output-point)
671 :     (while (> n 0)
672 :     (insert-before-markers ?\n)
673 :     (setq n (1- n)))))
674 :    
675 :     (defun forth-goto-output-point ()
676 :     (let ((process (get-process forth-program-name)))
677 :     (set-buffer (process-buffer process))
678 :     (goto-char (process-mark process))))
679 :    
680 :     (defun forth-modeline-initialize ()
681 :     (setq forth-mode-string " "))
682 :    
683 :     (defun forth-set-runlight (runlight)
684 :     (aset forth-mode-string 0 runlight)
685 :     (forth-modeline-redisplay))
686 :    
687 :     (defun forth-modeline-redisplay ()
688 :     (save-excursion (set-buffer (other-buffer)))
689 :     (set-buffer-modified-p (buffer-modified-p))
690 :     (sit-for 0))
691 :    
692 :     ;;;; Process Filter Operations
693 :    
694 :     (defun add-to-global-mode-string (x)
695 :     (cond ((null global-mode-string)
696 :     (setq global-mode-string (list "" x " ")))
697 :     ((not (memq x global-mode-string))
698 :     (setq global-mode-string
699 :     (cons ""
700 :     (cons x
701 :     (cons " "
702 :     (if (equal "" (car global-mode-string))
703 :     (cdr global-mode-string)
704 :     global-mode-string))))))))
705 :    
706 :    
707 :     ;; Misc
708 :    
709 :     (setq auto-mode-alist (append auto-mode-alist
710 : pazsan 1.4 '(("\\.fs$" . forth-mode))))
711 : anton 1.1
712 :     (defun forth-split ()
713 :     (interactive)
714 :     (forth-split-1 "*forth*"))
715 :    
716 :     (defun forth-split-1 (buffer)
717 :     (if (not (eq (window-buffer) (get-buffer buffer)))
718 :     (progn
719 :     (delete-other-windows)
720 :     (split-window-vertically
721 :     (/ (* (screen-height) forth-percent-height) 100))
722 :     (other-window 1)
723 :     (switch-to-buffer buffer)
724 :     (goto-char (point-max))
725 :     (other-window 1))))
726 :    
727 :     (defun forth-reload ()
728 :     (interactive)
729 :     (let ((process (get-process forth-program-name)))
730 :     (if process (kill-process process t)))
731 : anton 1.28 (sleep-for 0 100)
732 : anton 1.1 (forth-mode))
733 :    
734 :    
735 :     ;; Special section for forth-help
736 :    
737 :     (defvar forth-help-buffer "*Forth-help*"
738 :     "Buffer used to display the requested documentation.")
739 :    
740 :     (defvar forth-help-load-path nil
741 :     "List of directories to search through to find *.doc
742 :     (forth-help-file-suffix) files. Nil means current default directory.
743 :     The specified directories must contain at least one .doc file. If it
744 :     does not and you still want the load-path to scan that directory, create
745 :     an empty file dummy.doc.")
746 :    
747 :     (defvar forth-help-file-suffix "*.doc"
748 :     "The file names to search for in each directory.")
749 :    
750 :     (setq forth-search-command-prefix "grep -n \"^ [^(]* ")
751 :     (defvar forth-search-command-suffix "/dev/null")
752 :     (defvar forth-grep-error-regexp ": No such file or directory")
753 :    
754 :     (defun forth-function-called-at-point ()
755 :     "Return the space delimited word a point."
756 :     (save-excursion
757 :     (save-restriction
758 :     (narrow-to-region (max (point-min) (- (point) 1000)) (point-max))
759 :     (skip-chars-backward "^ \t\n" (point-min))
760 :     (if (looking-at "[ \t\n]")
761 :     (forward-char 1))
762 :     (let (obj (p (point)))
763 :     (skip-chars-forward "^ \t\n")
764 :     (buffer-substring p (point))))))
765 :    
766 :     (defun forth-help-names-extend-comp (path-list result)
767 :     (cond ((null path-list) result)
768 :     ((null (car path-list))
769 :     (forth-help-names-extend-comp (cdr path-list)
770 :     (concat result forth-help-file-suffix " ")))
771 :     (t (forth-help-names-extend-comp
772 :     (cdr path-list) (concat result
773 :     (expand-file-name (car path-list)) "/"
774 :     forth-help-file-suffix " ")))))
775 :    
776 :     (defun forth-help-names-extended ()
777 :     (if forth-help-load-path
778 :     (forth-help-names-extend-comp forth-help-load-path "")
779 :     (error "forth-help-load-path not specified")))
780 :    
781 :    
782 : anton 1.7 ;(define-key forth-mode-map "\C-hf" 'forth-documentation)
783 : anton 1.1
784 :     (defun forth-documentation (function)
785 :     "Display the full documentation of FORTH word."
786 :     (interactive
787 :     (let ((fn (forth-function-called-at-point))
788 :     (enable-recursive-minibuffers t)
789 :     search-list
790 :     val)
791 :     (setq val (read-string (format "Describe forth word (default %s): " fn)))
792 :     (list (if (equal val "") fn val))))
793 :     (forth-get-doc (concat forth-search-command-prefix
794 :     (grep-regexp-quote (concat function " ("))
795 :     "[^)]*\-\-\" " (forth-help-names-extended)
796 :     forth-search-command-suffix))
797 :     (message "C-x C-m switches back to the forth interaction window"))
798 :    
799 :     (defun forth-get-doc (command)
800 :     "Display the full documentation of command."
801 :     (let ((curwin (get-buffer-window (window-buffer)))
802 :     reswin
803 :     pointmax)
804 :     (with-output-to-temp-buffer forth-help-buffer
805 :     (progn
806 :     (call-process "sh" nil forth-help-buffer t "-c" command)
807 :     (setq reswin (get-buffer-window forth-help-buffer))))
808 :     (setq reswin (get-buffer-window forth-help-buffer))
809 :     (select-window reswin)
810 :     (save-excursion
811 :     (goto-char (setq pointmax (point-max)))
812 :     (insert "--------------------\n\n"))
813 :     (let (fd doc)
814 :     (while (setq fd (forth-get-file-data pointmax))
815 :     (setq doc (forth-get-doc-string fd))
816 :     (save-excursion
817 :     (goto-char (point-max))
818 :     (insert (substring (car fd) (string-match "[^/]*$" (car fd)))
819 :     ":\n\n" doc "\n")))
820 :     (if (not doc)
821 :     (progn (goto-char (point-max)) (insert "Not found"))))
822 :     (select-window curwin)))
823 :    
824 :     (defun forth-skip-error-lines ()
825 :     (let ((lines 0))
826 :     (save-excursion
827 :     (while (re-search-forward forth-grep-error-regexp nil t)
828 :     (beginning-of-line)
829 :     (forward-line 1)
830 :     (setq lines (1+ lines))))
831 :     (forward-line lines)))
832 :    
833 :     (defun forth-get-doc-string (fd)
834 :     "Find file (car fd) and extract documentation from line (nth 1 fd)."
835 :     (let (result)
836 :     (save-window-excursion
837 :     (find-file (car fd))
838 :     (goto-line (nth 1 fd))
839 :     (if (not (eq (nth 1 fd) (1+ (count-lines (point-min) (point)))))
840 :     (error "forth-get-doc-string: serious error"))
841 :     (if (not (re-search-backward "\n[\t ]*\n" nil t))
842 :     (goto-char (point-min))
843 :     (goto-char (match-end 0)))
844 :     (let ((p (point)))
845 :     (if (not (re-search-forward "\n[\t ]*\n" nil t))
846 :     (goto-char (point-max)))
847 :     (setq result (buffer-substring p (point))))
848 :     (bury-buffer (current-buffer)))
849 :     result))
850 :    
851 :     (defun forth-get-file-data (limit)
852 :     "Parse grep output and return '(filename line#) list. Return nil when
853 :     passing limit."
854 :     (forth-skip-error-lines)
855 :     (if (< (point) limit)
856 :     (let ((result (forth-get-file-data-cont limit)))
857 :     (forward-line 1)
858 :     (beginning-of-line)
859 :     result)))
860 :    
861 :     (defun forth-get-file-data-cont (limit)
862 :     (let (result)
863 :     (let ((p (point)))
864 :     (skip-chars-forward "^:")
865 :     (setq result (buffer-substring p (point))))
866 :     (if (< (point) limit)
867 :     (let ((p (1+ (point))))
868 :     (forward-char 1)
869 :     (skip-chars-forward "^:")
870 :     (list result (string-to-int (buffer-substring p (point))))))))
871 :    
872 :     (defun grep-regexp-quote (str)
873 :     (let ((i 0) (m 1) (res ""))
874 :     (while (/= m 0)
875 :     (setq m (string-to-char (substring str i)))
876 :     (if (/= m 0)
877 :     (progn
878 :     (setq i (1+ i))
879 :     (if (string-match (regexp-quote (char-to-string m))
880 :     ".*\\^$[]")
881 :     (setq res (concat res "\\")))
882 :     (setq res (concat res (char-to-string m))))))
883 :     res))
884 :    
885 :    
886 : anton 1.9 (define-key forth-mode-map "\C-x\C-e" 'compile)
887 : anton 1.1 (define-key forth-mode-map "\C-x\C-n" 'next-error)
888 :     (require 'compile "compile")
889 :    
890 : anton 1.6 (defvar forth-compile-command "gforth ")
891 : anton 1.9 ;(defvar forth-compilation-window-percent-height 30)
892 : anton 1.1
893 :     (defun forth-compile (command)
894 :     (interactive (list (setq forth-compile-command (read-string "Compile command: " forth-compile-command))))
895 :     (forth-split-1 "*compilation*")
896 :     (setq ctools-compile-command command)
897 :     (compile1 ctools-compile-command "No more errors"))
898 :    
899 :    
900 : pazsan 1.12 ;;; Forth menu
901 :     ;;; Mikael Karlsson <qramika@eras70.ericsson.se>
902 :    
903 :     (cond ((string-match "XEmacs\\|Lucid" emacs-version)
904 :     (require 'func-menu)
905 :    
906 :     (defconst fume-function-name-regexp-forth
907 :     "^\\(:\\)[ \t]+\\([^ \t]*\\)"
908 :     "Expression to get word definitions in Forth.")
909 :    
910 :     (setq fume-function-name-regexp-alist
911 :     (append '((forth-mode . fume-function-name-regexp-forth)
912 :     ) fume-function-name-regexp-alist))
913 :    
914 :     ;; Find next forth word in the buffer
915 :     (defun fume-find-next-forth-function-name (buffer)
916 :     "Searches for the next forth word in BUFFER."
917 :     (set-buffer buffer)
918 :     (if (re-search-forward fume-function-name-regexp nil t)
919 :     (let ((beg (match-beginning 2))
920 :     (end (match-end 2)))
921 :     (cons (buffer-substring beg end) beg))))
922 :    
923 :     (setq fume-find-function-name-method-alist
924 :     (append '((forth-mode . fume-find-next-forth-function-name))))
925 :    
926 :     ))
927 :     ;;; End Forth menu
928 :    
929 :     ;;; File folding of forth-files
930 :     ;;; uses outline
931 :     ;;; Toggle activation with M-x fold-f (when editing a forth-file)
932 :     ;;; Use f9 to expand, f10 to hide, Or the menubar in xemacs
933 :     ;;;
934 :     ;;; Works most of the times but loses sync with the cursor occasionally
935 :     ;;; Could be improved by also folding on comments
936 :    
937 :     (require 'outline)
938 :    
939 : pazsan 1.29 (defun f-outline-level ()
940 :     (cond ((looking-at "\\`\\\\")
941 :     0)
942 :     ((looking-at "\\\\ SEC")
943 :     0)
944 :     ((looking-at "\\\\ \\\\ .*")
945 :     0)
946 :     ((looking-at "\\\\ DEFS")
947 :     1)
948 :     ((looking-at "\\/\\* ")
949 :     1)
950 :     ((looking-at ": .*")
951 :     1)
952 :     ((looking-at "\\\\G")
953 :     2)
954 :     ((looking-at "[ \t]+\\\\")
955 :     3))
956 :     )
957 : pazsan 1.12
958 :     (defun fold-f ()
959 :     (interactive)
960 :     (add-hook 'outline-minor-mode-hook 'hide-body)
961 :    
962 :     ; outline mode header start, i.e. find word definitions
963 : pazsan 1.29 ;;; (setq outline-regexp "^\\(:\\)[ \t]+\\([^ \t]*\\)")
964 :     (setq outline-regexp "\\`\\\\\\|:\\|\\\\ SEC\\|\\\\G\\|[ \t]+\\\\\\|\\\\ DEFS\\|\\/\\*\\|\\\\ \\\\ .*")
965 :     (setq outline-level 'f-outline-level)
966 : pazsan 1.12
967 :     (outline-minor-mode)
968 : anton 1.30 (define-key outline-minor-mode-map '(shift up) 'hide-sublevels)
969 :     (define-key outline-minor-mode-map '(shift right) 'show-children)
970 :     (define-key outline-minor-mode-map '(shift left) 'hide-subtree)
971 :     (define-key outline-minor-mode-map '(shift down) 'show-subtree)
972 : pazsan 1.29
973 : pazsan 1.12 )
974 : pazsan 1.29
975 :     ;;(define-key global-map '(shift up) 'fold-f)
976 :    
977 : pazsan 1.12 ;;; end file folding
978 :    
979 :     ;;; func-menu is a package that scans your source file for function definitions
980 :     ;;; and makes a menubar entry that lets you jump to any particular function
981 :     ;;; definition by selecting it from the menu. The following code turns this on
982 :     ;;; for all of the recognized languages. Scanning the buffer takes some time,
983 :     ;;; but not much.
984 :     ;;;
985 :     (cond ((string-match "XEmacs\\|Lucid" emacs-version)
986 :     (require 'func-menu)
987 :     ;; (define-key global-map 'f8 'function-menu)
988 :     (add-hook 'find-fible-hooks 'fume-add-menubar-entry)
989 : anton 1.30 ; (define-key global-map "\C-cg" 'fume-prompt-function-goto)
990 :     ; (define-key global-map '(shift button3) 'mouse-function-menu)
991 : pazsan 1.29 ))
992 :    
993 : pazsan 1.37 ;;; Highlighting
994 :    
995 :     (if (not (file-exists-p "/usr/share/emacs/site-lisp/hl319.el"))
996 :     (require 'hilit19)
997 :     (require 'hl319))
998 :    
999 :     (hilit-set-mode-patterns
1000 :     '(forth-mode)
1001 :     (append
1002 :     '(("\\\\ \\(.*\\)$" nil comment)) ; comments
1003 : pazsan 1.38 '(("( [^)\n]* -- [^)\n]* )" nil decl))
1004 :     '(("( -- [^)\n]* )" nil decl))
1005 :     '(("( [^)\n]* -- )" nil decl))
1006 : pazsan 1.37 '(("( -- )" nil decl))
1007 :     '(("( " ")" comment))
1008 : pazsan 1.38 '(("\" [^\"\n]*\"" nil string))
1009 : pazsan 1.40 '(("\\(\\[IF]\\|\\[IFDEF]\\|\\[IFUNDEF]\\|\\[ELSE]\\|\\[THEN]\\|IF\\|ELSE\\|THEN\\|BEGIN\\|WHILE\\|REPEAT\\|UNTIL\\|DOES>\\|?DO\\|DO\\|\+LOOP\\|LOOP\\)" nil keyword))
1010 : pazsan 1.38 '((": *[^ \n]*" nil defun))
1011 :     '(("Defer *[^ \n]*" nil defun))
1012 : pazsan 1.40 '(("\\(Variable\\|Constant\\|Value\\|Create\\) *[^ \n]*" nil define))
1013 :     '(("\\(include\\|require\\) *[^ \n]*" nil include))
1014 : pazsan 1.39 '(("[\n ]\\(\\$[0-9A-Fa-f]+[\n ]\\|&[0-9]+[\n ]\\|[0-9]+[\n ]\\|%[01]+[\n ]\\|'[^ \n]+\\)+" nil formula))
1015 : pazsan 1.37 '((":noname" nil defun))))
1016 :    
1017 : pazsan 1.29 ;; end
1018 :    

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help