Initial commit, 3-52-19 alpha
[cls.git] / src / c / macintosh / editwindows.c
blobc9014614e6a059ab408a68a01e3c50609f4deecd
1 /* edit - Macintosh editing functions */
2 /* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
3 /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
4 /* You may give out copies of this software; for conditions see the */
5 /* file COPYING included with this distribution. */
7 #include "xlisp.h"
8 #include "xlstat.h"
9 #include "xlgraph.h"
10 #include "TransEdit1.h"
12 # define MIN(x,y) (((x) < (y)) ? (x) : (y))
14 # define BUFMAX STRMAX
15 # define MAXCOUNT 10000L
16 # define KEEPCOUNT 5000L
18 extern WindowPtr ttyWind;
19 extern LVAL s_true, sk_remove, s_input_stream, s_input_enabled;
20 static char ttybuf[BUFMAX];
21 static int ttybufcount = 0, ttyfixcount = 0;
23 # define enter 3
24 # ifndef shiftKey
25 # define shiftKey 0x0200
26 # endif
28 /* forward declarations */
29 LOCAL int paste_stream(WindowPtr w, LVAL stream, int input);
30 LOCAL VOID flush_window(WindowPtr w, long byteCount);
31 LOCAL VOID adjust_fixed_count(WindowPtr w);
32 LOCAL int input_enabled(WindowPtr w);
33 LOCAL VOID tty_return(void);
34 LOCAL int GetInputLine(void);
35 LOCAL int check_parens(unsigned char *s, int n);
36 LOCAL VOID pardelay(void);
37 LOCAL VOID do_tab(TEHandle teEdit, int start);
38 LOCAL VOID fix_blanks(TEHandle teEdit, int nblanks, int curline);
39 LOCAL int at_text_end(TEHandle teEdit);
40 LOCAL int last_is_return(TEHandle teEdit);
41 LOCAL int num_to_skip(unsigned char *s, int n);
42 LOCAL int is_special(unsigned char *s, int n);
43 LOCAL pascal VOID close_listener(void);
44 LOCAL pascal VOID tty_key(void);
45 LOCAL pascal VOID edit_idle(void);
46 LOCAL pascal VOID close_edit(void);
47 LOCAL VOID AdjusrDisplay(WindowPtr w);
49 LOCAL VOID AdjustDisplay(WindowPtr w)
51 GrafPtr port;
52 GetPort(&port);
53 EWindowAdjustDisplay (w);
54 SetPort(port);
57 static LVAL get_output_stream(WindowPtr w)
59 LVAL object = get_window_object(w), s_output_stream = xlenter("OUTPUT-STREAM");
60 LVAL stream = NIL;
62 if (objectp(object)) lex_slot_value(object, s_output_stream, &stream);
63 return(ustreamp(stream) ? stream :NIL);
66 static LVAL get_input_stream(void)
68 if (ttyWind == nil) return(NIL);
69 else return(getvalue(s_input_stream));
72 static VOID flush_output_stream(WindowPtr w)
74 LVAL stream = get_output_stream(w);
75 int ch;
76 TEHandle te = GetEWindowTE(w);
78 if (w == ttyWind) TtyFlush();
79 if (stream != NIL && (ch = xlgetc(stream)) != EOF) {
80 xlungetc(stream, ch);
81 paste_stream(w, stream, FALSE);
82 if ((w == ttyWind || ttyWind == nil) && (*te)->teLength > MAXCOUNT)
83 flush_window(w, (*te)->teLength - KEEPCOUNT);
84 adjust_fixed_count(w);
88 LOCAL VOID flush_window(WindowPtr w, long byteCount)
90 TEHandle te = GetEWindowTE(w);
92 TESetSelect (0L, byteCount, te); /* select text */
93 TEDelete (te); /* clobber it */
94 TESetSelect((*te)->teLength, (*te)->teLength, te);
95 adjust_fixed_count(w);
96 AdjustDisplay(w);
99 static VOID InsertText(char *buf, long count, TEHandle te)
101 if ((*te)->teLength + count > 32000) xlfail("Buffer is too big");
102 else TEInsert(buf, count, te);
105 static get_fixed_count(WindowPtr w, int *count)
107 if (w == ttyWind || ttyWind == nil) {
108 if (count != nil) *count = ttyfixcount;
109 return(TRUE);
111 else return(FALSE);
114 static VOID set_fixed_count(WindowPtr w, int count)
116 if (w == ttyWind || ttyWind == nil) ttyfixcount = count;
119 VOID adjust_insert(WindowPtr w)
121 int count;
122 TEHandle te = GetEWindowTE(w);
124 flush_output_stream(w);
125 if (get_fixed_count(w, &count) && (*te)->selStart < count) {
126 TESetSelect((*te)->teLength, (*te)->teLength, te);
130 LOCAL VOID adjust_fixed_count(WindowPtr w)
132 int count;
133 TEHandle te = GetEWindowTE(w);
135 if (get_fixed_count(w, &count)) {
136 set_fixed_count(w, (*te)->teLength);
138 if (get_fixed_count(w, &count) && (*te)->selStart < count) {
139 TESetSelect((*te)->teLength, (*te)->teLength, te);
143 LOCAL int paste_stream(WindowPtr w, LVAL stream, int input)
145 int buffpos = 0, ch;
147 if (! IsEWindow(w) || stream == NIL) return(FALSE);
149 while((ch = xlgetc(stream)) != EOF) {
150 if (ch == '\n') ch = RETURNCHAR;
151 buf[buffpos++] = ch;
152 if (buffpos > BUFMAX) {
153 InsertText(buf, (long) buffpos, GetEWindowTE(w));
154 buffpos = 0;
157 InsertText(buf, (long) buffpos, GetEWindowTE(w));
158 AdjustDisplay(w);
159 if (input && w == ttyWind) return_action(GetEWindowTE(w));
160 if (! input_enabled(w) || w == ttyWind) SetEWindowDirty(w, FALSE);
161 return(TRUE);
164 static paste_string(WindowPtr w, char *str, int input)
166 int buffpos = 0, ch;
167 long len;
169 if (! IsEWindow(w) || str == nil) return(FALSE);
171 len = strlen(str);
172 while(len -- > 0) {
173 ch = *str++;
174 if (ch == '\n') ch = RETURNCHAR;
175 buf[buffpos++] = ch;
176 if (buffpos > BUFMAX) {
177 InsertText(buf, (long) buffpos, GetEWindowTE(w));
178 buffpos = 0;
181 InsertText(buf, (long) buffpos, GetEWindowTE(w));
182 AdjustDisplay(w);
183 if (input && w == ttyWind) return_action(GetEWindowTE(w));
184 return(TRUE);
185 AdjustDisplay(w);
186 if (input && w == ttyWind) return_action(GetEWindowTE(w));
187 if (! input_enabled(w) || w == ttyWind) SetEWindowDirty(w, FALSE);
188 return(TRUE);
191 LOCAL int input_enabled(WindowPtr w)
193 LVAL enabled = s_true, object = get_window_object(w);
195 if (w == ttyWind) return(TRUE);
196 if (objectp(object)) lex_slot_value(object, s_input_enabled, &enabled);
197 return((enabled != NIL));
200 static VOID tty_enter(void)
202 TEHandle te = GetEWindowTE(ttyWind);
204 if (te == nil) return;
205 adjust_insert(ttyWind);
206 if ((*te)->selStart < (*te)->teLength)
207 TESetSelect((*te)->teLength, (*te)->teLength, te);
208 else tty_return();
211 LOCAL VOID tty_return(void)
213 TEHandle te = GetEWindowTE(ttyWind);
215 if (te == nil) return;
216 adjust_insert(ttyWind);
217 TEKey (RETURNCHAR, te);
218 AdjustDisplay(ttyWind);
219 return_action(te);
222 VOID TtyPutc(int c)
224 if (c == '\n') c = RETURNCHAR;
225 ttybuf[ttybufcount++] = c;
226 if (c == RETURNCHAR || ttybufcount >= (BUFMAX - 1)) TtyFlush();
229 VOID TtyPrint(char *s)
231 while (strlen(s) > 0) TtyPutc(*s++);
232 TtyFlush();
235 VOID TtyFlush(void)
237 TEHandle te = GetEWindowTE(ttyWind);
238 int count;
240 if (ttybufcount > 0) {
241 if (get_fixed_count(ttyWind, &count) && (*te)->selStart < count) {
242 TESetSelect((*te)->teLength, (*te)->teLength, te);
244 adjust_fixed_count(ttyWind);
245 InsertText(ttybuf, (long) ttybufcount, GetEWindowTE(ttyWind));
246 ttybufcount = 0;
247 if ((*te)->teLength > MAXCOUNT) {
248 flush_window(ttyWind, (*te)->teLength - KEEPCOUNT);
250 TESetSelect((*te)->teLength, (*te)->teLength, te);
251 adjust_fixed_count(ttyWind);
252 AdjustDisplay(ttyWind);
256 LOCAL int GetInputLine(void)
258 int i, has_fixed, count;
259 unsigned char **mytext;
260 TEHandle te = GetEWindowTE(ttyWind);
261 LVAL stream = get_input_stream();
263 mytext = (unsigned char **)TEGetText(te);
264 has_fixed = get_fixed_count(ttyWind, &count);
265 if (! has_fixed) count = 0;
266 if (ustreamp(stream) && check_parens(*mytext + count, (*te)->teLength - count)) {
267 for (i = count; i < (*te)->teLength; i++)
268 xlputc(stream, (*mytext)[i]);
269 if (has_fixed) adjust_fixed_count(ttyWind);
270 return(TRUE);
272 else return(FALSE);
275 LOCAL int check_parens(unsigned char *s, int n)
277 int parcount = 0, inquotes = FALSE, incomment = FALSE;
278 char ch;
280 while (n-- > 0) {
281 ch = *s++;
282 switch (ch) {
283 case '"': inquotes = ! inquotes; break;
284 case ';': if (! inquotes) incomment = TRUE; break;
285 case '\r':
286 case '\n': incomment = FALSE; break;
287 case '(': if (! inquotes && ! incomment) parcount++; break;
288 case ')': if (! inquotes && ! incomment) parcount--; break;
291 return (parcount <= 0);
294 LVAL xsedit_window_paste_stream(void)
296 LVAL stream;
297 WindowPtr w;
299 w = (WindowPtr) get_edit_window_address(xlgetarg());
300 stream = xlgetfile(FALSE);
301 xllastarg();
303 adjust_insert(w);
304 return((paste_stream(w, stream, TRUE)) ? s_true : NIL);
307 LVAL xsedit_window_paste_string(void)
309 LVAL string;
310 WindowPtr w;
312 w = (WindowPtr) get_edit_window_address(xlgetarg());
313 string = xlgastring();
314 xllastarg();
316 adjust_insert(w);
317 return((paste_string(w, getstring(string), TRUE)) ? s_true : NIL);
320 LVAL xsedit_window_flush_window(void)
322 WindowPtr w;
323 long count;
325 w = (WindowPtr) get_edit_window_address(xlgetarg());
326 count = (moreargs()) ? getfixnum(xlgafixnum()) : 32767;
327 xllastarg();
329 flush_window(w, count);
330 return(NIL);
333 static flash_matching_paren(TEHandle teEdit, int start)
335 int parcount = 0, inquotes = FALSE, sel, par;
336 unsigned char ch, *s;
338 sel = (*teEdit)->selStart;
339 s = *((unsigned char **)TEGetText(teEdit)) + sel - 1;
340 par = sel;
341 do {
342 par--;
343 ch = *s--;
344 switch (ch) {
345 case '"': inquotes = ! inquotes; break;
346 case '(': if (! inquotes) parcount--; break;
347 case ')': if (! inquotes) parcount++; break;
349 } while (par > start && parcount > 0);
350 if (ch == '(' && parcount == 0) {
351 TESetSelect(par, par + 1, teEdit);
352 pardelay();
353 TESetSelect(sel, sel, teEdit);
355 return (parcount <= 0);
358 LOCAL VOID pardelay(void)
360 unsigned long t = 5, f;
361 Delay(t, &f);
364 LOCAL VOID do_tab(TEHandle teEdit, int start)
366 int sel, curline, lastline, pos, nblanks, inquote, parcount;
367 unsigned char *s, ch;
369 /* for an edit window get rid of the inserted tab
370 if (teEdit != TTY.teEdit) TEKey('\b', teEdit);*/
372 sel = (*teEdit)->selStart;
373 s = *((unsigned char **)TEGetText(teEdit));
375 /* find beginning of the line */
376 curline = sel;
377 while (curline > start && s[curline - 1] != RETURNCHAR) curline--;
378 if (curline == start) return;
380 /* find unmatched paren */
381 parcount = 0;
382 inquote = FALSE;
383 pos = curline;
384 while (parcount >= 0 && --pos >= start) {
385 ch = s[pos];
386 switch (ch) {
387 case ')': if (! inquote) parcount++; break;
388 case '(': if (! inquote) parcount--; break;
389 case '"': inquote = ! inquote; break;
392 if (parcount == 0) return;
394 /* find beginning of the previous line */
395 lastline = pos;
396 while (lastline > 0 && s[lastline - 1] != RETURNCHAR) lastline--;
398 /* skip forward an s-expression or to first non blank */
399 pos += num_to_skip(s + pos, curline - pos);
401 if (pos > curline) pos = curline;
402 nblanks = pos - lastline;
404 /* adjust for the number of blanks already present, replace tabs by blanks */
405 for (pos = curline;
406 pos < (*teEdit)->teLength && (s[pos] == ' ' || s[pos] == '\t');
407 nblanks--, pos++)
408 if (s[pos] == '\t') s[pos] = ' ';
410 /* insert or delete the appropriate number of blanks */
411 if (nblanks == 0) return;
413 sel += nblanks;
414 if (pos > (*teEdit)->teLength) pos = (*teEdit)->teLength;
415 TESetSelect(pos, pos, teEdit);
416 fix_blanks(teEdit, nblanks, curline);
417 if (sel > (*teEdit)->teLength) sel = (*teEdit)->teLength;
418 TESetSelect(sel, sel, teEdit);
421 LOCAL VOID fix_blanks(TEHandle teEdit, int nblanks, int curline)
423 int i;
425 if (nblanks > 0) {
426 for (i = 0; i < nblanks; i++) buf[i] = ' ';
427 TESetSelect(curline, curline, teEdit);
428 TEInsert(buf, (long) nblanks, teEdit);
430 else {
431 TESetSelect(curline, curline - nblanks, teEdit);
432 TECut(teEdit);
436 LOCAL int at_text_end(TEHandle teEdit)
438 int i, result = TRUE;
439 unsigned char *s = *((unsigned char **)TEGetText(teEdit));
441 for (i = (*teEdit)->selStart; result && i < (*teEdit)->teLength; i++)
442 if (! isspace(s[i])) result = FALSE;
443 return(result);
446 LOCAL int last_is_return(TEHandle teEdit)
448 int i;
449 unsigned char *s = *((unsigned char **)TEGetText(teEdit));
451 for (i = (*teEdit)->selStart - 1; i >= 0 && isspace(s[i]); i--)
453 i = MIN((*teEdit)->selStart - 1, i + 1);
454 return(s[i] == RETURNCHAR);
457 VOID return_action(TEHandle te)
459 if (at_text_end(te) && last_is_return(te) && GetInputLine()) {
460 flush_output_stream(ttyWind);
461 getttyline(get_input_stream());
465 LOCAL int num_to_skip(unsigned char *s, int n)
467 unsigned char str[4];
468 int i, pos, oldpos;
470 pos = 0;
472 if (n <= 0) pos = 0;
473 else if (*s == '(') {
475 s++; n--; pos = 1;
477 /* skip blanks */
478 while (n > 0 && (*s == ' ' || *s == '\t')) { s++; n--; pos++; }
480 /* check for end of line or list or lisp comment*/
481 if (n > 0 && *s != RETURNCHAR && *s != ';' && *s != '(') {
483 /* check for special symbols */
484 for (i = 0; i < 3 && i < n; i++)
485 str[i] = toupper(s[i]);
486 str[i] = '\0';
487 if (is_special(s, n) /* strcmp(str, "DEF") == 0 || strcmp(str, "LET") == 0
488 || strcmp(str, "FLE") == 0 */ )
489 pos = 2;
490 else {
492 /* skip over the s-expression */
493 oldpos = pos;
494 while (n > 0 && *s != ' ' && *s != '\t' && *s != RETURNCHAR)
495 { s++; n--; pos++; }
497 /* check for another s expression */
498 for (i = 0; n > 0 && (*s == ' ' || *s == '\t'); s++, n--, i++) ;
499 if (n == 0 || *s == RETURNCHAR)
500 pos = (oldpos == pos) ? oldpos + 1 : oldpos;
501 else pos += i;
505 else {
507 /* skip over any blanks */
508 for (i = 0; n > 0 && (*s == ' ' || *s == '\t'); s++, n--, i++) ;
509 if (n > 0 && *s != RETURNCHAR) pos += i;
511 return(pos);
514 LOCAL int is_special(unsigned char *s, int n)
516 char str[10];
517 int i;
519 for (i = 0; i < n && i < 9; i++) str[i] = toupper(s[i]);
520 str[i] = '\0';
522 if (n >= 5 && strncmp(str, "DEFUN", 5) == 0) return(TRUE);
523 if (n >= 8 && strncmp(str, "DEFMACRO", 8) == 0) return(TRUE);
524 if (n >= 7 && strncmp(str, "DEFMETH", 7) == 0) return(TRUE);
525 if (n >= 8 && strncmp(str, "DEFPROTO", 8) == 0) return(TRUE);
526 if (n >= 3 && strncmp(str, "LET", 3) == 0) return(TRUE);
527 if (n >= 4 && strncmp(str, "FLET", 4) == 0) return(TRUE);
528 if (n >= 4 && strncmp(str, "COND", 4) == 0) return(TRUE);
529 if (n >= 4 && strncmp(str, "CASE", 4) == 0) return(TRUE);
530 if (n >= 6 && strncmp(str, "LABELS", 6) == 0) return(TRUE);
531 if (n >= 6 && strncmp(str, "LAMBDA", 6) == 0) return(TRUE);
532 return(FALSE);
535 LOCAL pascal VOID close_listener(void)
537 HideWindow(ttyWind);
540 Boolean edit_key_filter(WindowPtr editWind, int c)
542 TEHandle editTE;
543 int count, has_fixed;
545 editTE = GetEWindowTE(editWind);
546 if (editWind == nil) return(TRUE);
547 has_fixed = get_fixed_count(editWind, &count);
548 if (! has_fixed) count = 0;
550 if (! input_enabled(editWind)) return (TRUE);
551 switch (c) {
552 case '\034':
553 case '\035':
554 case '\036':
555 case '\037': return(FALSE); /* arrow keys */
556 case '\t': adjust_insert(editWind); do_tab(editTE, count); return(TRUE);
557 case '\b':
558 adjust_insert(editWind);
559 if ((*editTE)->selStart > count
560 || ((*editTE)->selStart == count
561 && (*editTE)->selStart < (*editTE)->selEnd)) {
562 return(FALSE);
564 else return(TRUE);
565 case enter: if (editWind == ttyWind && ttyWind != nil) tty_enter(); return(TRUE);
566 case RETURNCHAR:
567 if (editWind == ttyWind) {
568 tty_return();
569 return(TRUE);
571 else {
572 adjust_insert(editWind);
573 return(FALSE);
575 case ')':
576 adjust_insert(editWind);
577 TEKey(c, editTE);
578 flash_matching_paren(editTE, count);
579 return(TRUE);
580 default:
581 adjust_insert(editWind);
582 return(FALSE);
586 LOCAL pascal VOID tty_key(void)
588 SetEWindowDirty (ttyWind, FALSE);
591 LOCAL pascal VOID edit_idle (void)
593 GrafPtr port;
594 TEHandle editTE;
596 GetPort(&port);
597 flush_output_stream(port);
598 if (! input_enabled(port)) {
599 editTE = GetEWindowTE(port);
600 if (editTE != nil) TEDeactivate (editTE);
604 LOCAL pascal VOID close_edit(void)
606 GrafPtr w;
607 LVAL object;
609 GetPort(&w);
610 object = get_window_object(w);
611 if (objectp(object)) send_message(object, sk_remove);
614 VOID make_listener_window(Rect r)
616 ttyWind = NewEWindow (&r, "\pXLISP-STAT", TRUE, (WindowPtr) -1L, TRUE, 0L, FALSE);
617 SetEWindowProcs(ttyWind, tty_key, nil, close_listener, edit_idle);
618 SetEWindowStyle (ttyWind,
619 listenerFontNum, listenerFontSize, listenerFontStyle,
620 0, teJustLeft);
623 VOID set_edit_window_procs(WindowPtr w)
625 if (IsEWindow(w)) {
626 SetEWindowProcs(w, nil, nil, close_edit, edit_idle);
630 LVAL xsedit_window_update(void) { return(NIL); }
631 LVAL xsedit_window_activate(void) { return(NIL); }