1 ;;; teco.el --- Teco interpreter for Gnu Emacs, version 1.
3 ;; Author: Dale R. Worley.
4 ;; Keywords: emulations
6 ;; This file is part of XEmacs.
8 ;; XEmacs is free software; you can redistribute it and/or modify it
9 ;; under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; XEmacs is distributed in the hope that it will be useful, but
14 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ;; General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with XEmacs; see the file COPYING. If not, write to the Free
20 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 ;;; Synched up with: Not in FSF
27 ;; This code has been tested some, but no doubt contains a zillion bugs.
28 ;; You have been warned.
30 ;; Written by Dale R. Worley based on a C implementation by Matt Fichtenbaum.
31 ;; Please send comments, bug fixes, enhancements, etc. to drw@math.mit.edu.
33 ;; Emacs Lisp version copyright (C) 1991 by Dale R. Worley.
34 ;; Do what you will with it.
36 ;; Since much of this code is translated from the C version by
37 ;; Matt Fichtenbaum, I include his copyright notice:
38 ;; TECO for Ultrix. Copyright 1986 Matt Fichtenbaum.
39 ;; This program and its components belong to GenRad Inc, Concord MA 01742.
40 ;; They may be copied if this copyright notice is included.
42 ;; To invoke directly, do:
43 ;; (global-set-key ?\C-z 'teco-command)
44 ;; (autoload teco-command "teco"
45 ;; "Read and execute a Teco command string."
48 ;; Differences from other Tecos:
49 ;; Character positions in the buffer are numbered in the Emacs way: The first
50 ;; character is numbered 1 (or (point-min) if narrowing is in effect). The
51 ;; B command returns that number.
52 ;; Ends of lines are represented by a single character (newline), so C and R
53 ;; skip over them, rather than 2C and 2R.
54 ;; All file I/O is left to the underlying Emacs. Thus, almost all Ex commands
59 ;; ^A Output message to terminal (argument ends with ^A)
61 ;; ^C^C Stop execution
62 ;; ^D Set radix to decimal
63 ;; ^EA (match char) Match alphabetics
64 ;; ^EC (match char) Match symbol constituents
65 ;; ^ED (match char) Match numerics
66 ;; ^EGq (match char) Match any char in q-reg
67 ;; ^EL (match char) Match line terminators
68 ;; ^EQq (string char) Use contents of q-reg
69 ;; ^ER (match char) Match alphanumerics
70 ;; ^ES (match char) Match non-null space/tab
71 ;; ^EV (match char) Match lower case alphabetic
72 ;; ^EW (match char) Match upper case alphabetic
73 ;; ^EX (match char) Match any char
74 ;; ^G^G (type-in) Kill command string
75 ;; ^G<sp> (type-in) Retype current command line
76 ;; ^G* (type-in) Retype current command input
77 ;; TAB Insert tab and text
78 ;; LF Line terminator; Ignored in commands
79 ;; VT Ignored in commands
80 ;; FF Ignored in commands
81 ;; CR Ignored in commands
82 ;; ^Nx (match char) Match all but x
83 ;; ^O Set radix to octal
84 ;; ^P Find matching parenthesis
85 ;; ^Q Convert line argument into character argument
86 ;; ^Qx (string char) Use x literally
88 ;; :^R Enter recursive edit
89 ;; ^S -(length of last referenced string)
90 ;; ^S (match char) match separator char
91 ;; ^T Ascii value of next character typed
92 ;; n^T Output Ascii character with value n
93 ;; ^U (type-in) Kill command line
94 ;; ^Uq Put text argument into q-reg
95 ;; n^Uq Put Ascii character 'n' into q-reg
96 ;; :^Uq Append text argument to q-reg
97 ;; n:^Uq Append character 'n' to q-reg
98 ;; ^X Set/get search mode flag
99 ;; ^X (match char) Match any character
100 ;; ^Y Equivalent to '.+^S,.'
101 ;; ^Z Not a Teco command
102 ;; ESC String terminator; absorbs arguments
103 ;; ESC ESC (type-in) End command
104 ;; ^\ Not a Teco command
105 ;; ^] Not a Teco command
106 ;; ^^x Ascii value of the character x
107 ;; ^_ One's complement (logical NOT)
108 ;; ! Define label (argument ends with !)
109 ;; " Start conditional
110 ;; n"< Test for less than zero
111 ;; n"> Test for greater than zero
112 ;; n"= Test for equal to zero
113 ;; n"A Test for alphabetic
114 ;; n"C Test for symbol constituent
115 ;; n"D Test for numeric
116 ;; n"E Test for equal to zero
117 ;; n"F Test for false
118 ;; n"G Test for greater than zero
119 ;; n"L Test for less than zero
120 ;; n"N Test for not equal to zero
121 ;; n"R Test for alphanumeric
122 ;; n"S Test for successful
124 ;; n"U Test for unsuccessful
125 ;; n"V Test for lower case
126 ;; n"W Test for upper case
128 ;; $ Not a Teco command
129 ;; n%q Add n to q-reg and return result
132 ;; ( Expression grouping
133 ;; ) Expression grouping
136 ;; , Argument separator
137 ;; - Subtraction or negation
138 ;; . Current pointer position
141 ;; n< Iterate n times
143 ;; := Type in decimal, no newline
145 ;; := Type in octal, no newline
146 ;; = Type in hexadecimal
147 ;; := Type in hexadecimal, no newline
148 ;; :: Make next search a compare
150 ;; n:A Get Ascii code of character at relative position n
151 ;; B Character position of beginning of buffer
152 ;; nC Advance n characters
153 ;; nD Delete n characters
154 ;; n,mD Delete characters between n and m
155 ;; Gq Get string from q-reg into buffer
156 ;; :Gq Type out q-reg
157 ;; H Equivalent to 'B,Z'
158 ;; I Insert text argument
159 ;; nJ Move pointer to character n
161 ;; n,mK Kill characters between n and m
162 ;; nL Advance n lines
163 ;; Mq Execute string in q-reg
165 ;; nO Go to n-th label in list (0-origin)
166 ;; Qq Number in q-reg
167 ;; nQq Ascii value of n-th character in q-reg
168 ;; :Qq Size of text in q-reg
169 ;; nR Back up n characters
172 ;; n,mT Type chars from n to m
173 ;; nUq Put number n into q-reg
174 ;; nV Type n lines around pointer
175 ;; nXq Put n lines into q-reg
176 ;; n,mXq Put characters from n to m into q-reg
177 ;; n:Xq Append n lines to q-reg q
178 ;; n,m:Xq Append characters from n to m into q-reg
179 ;; Z Pointer position at end of buffer
180 ;; [q Put q-reg on stack
181 ;; \ Value of digit string in buffer
182 ;; n\ Convert n to digits and insert in buffer
183 ;; ]q Pop q-reg from stack
184 ;; :]q Test whether stack is empty and return value
185 ;; ` Not a Teco command
186 ;; a-z Treated the same as A-Z
187 ;; { Not a Teco command
188 ;; | Conditional 'else'
189 ;; } Not a Teco command
190 ;; ~ Not a Teco command
191 ;; DEL Delete last character typed in
197 ;; set a range of elements of an array to a value
198 (defun teco-set-elements (array start end value)
204 ;; set a range of elements of an array to their indexes plus an offset
205 (defun teco-set-elements-index (array start end offset)
208 (aset array i (+ i offset))
211 (defvar teco-command-string ""
212 "The current command string being executed.")
214 (defvar teco-command-pointer nil
215 "Pointer into teco-command-string showing next character to be executed.")
217 (defvar teco-ctrl-r 10
218 "Current number radix.")
220 (defvar teco-digit-switch nil
221 "Set if we have just executed a digit.")
223 (defvar teco-exp-exp nil
224 "Expression value preceding operator.")
226 (defvar teco-exp-val1 nil
227 "Current argument value.")
229 (defvar teco-exp-val2 nil
230 "Argument before comma.")
232 (defvar teco-exp-flag1 nil
233 "t if argument is present.")
235 (defvar teco-exp-flag2 nil
236 "t if argument before comma is present.")
238 (defvar teco-exp-op nil
239 "Pending arithmetic operation on argument.")
241 (defvar teco-exp-stack nil
242 "Stack for parenthesized expressions.")
244 (defvar teco-macro-stack nil
245 "Stack for macro invocations.")
247 (defvar teco-mapch-l nil
248 "Translation table to lower-case letters.")
250 (setq teco-mapch-l (make-vector 256 0))
251 (teco-set-elements-index teco-mapch-l 0 255 0)
252 (teco-set-elements-index teco-mapch-l ?A ?Z (- ?a ?A))
254 (defvar teco-trace nil
255 "t if tracing is on.")
257 (defvar teco-at-flag nil
258 "t if an @ flag is pending.")
260 (defvar teco-colon-flag nil
261 "1 if a : flag is pending, 2 if a :: flag is pending.")
263 (defvar teco-qspec-valid nil
264 "Flags describing whether a character is a vaid q-register name.
265 3 means yes, 2 means yes but only for file and search operations.")
267 (setq teco-qspec-valid (make-vector 256 0))
268 (teco-set-elements teco-qspec-valid ?a ?z 3)
269 (teco-set-elements teco-qspec-valid ?0 ?9 3)
270 (aset teco-qspec-valid ?_ 2)
271 (aset teco-qspec-valid ?* 2)
272 (aset teco-qspec-valid ?% 2)
273 (aset teco-qspec-valid ?# 2)
275 (defvar teco-exec-flags 0
276 "Flags for iteration in process, ei macro, etc.")
278 (defvar teco-iteration-stack nil
281 (defvar teco-cond-stack nil
282 "Conditional stack.")
284 (defvar teco-qreg-text (make-vector 256 "")
285 "The text contents of the q-registers.")
287 (defvar teco-qreg-number (make-vector 256 0)
288 "The number contents of the q-registers.")
290 (defvar teco-qreg-stack nil
291 "The stack of saved q-registers.")
293 (defconst teco-prompt "*"
294 "*Prompt to be used when inputting Teco command.")
296 (defconst teco-exec-1 (make-vector 256 nil)
297 "Names of routines handling type 1 characters (characters that are
298 part of expression processing).")
300 (defconst teco-exec-2 (make-vector 256 nil)
301 "Names of routines handling type 2 characters (characters that are
302 not part of expression processing).")
304 (defvar teco-last-search-string ""
305 "Last string searched for.")
307 (defvar teco-last-search-regexp ""
308 "Regexp version of teco-last-search-string.")
310 (defmacro teco-define-type-1 (char &rest body)
311 "Define the code to process a type 1 character.
313 (teco-define-type-1 ?x
316 (defun teco-type-1-x ()
319 (aset teco-exec-1 ?x 'teco-type-1-x)"
320 (let ((s (intern (concat "teco-type-1-" (char-to-string char)))))
324 (aset teco-exec-1 (, char) '(, s))))))
326 (defmacro teco-define-type-2 (char &rest body)
327 "Define the code to process a type 2 character.
329 (teco-define-type-2 ?x
332 (defun teco-type-2-x ()
335 (aset teco-exec-2 ?x 'teco-type-2-x)"
336 (let ((s (intern (concat "teco-type-2-" (char-to-string char)))))
340 (aset teco-exec-2 (, char) '(, s))))))
342 (defconst teco-char-types (make-vector 256 0)
343 "Define the characteristics of characters, as tested by \":
345 2 alphabetic, $, or .
347 8 alphabetic or digit
348 16 lower-case alphabetic
349 32 upper-case alphabetic")
351 (teco-set-elements teco-char-types ?0 ?9 (+ 4 8))
352 (teco-set-elements teco-char-types ?A ?Z (+ 1 2 8 32))
353 (teco-set-elements teco-char-types ?a ?z (+ 1 2 8 16))
354 (aset teco-char-types ?$ 2)
355 (aset teco-char-types ?. 2)
357 (defconst teco-error-texts '(("BNI" . "> not in iteration")
358 ("CPQ" . "Can't pop Q register")
359 ("COF" . "Can't open output file ")
360 ("FNF" . "File not found ")
361 ("IEC" . "Invalid E character")
362 ("IFC" . "Invalid F character")
363 ("IIA" . "Invalid insert arg")
364 ("ILL" . "Invalid command")
365 ("ILN" . "Invalid number")
366 ("IPA" . "Invalid P arg")
367 ("IQC" . "Invalid \" character")
368 ("IQN" . "Invalid Q-reg name")
369 ("IRA" . "Invalid radix arg")
370 ("ISA" . "Invalid search arg")
371 ("ISS" . "Invalid search string")
372 ("IUC" . "Invalid ^ character")
373 ("LNF" . "Label not found")
374 ("MEM" . "Insufficient memory available")
375 ("MRP" . "Missing )")
376 ("NAB" . "No arg before ^_")
377 ("NAC" . "No arg before ,")
378 ("NAE" . "No arg before =")
379 ("NAP" . "No arg before )")
380 ("NAQ" . "No arg before \"")
381 ("NAS" . "No arg before ;")
382 ("NAU" . "No arg before U")
383 ("NFI" . "No file for input")
384 ("NFO" . "No file for output")
385 ("NYA" . "Numeric arg with Y")
386 ("OFO" . "Output file already open")
387 ("PDO" . "Pushdown list overflow")
388 ("POP" . "Pointer off page")
389 ("SNI" . "; not in iteration")
390 ("SRH" . "Search failure ")
391 ("STL" . "String too long")
392 ("UTC" . "Unterminated command")
393 ("UTM" . "Unterminated macro")
394 ("XAB" . "Execution interrupted")
395 ("YCA" . "Y command suppressed")
396 ("IWA" . "Invalid W arg")
397 ("NFR" . "Numeric arg with FR")
398 ("INT" . "Internal error")
399 ("EFI" . "EOF read from std input")
400 ("IAA" . "Invalid A arg")
403 (defconst teco-spec-chars
405 0 1 0 0 ; ^@ ^A ^B ^C
406 0 64 0 0 ; ^D ^E ^F ^G
407 0 2 128 128 ; ^H ^I ^J ^K
408 128 0 64 0 ; ^L ^M ^N ^O
409 0 64 64 64 ; ^P ^Q ^R ^S
410 0 34 0 0 ; ^T ^U ^V ^W
411 64 0 0 0 ; ^X ^Y ^Z ^\[
412 0 0 1 0 ; ^\ ^\] ^^ ^_
438 "The special properties of characters:
439 1 skipto() special character
440 2 command with std text argument
441 4 E<char> takes a text argument
442 8 F<char> takes a text argument
443 16 char causes skipto() to exit
444 32 command with q-register argument
445 64 special char in search string
446 128 character is a line separator")
449 (defun teco-execute-command (string)
450 "Execute teco command string."
451 ;; Initialize everything
452 (let ((teco-command-string string)
453 (teco-command-pointer 0)
454 (teco-digit-switch nil)
463 (teco-colon-flag nil)
465 (teco-iteration-stack nil)
466 (teco-cond-stack nil)
468 (teco-macro-stack nil)
469 (teco-qreg-stack nil))
475 ;; get next command character
476 (let ((cmdc (teco-get-command0 teco-trace)))
477 ;; if it's ^, interpret the next character as a control character
479 (setq cmdc (logand (teco-get-command teco-trace) 31)))
480 (if (and (<= ?0 cmdc) (<= cmdc ?9))
483 (setq cmdc (- cmdc ?0))
484 ;; check for invalid digit
485 (if (>= cmdc teco-ctrl-r)
487 (if teco-digit-switch
489 (setq teco-exp-val1 (+ (* teco-exp-val1 teco-ctrl-r) cmdc))
491 (setq teco-exp-val1 cmdc)
492 (setq teco-digit-switch t))
493 ;; indicate a value was read in
494 (setq teco-exp-flag1 t))
496 (setq teco-digit-switch nil)
497 ;; cannonicalize the case
498 (setq cmdc (aref teco-mapch-l cmdc))
499 ;; dispatch on the character, if it is a type 1 character
500 (let ((r (aref teco-exec-1 cmdc)))
503 ;; if a value has been entered, process any pending operation
505 (cond ((eq teco-exp-op 'start)
507 ((eq teco-exp-op 'add)
508 (setq teco-exp-val1 (+ teco-exp-exp teco-exp-val1))
509 (setq teco-exp-op 'start))
510 ((eq teco-exp-op 'sub)
511 (setq teco-exp-val1 (- teco-exp-exp teco-exp-val1))
512 (setq teco-exp-op 'start))
513 ((eq teco-exp-op 'mult)
514 (setq teco-exp-val1 (* teco-exp-exp teco-exp-val1))
515 (setq teco-exp-op 'start))
516 ((eq teco-exp-op 'div)
518 (if (/= teco-exp-val1 0)
519 (/ teco-exp-exp teco-exp-val1)
521 (setq teco-exp-op 'start))
522 ((eq teco-exp-op 'and)
524 (logand teco-exp-exp teco-exp-val1))
525 (setq teco-exp-op 'start))
526 ((eq teco-exp-op 'or)
528 (logior teco-exp-exp teco-exp-val1))
529 (setq teco-exp-op 'start))))
530 ;; dispatch on a type 2 character
531 (let ((r (aref teco-exec-2 cmdc)))
534 (teco-error "ILL")))))))))))
560 (if (teco-peek-command ?\e)
561 ;; ESC ESC terminates macro or command
562 (teco-pop-macro-stack)
563 ;; otherwise, consume argument
564 (setq teco-exp-flag1 nil)
565 (setq teco-exp-op 'start)))
569 (while (/= (teco-get-command teco-trace) ?!)
575 (setq teco-at-flag t))
580 (if (teco-peek-command ?:)
583 (teco-get-command teco-trace)
584 ;; set flag to show two colons
585 (setq teco-colon-flag 2))
586 ;; set flag to show one colon
587 (setq teco-colon-flag 1)))
592 (setq teco-trace (not teco-trace)))
597 (setq teco-exp-val1 (point)
602 ;; value is point-max
603 (setq teco-exp-val1 (point-max)
608 ;; value is point-min
609 (setq teco-exp-val1 (point-min)
615 (setq teco-exp-val1 (point-max)
616 teco-exp-val2 (point-min)
623 ;; value is - length of last insert, etc.
624 (setq teco-exp-val1 teco-ctrl-s
630 (setq teco-exp-val1 (+ (point) teco-ctrl-s)
631 teco-exp-val2 (point)
638 ;; push expression stack
639 (teco-push-exp-stack)
640 (setq teco-exp-flag1 nil
650 ;; get next command character
651 (setq teco-exp-val1 (teco-get-command teco-trace)
658 (setq teco-exp-exp (if teco-exp-flag1 teco-exp-val1 0)
664 (setq teco-exp-exp (if teco-exp-flag1 teco-exp-val1 0)
670 (setq teco-exp-exp (if teco-exp-flag1 teco-exp-val1 0)
676 (setq teco-exp-exp (if teco-exp-flag1 teco-exp-val1 0)
682 (setq teco-exp-exp (if teco-exp-flag1 teco-exp-val1 0)
688 (setq teco-exp-exp (if teco-exp-flag1 teco-exp-val1 0)
694 (if (or (not teco-exp-flag1) (not teco-exp-stack))
696 (let ((v teco-exp-val1))
698 (setq teco-exp-val1 v
703 (if (not teco-exp-flag1)
705 (setq teco-exp-val2 teco-exp-val1
711 (if (not teco-exp-flag1)
713 (setq teco-exp-val1 (lognot teco-exp-val1))))
732 (setq teco-colon-flag nil))
736 (if (and (/= teco-exp-val1 8)
737 (/= teco-exp-val1 10)
738 (/= teco-exp-val1 16))
740 (setq teco-ctrl-r teco-exp-val1
744 (setq teco-exp-val1 teco-ctrl-r
749 (if (teco-peek-command ?\^c)
750 ;; ^C^C stops execution
751 (throw 'teco-exit nil)
753 ;; ^C inside macro exits macro
754 (teco-pop-macro-stack)
755 ;; ^C in command stops execution
756 (throw 'teco-exit nil))))
760 ;; set/get search mode flag
761 (teco-set-var 'teco-ctrl-x))
765 (let ((macro-name (teco-get-qspec nil
766 (teco-get-command teco-trace))))
767 (teco-push-macro-stack)
768 (setq teco-command-string (aref teco-qreg-text macro-name)
769 teco-command-pointer 0)))
774 (if (and teco-exp-flag1 (<= teco-exp-val1 0))
775 ;; if this is not to be executed, just skip the
778 ;; push iteration stack
779 (teco-push-iter-stack teco-command-pointer
780 teco-exp-flag1 teco-exp-val1)
781 ;; consume the argument
782 (setq teco-exp-flag1 nil)))
787 (if (not teco-iteration-stack)
789 ;; decrement count and pop conditionally
790 (teco-pop-iter-stack nil)
792 (setq teco-exp-flag1 nil
798 ;; semicolon iteration exit
799 (if (not teco-iteration-stack)
802 (if (if (>= (if teco-exp-flag1
804 teco-search-result) 0)
805 (not teco-colon-flag)
809 (teco-pop-iter-stack t)))
810 ;; consume argument and colon
811 (setq teco-exp-flag1 nil
817 ;; must be an argument
818 (if (not teco-exp-flag1)
821 (setq teco-exp-flag1 nil
823 (let* (;; get the test specification
824 (c (aref teco-mapch-l (teco-get-command teco-trace)))
825 ;; determine whether the test is true
826 (test (cond ((eq c ?a)
827 (/= (logand (aref teco-char-types teco-exp-val1)
830 (/= (logand (aref teco-char-types teco-exp-val1)
833 (/= (logand (aref teco-char-types teco-exp-val1)
835 ((or (eq c ?e) (eq c ?f) (eq c ?u) (eq c ?=))
837 ((or (eq c ?g) (eq c ?>))
839 ((or (eq c ?l) (eq c ?s) (eq c ?t) (eq c ?<))
842 (/= teco-exp-val1 0))
844 (/= (logand (aref teco-char-types teco-exp-val1)
847 (/= (logand (aref teco-char-types teco-exp-val1)
850 (/= (logand (aref teco-char-types teco-exp-val1)
853 (teco-error "IQC")))))
855 ;; if the conditional isn't satisfied, read
856 ;; to matching | or '
860 (while (progn (setq c (teco-skipto))
873 ;; ignore it if executing
881 (while (progn (setq c (teco-skipto))
887 (setq ll (1- ll))))))
891 (if (not teco-exp-flag1)
893 (aset teco-qreg-number
894 (teco-get-qspec 0 (teco-get-command teco-trace))
896 (setq teco-exp-flag1 teco-exp-flag2 ; command's value is second arg
897 teco-exp-val1 teco-exp-val2
903 ;; Qn is numeric val, :Qn is # of chars, mQn is mth char
904 (let ((mm (teco-get-qspec (or teco-colon-flag teco-exp-flag1)
905 (teco-get-command teco-trace))))
906 (if (not teco-exp-flag1)
907 (setq teco-exp-val1 (if teco-colon-flag
909 (length (aref teco-qreg-text mm))
911 (aref teco-qreg-number mm))
914 (let ((v (aref teco-qreg-text mm)))
915 (setq teco-exp-val1 (condition-case nil
916 (aref v teco-exp-val1)
918 teco-exp-op 'start)))
919 (setq teco-colon-flag nil)))
923 (let* ((mm (teco-get-qspec nil (teco-get-command teco-trace)))
924 (v (+ (aref teco-qreg-number mm) (teco-get-value 1))))
925 (aset teco-qreg-number mm v)
926 (setq teco-exp-val1 v
931 (let ((p (+ (point) (teco-get-value 1))))
932 (if (or (< p (point-min)) (> p (point-max)))
935 (setq teco-exp-flag2 nil))))
939 (let ((p (- (point) (teco-get-value 1))))
940 (if (or (< p (point-min)) (> p (point-max)))
943 (setq teco-exp-flag2 nil))))
947 (let ((p (teco-get-value (point-min))))
948 (if (or (< p (point-min)) (> p (point-max)))
951 (setq teco-exp-flag2 nil))))
955 ;; move forward by lines
956 (forward-char (teco-lines (teco-get-value 1))))
960 ;; number of characters until the nth line feed
961 (setq teco-exp-val1 (teco-lines (teco-get-value 1))
966 ;; print numeric value
967 (if (not teco-exp-flag1)
970 (if (teco-peek-command ?=)
971 ;; at least one more =
974 (teco-get-command teco-trace)
975 (if (teco-peek-command ?=)
979 (teco-get-command teco-trace)
987 ;; add newline if no colon
988 (if (not teco-colon-flag)
990 ;; absorb argument, etc.
991 (setq teco-exp-flag1 nil
1000 (let ((text (teco-get-text-arg)))
1002 (setq teco-ctrl-s (1+ (length text))))
1004 (setq teco-colon-flag nil
1006 teco-exp-flag2 nil))
1010 (let ((text (teco-get-text-arg)))
1014 ;; text argument must be null
1015 (or (string-equal text "") (teco-error "IIA"))
1016 ;; insert the character
1017 (insert teco-exp-val1)
1018 (setq teco-ctrl-s 1)
1020 (setq teco-exp-op 'start))
1021 ;; otherwise, insert the text
1023 (setq teco-ctrl-s (length text)))
1025 (setq teco-colon-flag nil
1027 teco-exp-flag2 nil)))
1031 (let ((args (teco-line-args nil)))
1032 (teco-output (buffer-substring (car args) (cdr args)))))
1036 (let ((ll (teco-get-value 1)))
1037 (teco-output (buffer-substring (+ (point) (teco-lines (- 1 ll)))
1038 (+ (point) (teco-lines ll))))))
1042 (teco-output (teco-get-text-arg nil ?\C-a))
1043 (setq teco-at-flag nil
1047 teco-exp-op 'start))
1051 (if (not teco-exp-flag2)
1052 ;; if only one argument
1053 (delete-char (teco-get-value 1))
1054 ;; if two arguments, treat as n,mK
1055 (let ((ll (teco-line-args 1)))
1056 (delete-region (car ll) (cdr ll)))))
1060 (let ((ll (teco-line-args 1)))
1061 (delete-region (car ll) (cdr ll))))
1065 (let* ((mm (teco-get-qspec nil (teco-get-command teco-trace)))
1066 (text-arg (teco-get-text-arg))
1067 (text (if (not teco-exp-flag1)
1069 (if (string-equal text-arg "")
1070 (char-to-string teco-exp-val1)
1071 (teco-error "IIA")))))
1072 ;; if :, append to the register
1073 (aset teco-qreg-text mm (if teco-colon-flag
1074 (concat (aref teco-qreg-text mm) text)
1076 ;; clear various flags
1077 (setq teco-exp-flag1 nil
1080 teco-exp-flag1 nil)))
1084 (let* ((mm (teco-get-qspec nil (teco-get-command teco-trace)))
1085 (args (teco-line-args 0))
1086 (text (buffer-substring (car args) (cdr args))))
1087 ;; if :, append to the register
1088 (aset teco-qreg-text mm (if teco-colon-flag
1089 (concat (aref teco-qreg-text mm) text)
1091 ;; clear various flags
1092 (setq teco-exp-flag1 nil
1095 teco-exp-flag1 nil)))
1099 (let ((mm (teco-get-qspec t (teco-get-command teco-trace))))
1101 (teco-output (aref teco-qreg-text mm))
1102 (insert (aref teco-qreg-text mm)))
1103 (setq teco-colon-flag nil)))
1107 (let ((mm (teco-get-qspec t (teco-get-command teco-trace))))
1108 (setq teco-qreg-stack
1109 (cons (cons (aref teco-qreg-text mm)
1110 (aref teco-qreg-number mm))
1115 (let ((mm (teco-get-qspec t (teco-get-command teco-trace))))
1117 (setq teco-exp-flag1 t
1118 teco-exp-val1 (if teco-qreg-stack -1 0))
1120 (let ((pop (car teco-qreg-stack)))
1121 (aset teco-qreg-text mm (car pop))
1122 (aset teco-qreg-number mm (cdr pop))
1123 (setq teco-qreg-stack (cdr teco-qreg-stack)))
1124 (teco-error "CPQ")))
1125 (setq teco-colon-flag nil)))
1129 (if (not teco-exp-flag1)
1130 ;; no argument; read number
1135 (setq c (char-after p))
1145 (setq c (char-after p))
1146 (and c (>= c ?0) (<= c ?7)))
1148 n (+ c -48 (* n 8)))))
1151 (setq c (char-after p))
1152 (and c (>= c ?0) (<= c ?9)))
1154 n (+ c -48 (* n 10)))))
1157 (setq c (char-after p))
1160 (and (>= c ?0) (<= c ?9))
1161 (and (>= c ?a) (<= c ?f))
1162 (and (>= c ?A) (<= c ?F)))))
1165 ;; convert 'a' to 10
1168 ;; convert 'A' to 10
1173 (setq teco-exp-val1 (* n sign)
1175 teco-ctrl-s (- (point) p)))
1176 ;; argument: insert it as a digit string
1177 (insert (format (cond
1178 ((= teco-ctrl-r 8) "%o")
1179 ((= teco-ctrl-r 10) "%d")
1182 (setq teco-exp-flag1 nil
1183 teco-exp-op 'start)))
1190 (teco-output teco-exp-val1)
1191 (setq teco-exp-flag1 nil))
1192 ;; input a character
1193 (let* ((echo-keystrokes 0)
1196 (setq teco-exp-val1 c
1197 teco-exp-flag1 t))))
1201 (let ((arg (teco-get-text-arg))
1202 (count (if teco-exp-flag1 teco-expr-val1 1))
1204 (if (not (string-equal arg ""))
1205 (setq regexp (teco-parse-search-string arg)
1206 teco-last-search-string arg
1207 teco-last-search-regexp regexp)
1208 (setq regexp (teco-last-search-regexp)
1209 arg teco-last-search-string))
1213 (re-search-forward regexp nil t count))
1215 (re-search-backward regexp nil t count))
1217 ;; 0s always is successful
1219 ;; if ::s, restore point
1220 (if (eq teco-colon-flag 2)
1222 ;; if no real or implied colon, error if not found
1223 (if (and (not result)
1224 (not teco-colon-flag)
1225 (/= (teco-peekcmdc) 34))
1227 ;; set return results
1228 (setq teco-exp-flag2 nil
1233 (setq teco-exp-flag1 t
1234 teco-exp-val1 (if result -1 0))
1235 (setq teco-exp-flag1 nil)))))
1237 (defun teco-parse-search-string (s)
1243 (setq r (concat r (teco-parse-search-string-1))))
1246 (defun teco-parse-search-string-1 ()
1252 ((eq c ?\C-e) ; ^E - special match characters
1253 (teco-parse-search-string-e))
1254 ((eq c ?\C-n) ; ^Nx - match all but x
1255 (teco-parse-search-string-n))
1256 ((eq c ?\C-q) ; ^Qx - use x literally
1257 (teco-parse-search-string-q))
1258 ((eq c ?\C-s) ; ^S - match separator chars
1260 ((eq c ?\C-x) ; ^X - match any character
1262 (t ; ordinary character
1263 (teco-parse-search-string-char c))))
1265 (defun teco-parse-search-string-char (c)
1266 (regexp-quote (char-to-string c)))
1268 (defun teco-parse-search-string-q ()
1273 (teco-parse-search-string-char c))
1275 (defun teco-parse-search-string-e ()
1281 ((or (eq c ?a) (eq c ?A)) ; ^EA - match alphabetics
1283 ((or (eq c ?c) (eq c ?C)) ; ^EC - match symbol constituents
1285 ((or (eq c ?d) (eq c ?D)) ; ^ED - match numerics
1287 ((eq c ?g) ; ^EGq - match any char in q-reg
1288 (teco-parse-search-string-e-g))
1289 ((or (eq c ?l) (eq c ?L)) ; ^EL - match line terminators
1291 ((eq c ?q) ; ^EQq - use contents of q-reg
1292 (teco-parse-search-string-e-q))
1293 ((eq c ?r) ; ^ER - match alphanumerics
1295 ((eq c ?s) ; ^ES - match non-null space/tab seq
1297 ((eq c ?v) ; ^EV - match lower case alphabetic
1299 ((eq c ?w) ; ^EW - match upper case alphabetic
1301 ((eq c ?x) ; ^EX - match any character
1304 (teco-error "ISS"))))
1306 (defun teco-parse-search-string-e-q ()
1311 (regexp-quote (aref reco:q-reg-text c)))
1313 (defun teco-parse-search-string-e-g ()
1318 (let* ((q (aref teco-qreg-text c))
1321 (one-char (= len 1))
1322 (dash-present (string-match "-" q))
1323 (caret-present (string-match "\\^" q))
1324 (outbracket-present (string-match "]" q))
1330 (teco-parse-search-string-char c))
1332 (while (setq p (string-match "^]\\^"))
1333 (setq q (concat (substring q 1 p) (substring q (1+ p)))))
1336 (if outbracket-present "]" "")
1337 (if dash-present "---" "")
1339 (if caret-present "^" ""))))))
1341 (defun teco-parse-search-string-n ()
1342 (let ((p (teco-parse-search-string-1)))
1345 (if (= (aref p 1) ?^)
1346 ;; complement character set
1347 (if (= (length p) 4)
1348 ;; complement of one character
1349 (teco-parse-search-string-char (aref p 2))
1350 ;; complement of more than one character
1351 (concat "[" (substring p 2)))
1352 ;; character set - invert it
1353 (concat "[^" (substring p 1))))
1355 ;; single quoted character
1356 (concat "[^" (substring p 1) "]"))
1359 (if (string-equal p "-")
1361 (concat "[^" p "]"))))))
1365 (let ((label (teco-get-text-arg))
1366 (index (and teco-exp-flag1 teco-exp-val1)))
1367 (setq teco-exp-flag1 nil)
1368 ;; handle computed goto by extracting the proper label
1371 ;; argument < 0 is a noop
1373 ;; otherwise, find the n-th label (0-origin)
1374 (setq label (concat label ","))
1376 (while (and (> index 0)
1377 (setq p (string-match "," label p))
1379 (setq index (1- index)))
1380 (setq q (string-match "," label p))
1381 (setq label (substring label p q)))))
1382 ;; if the label is non-null, find the correct label
1383 ;; start from beginning of iteration or macro, and look for tag
1384 (setq teco-command-pointer
1385 (if teco-iteration-stack
1386 ;; if in iteration, start at beginning of iteration
1387 (aref (car teco-iteration-stack) 0)
1388 ;; if not in iteration, start at beginning of command or macro
1394 ;; look for interesting things, including !
1396 (setq c (teco-skipto t))
1398 ((= c ?<) ; start of iteration
1399 (setq level (1+ level)))
1400 ((= c ?>) ; end of iteration
1402 (teco-pop-iter-stack t)
1403 (setq level (1- level))))
1404 ((= c ?!) ; start of tag
1405 (setq p (string-match "!" teco-command-string teco-command-pointer))
1407 (string-equal label (substring teco-command-string
1408 teco-command-pointer
1411 (setq teco-command-pointer (1+ p))
1412 (throw 'label nil))))))))))
1416 ;; 'a' must be used as ':a'
1417 (if (and teco-exp-flag1 teco-colon-flag)
1418 (let ((char (+ (point) teco-exp-val1)))
1420 (if (and (>= char (point-min))
1421 (< char (point-max)))
1424 teco-colon-flag nil))
1425 (teco-error "ILL")))
1428 ;; Routines to get next character from command buffer
1429 ;; getcmdc0, when reading beyond command string, pops
1430 ;; macro stack and continues.
1431 ;; getcmdc, in similar circumstances, reports an error.
1432 ;; If pushcmdc() has returned any chars, read them first
1433 ;; routines type characters as read, if argument != 0.
1435 (defun teco-get-command0 (trace)
1436 ;; get the next character
1438 (while (not (condition-case nil
1439 (setq char (aref teco-command-string teco-command-pointer))
1440 ;; if we've exhausted the string, pop the macro stack
1441 ;; if we exhaust the macro stack, exit
1442 (error (teco-pop-macro-stack)
1444 ;; bump the command pointer
1445 (setq teco-command-pointer (1+ teco-command-pointer))
1446 ;; trace, if requested
1447 (and trace (teco-trace-type char))
1448 ;; return the character
1451 ;; while (cptr.dot >= cptr.z) /* if at end of this level, pop macro stack
1453 ;; if (--msp < &mstack[0]) /* pop stack; if top level
1455 ;; msp = &mstack[0]; /* restore stack pointer
1456 ;; cmdc = ESC; /* return an ESC (ignored)
1457 ;; exitflag = 1; /* set to terminate execution
1458 ;; return(cmdc); /* exit "while" and return
1461 ;; cmdc = cptr.p->ch[cptr.c++]; /* get char
1462 ;; ++cptr.dot; /* increment character count
1463 ;; if (trace) type_char(cmdc); /* trace
1464 ;; if (cptr.c > CELLSIZE-1) /* and chain if need be
1466 ;; cptr.p = cptr.p->f;
1473 (defun teco-get-command (trace)
1474 ;; get the next character
1475 (let ((char (condition-case nil
1476 (aref teco-command-string teco-command-pointer)
1477 ;; if we've exhausted the string, give error
1479 (teco-error (if teco-macro-stack "UTM" "UTC"))))))
1480 ;; bump the command pointer
1481 (setq teco-command-pointer (1+ teco-command-pointer))
1482 ;; trace, if requested
1483 (and trace (teco-trace-type char))
1484 ;; return the character
1487 ;; char getcmdc(trace)
1489 ;; if (cptr.dot++ >= cptr.z) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
1492 ;; cmdc = cptr.p->ch[cptr.c++]; /* get char
1493 ;; if (trace) type_char(cmdc); /* trace
1494 ;; if (cptr.c > CELLSIZE-1) /* and chain if need be
1496 ;; cptr.p = cptr.p->f;
1504 ;; peek at next char in command string, return 1 if it is equal
1505 ;; (case independent) to argument
1507 (defun teco-peek-command (arg)
1509 (eq (aref teco-mapch-l (aref teco-command-string teco-command-pointer))
1510 (aref teco-mapch-l arg))
1513 ;; int peekcmdc(arg)
1516 ;; return(((cptr.dot < cptr.z) && (mapch_l[cptr.p->ch[cptr.c]] == mapch_l[arg])) ? 1 : 0);
1519 (defun teco-get-text-arg (&optional term-char default-term-char)
1520 ;; figure out what the terminating character is
1521 (setq teco-term-char (or term-char
1523 (teco-get-command teco-trace)
1524 (or default-term-char
1530 (setq c (teco-get-command teco-trace))
1531 (/= c teco-term-char))
1532 (setq s (concat s (char-to-string c))))
1536 ;; Routines to manipulate the stacks
1538 ;; Pop the macro stack. Throw to 'teco-exit' if the stack is empty.
1539 (defun teco-pop-macro-stack ()
1540 (if teco-macro-stack
1541 (let ((frame (car teco-macro-stack)))
1542 (setq teco-macro-stack (cdr teco-macro-stack)
1543 teco-command-string (aref frame 0)
1544 teco-command-pointer (aref frame 1)
1545 teco-exec-flags (aref frame 2)
1546 teco-iteration-stack (aref frame 3)
1547 teco-cond-stack (aref frame 4)))
1548 (throw 'teco-exit nil)))
1550 ;; Push the macro stack.
1551 (defun teco-push-macro-stack ()
1552 (setq teco-macro-stack
1553 (cons (vector teco-command-string
1554 teco-command-pointer
1556 teco-iteration-stack
1560 ;; Pop the expression stack.
1561 (defun teco-pop-exp-stack ()
1562 (let ((frame (car teco-exp-stack)))
1563 (setq teco-exp-stack (cdr teco-exp-stack)
1564 teco-exp-val1 (aref frame 0)
1565 teco-exp-flag1 (aref frame 1)
1566 teco-exp-val2 (aref frame 2)
1567 teco-exp-flag2 (aref frame 3)
1568 teco-exp-exp (aref frame 4)
1569 teco-exp-op (aref frame 5))))
1571 ;; Push the expression stack.
1572 (defun teco-push-exp-stack ()
1573 (setq teco-exp-stack
1574 (cons (vector teco-exp-val1
1582 ;; Pop the iteration stack
1583 ;; if arg t, exit unconditionally
1584 ;; else check exit conditions and exit or reiterate
1585 (defun teco-pop-iter-stack (arg)
1586 (let ((frame (car teco-iteration-stack)))
1588 (not (aref frame 1))
1589 ;; test against 1, since one iteration has already been done
1590 (<= (aref frame 2) 1))
1592 (setq teco-iteration-stack (cdr teco-iteration-stack))
1593 ;; continue with iteration
1595 (aset frame 2 (1- (aref frame 2)))
1596 ;; reset command pointer
1597 (setq teco-command-pointer (aref frame 0)))))
1599 ;; Push the iteration stack
1600 (defun teco-push-iter-stack (pointer flag count)
1601 (setq teco-iteration-stack
1602 (cons (vector pointer
1605 teco-iteration-stack)))
1607 (defun teco-find-enditer ()
1611 (while (progn (setq c (teco-skipto))
1615 (setq icnt (1+ icnt))
1616 (setq icnt (1- icnt)))))))
1621 (defvar teco-output-buffer (get-buffer-create "*Teco Output*")
1622 "The buffer into which Teco output is written.")
1624 (defun teco-out-init ()
1625 ;; Recreate the teco output buffer, if necessary
1626 (setq teco-output-buffer (get-buffer-create "*Teco Output*"))
1628 (set-buffer teco-output-buffer)
1629 ;; get a fresh line in output buffer
1630 (goto-char (point-max))
1632 ;; remember where to start displaying
1633 (setq teco-output-start (point))
1634 ;; clear minibuffer, in case we have to display in it
1635 (save-window-excursion
1636 (select-window (minibuffer-window))
1638 ;; if output is visible, position it correctly
1639 (let ((w (get-buffer-window teco-output-buffer)))
1642 (set-window-start w teco-output-start)
1643 (set-window-point w teco-output-start))))))
1645 (defun teco-output (s)
1646 (let ((w (get-buffer-window teco-output-buffer))
1647 (b (current-buffer))
1648 (sw (selected-window)))
1649 ;; Put the text in the output buffer
1650 (set-buffer teco-output-buffer)
1651 (goto-char (point-max))
1656 ;; if output is visible, move the window point to the end
1657 (set-window-point w p)
1658 ;; Otherwise, we have to figure out how to display the text
1659 ;; Has a newline followed by another character been added to the
1660 ;; output buffer? If so, we have to make the output buffer visible.
1662 (set-buffer teco-output-buffer)
1664 (search-backward "\n" teco-output-start t))
1665 ;; a newline has been seen, clear the minibuffer and make the
1666 ;; output buffer visible
1668 (save-window-excursion
1669 (select-window (minibuffer-window))
1671 (let ((pop-up-windows t))
1672 (pop-to-buffer teco-output-buffer)
1674 (set-window-start w teco-output-start)
1675 (set-window-point w p)
1676 (select-window sw)))
1677 ;; a newline has not been seen, add output to minibuffer
1678 (save-window-excursion
1679 (select-window (minibuffer-window))
1680 (goto-char (point-max))
1683 ;; Output a character of tracing information
1684 (defun teco-trace-type (c)
1685 (teco-output (if (= c ?\e)
1690 (defun teco-error (code)
1691 (let ((text (cdr (assoc code teco-error-texts))))
1692 (teco-output (concat (if (save-excursion (set-buffer teco-output-buffer)
1693 (/= (point) teco-output-start))
1696 "? " code " " text))
1698 (if debug-on-error (debug nil code text))
1699 (throw 'teco-exit nil)))
1704 ;; copy characters from command string to buffer
1705 (defun teco-moveuntil (string pointer terminate trace)
1708 (while (/= (aref string pointer) terminate)
1709 (and teco-trace (teco-trace-type (aref string pointer)))
1710 (insert (aref string pointer))
1711 (setq pointer (1+ pointer))
1712 (setq count (1+ count)))
1713 (error (teco-error (if teco-macro-stack "UTM" "UTC"))))
1716 ;; Convert character to q-register name
1717 ;; If file-or-search is t, allow _, *, %, #
1718 (defun teco-get-qspec (file-or-search char)
1720 (setq char (aref teco-mapch-l char))
1721 ;; test that it's valid
1722 (if (= (logand (aref teco-qspec-valid char) (if file-or-search 2 1)) 0)
1726 ;; Set or get value of a variable
1727 (defun teco-set-var (var)
1731 ;; if two arguments, they they are <clear bits>, <set bits>
1732 (set var (logior (logand (symbol-value var) (lognot teco-exp-val2))
1734 ;; if one argument, it is the new value
1735 (set var teco-exp-val1))
1736 ;; consume argument(s)
1737 (setq teco-exp-flag2 nil
1738 teco-exp-flag1 nil))
1739 ;; if no arguments, fetch the value
1740 (setq teco-exp-val1 (symbol-value var)
1743 ;; Get numeric argument
1744 (defun teco-get-value (default)
1748 (if (eq teco-exp-op 'sub)
1752 (setq teco-exp-flag1 nil
1753 teco-exp-op 'start)))
1755 ;; Get argument measuring in lines
1756 (defun teco-lines (r)
1759 (if (search-forward "\n" nil t r)
1762 (if (search-backward "\n" nil t (- 1 r))
1767 ;; routine to handle args for K, T, X, etc.
1768 ;; if two args, 'char x' to 'char y'
1769 ;; if just one arg, then n lines (default 1)
1770 (defun teco-line-args (arg)
1772 (cons teco-exp-val1 teco-exp-val2)
1773 (cons (point) (+ (point) (teco-lines (if teco-exp-flag1
1777 ;; routine to skip to next ", ', |, <, or >
1778 ;; skips over these chars embedded in text strings
1779 ;; stops in ! if argument is t
1780 ;; returns character found
1781 (defun teco-skipto (&optional arg)
1783 (let (;; "at" prefix
1792 (setq skipc (teco-get-command nil)
1793 ta (aref teco-spec-chars skipc))
1794 ;; if char is ^, treat next char as control
1796 (setq skipc (logand 31 (teco-get-command nil))
1797 ta (aref teco-spec-chars skipc)))
1798 (= (logand ta 51) 0)) ; read until something interesting
1801 (if (/= (logand ta 32) 0)
1802 (teco-get-command nil)) ; if command takes a Q spec,
1804 (if (/= (logand ta 16) 0) ; sought char found: quit
1806 (if (= skipc ?\") ; quote must skip next char
1807 (teco-get-command nil))
1808 (throw 'teco-skip skipc)))
1809 (if (/= (logand ta 1) 0) ; other special char
1811 ((eq skipc ?@) ; use alternative text terminator
1813 ((eq skipc ?\C-^) ; ^^ is value of next char
1815 (teco-get-command nil))
1816 ((eq skipc ?\C-a) ; type text
1817 (setq term (if atsw (teco-get-command nil) ?\C-a)
1819 (while (/= (teco-get-command nil) term)
1821 ((eq skipc ?!) ; tag
1823 (throw 'teco-skip skipc))
1824 (while (/= (teco-get-command nil) ?!)
1825 nil)) ; skip until next !
1827 (eq skipc ?f)) ; first char of two-letter E or F
1829 nil))) ; not implemented
1830 (if (/= (logand ta 2) 0) ; command with a text
1833 (setq term (if atsw (teco-get-command nil) ?\e)
1835 (while (/= (teco-get-command nil) term)
1840 (defvar teco-command-keymap
1841 ;; This is what used to be (make-vector 128 'teco-command-self-insert)
1843 (let ((map (make-keymap)) (n 127))
1845 (define-key map (if (< n 32) (list 'control (+ n 32)) n)
1846 'teco-command-self-insert)
1849 "Keymap used while reading teco commands.")
1851 (define-key teco-command-keymap "\^g" 'teco-command-ctrl-g)
1852 (define-key teco-command-keymap "\^m" 'teco-command-return)
1853 (define-key teco-command-keymap "\^u" 'teco-command-ctrl-u)
1854 (define-key teco-command-keymap "\e" 'teco-command-escape)
1855 (define-key teco-command-keymap "\^?" 'teco-command-delete)
1857 (defvar teco-command-escapes nil
1858 "Records where ESCs are, since they are represented in the command buffer
1862 (defun teco-command ()
1863 "Read and execute a Teco command string."
1865 (let* ((teco-command-escapes nil)
1866 (command (catch 'teco-command-quit
1867 (read-from-minibuffer teco-prompt nil
1868 teco-command-keymap))))
1871 (while teco-command-escapes
1872 (aset command (car teco-command-escapes) ?\e)
1873 (setq teco-command-escapes (cdr teco-command-escapes)))
1874 (setq teco-output-buffer (get-buffer-create "*Teco Output*"))
1876 (set-buffer teco-output-buffer)
1877 (goto-char (point-max))
1878 (insert teco-prompt command))
1879 (teco-execute-command command)))))
1881 (defun teco-read-command ()
1882 "Read a teco command string from the user."
1883 (let ((command (catch 'teco-command-quit
1884 (read-from-minibuffer teco-prompt nil
1885 teco-command-keymap)))
1886 teco-command-escapes)
1888 (while teco-command-escapes
1889 (aset command (car teco-command-escapes) ?\e)
1890 (setq teco-command-escapes (cdr teco-command-escapes))))
1893 (defun teco-command-self-insert ()
1895 (insert last-command-char)
1896 (if (not (pos-visible-in-window-p))
1897 (enlarge-window 1)))
1899 (defun teco-command-ctrl-g ()
1902 (throw 'teco-command-quit nil))
1904 (defun teco-command-return ()
1906 (setq last-command-char ?\n)
1907 (teco-command-self-insert))
1909 (defun teco-command-escape ()
1911 ;; Two ESCs in a row terminate the command string
1912 (if (eq last-command 'teco-command-escape)
1913 (throw 'teco-command-quit (buffer-string)))
1914 (setq teco-command-escapes (cons (1- (point)) teco-command-escapes))
1915 (setq last-command-char ?$)
1916 (teco-command-self-insert))
1918 (defun teco-command-ctrl-u ()
1920 ;; delete the characters
1922 ;; forget that they were ESCs
1923 (while (and teco-command-escapes (<= (point) (car teco-command-escapes)))
1924 (setq teco-command-escapes (cdr teco-command-escapes)))
1925 ;; decide whether to shrink the window
1926 (while (let ((a (insert ?\n))
1927 (b (pos-visible-in-window-p))
1928 (c (backward-delete-char 1)))
1932 (defun teco-command-delete ()
1934 ;; delete the character
1935 (backward-delete-char 1)
1936 ;; forget that it was an ESC
1937 (if (and teco-command-escapes (= (point) (car teco-command-escapes)))
1938 (setq teco-command-escapes (cdr teco-command-escapes)))
1939 ;; decide whether to shrink the window
1941 (if (prog1 (pos-visible-in-window-p)
1942 (backward-delete-char 1))
1947 ;;; teco.el ends here