1 /* Lisp Editor and Listener Window Class */
13 static HFONT hFixedFont
;
14 static HWND hTTYWnd
= NULL
;
15 static void (*MainLoop
)(void);
16 static WNDPROC fpOldEditProc
= NULL
, fpLEditProc
= NULL
;
18 /* input and output buffers */
20 static char obuf
[BUFSIZE
];
24 static char *obp
= obuf
;
25 static int instart
= 0, inend
= 0;
28 /* TTY Trimming defines */
29 #define MAXTTYBUF 25000
30 #define TRIMTTYTO 20000
32 LONG CALLBACK
LEditWndProc(HWND
, UINT
, WPARAM
, LONG
);
34 static void waitforline(void);
35 static BOOL
check_parens(char *, int);
36 static BOOL
at_text_end(char *, int);
37 static BOOL
has_return(char *, int);
38 static BOOL
input_complete(int);
39 static void check_trim_buffer(int);
41 static BOOL
flash_matching_paren(HWND
, int);
42 static void pardelay(void);
43 static void do_tab(HWND
, int);
44 static void fix_blanks(HWND
, int, int);
45 static int num_to_skip(char *, int);
46 static BOOL
is_special(char *, int);
47 static void edit_getsel(HWND
, UINT
*, UINT
*);
49 static char *LockText(void);
50 static void UnlockText(void);
52 /**************************************************************************/
53 /**************************************************************************/
55 /** Public Routines **/
57 /**************************************************************************/
58 /**************************************************************************/
60 void InitLEditClass(void (*f
)(), HFONT font
)
64 hFixedFont
= (font
) ? font
: GetStockObject(ANSI_FIXED_FONT
);
67 HWND
CreateLEditWindow(HWND hWndParent
, HMENU hMenu
, HANDLE hInstance
)
73 /* This generates a global handle tobe used in place of hInstance. */
74 /* This forces the edit control to use the global hewp with this */
75 /* handle for its text. It looks like this call works in Win32s */
76 /* too, but is should not be necessary there, so I have ifdefed it */
81 h
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, 1024L),
84 GetClientRect(hWndParent
, (LPRECT
) &Rect
);
85 hWnd
= CreateWindow("Edit",
87 WS_CHILD
| WS_VISIBLE
| WS_VSCROLL
|
88 ES_MULTILINE
| ES_AUTOVSCROLL
,
91 (Rect
.right
- Rect
.left
),
92 (Rect
.bottom
- Rect
.top
),
99 if (fpOldEditProc
== NULL
) {
100 fpOldEditProc
= XLSGetWindowProc(hWnd
);
101 fpLEditProc
= (WNDPROC
) MakeProcInstance((FARPROC
) LEditWndProc
,
104 (void) SubclassWindow(hWnd
, fpLEditProc
);
106 /* "First" window created is TTY */
107 if (hTTYWnd
== NULL
) hTTYWnd
= hWnd
;
108 SetWindowFont(hWnd
, hFixedFont
, FALSE
);
115 BOOL
TTYHasInput(void)
117 return(instart
< inend
? TRUE
: FALSE
);
120 void TTYPutStr(char *s
)
122 while (*s
!= '\0') TTYPutC((int) *s
++);
128 if (obp
>= obuf
+ BUFSIZE
- 3) TTYFlushOutput();
129 if (c
== '\n' || c
== '\r') {
138 void TTYResetInput(void)
140 instart
= Edit_GetTextLength(hTTYWnd
);
142 Edit_SetSel(hTTYWnd
, instart
, instart
);
145 void TTYFlushOutput(void)
147 int selstart
, selend
;
152 selstart
= Edit_GetTextLength(hTTYWnd
);
153 selend
= selstart
+ strlen(obuf
);
154 Edit_SetSel(hTTYWnd
, selstart
, selend
);
155 Edit_ReplaceSel(hTTYWnd
, obuf
);
157 check_trim_buffer(TRUE
);
172 /* wait for input if there is none */
173 if (! TTYHasInput()) waitforline();
177 if (! pText
) { SysBeep(10); return('\0'); }
179 /* skip linefeeds (or whatever they are) */
180 while (pText
[instart
] == '\r') instart
++;
183 c
= pText
[instart
++];
189 /* release the text buffer */
192 /* reset the enput at the end of the last line */
193 if (instart
>= inend
) TTYResetInput();
195 return((c
== '\r') ? '\n' : c
);
199 BOOL
TTYHasSelection(void)
203 edit_getsel(hTTYWnd
, &start
, &end
);
204 return(start
< end
? TRUE
: FALSE
);
207 void TTYSelToClip(void)
209 XLSEditCopy(hTTYWnd
);
212 void TTYClearSel(void)
217 edit_getsel(hTTYWnd
, &selstart
, NULL
);
219 if (selstart
< instart
)
223 XLSEditClear(hTTYWnd
);
226 void TTYPasteFromClip(void)
231 edit_getsel(hTTYWnd
, &selstart
, NULL
);
233 /* move the insertion point to the end if it is */
234 /* before the input text start */
235 if (selstart
< instart
) {
236 int text_end
= Edit_GetTextLength(hTTYWnd
);
237 Edit_SetSel(hTTYWnd
, text_end
, text_end
);
241 XLSEditPaste(hTTYWnd
);
244 /* check for a return and a complete expression */
245 if (input_complete(TRUE
)) {
246 inend
= Edit_GetTextLength(hTTYWnd
);
252 /**** This relies on being able to modify the buffer */
253 /**** and on the fact that an unlock does nothing */
254 char *TTYSelectionStr()
256 UINT selstart
, selend
;
259 edit_getsel(hTTYWnd
, &selstart
, &selend
);
262 p
[(int)(selend
- selstart
)] = '\0';
266 void TTYTrimBuffer(void)
268 check_trim_buffer(FALSE
);
272 /**************************************************************************/
273 /**************************************************************************/
275 /** Subclass Callback Function **/
277 /**************************************************************************/
278 /**************************************************************************/
280 /* window function for LEdit class -- filters returns */
281 LONG CALLBACK
LEditWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LONG lParam
)
283 if (message
== WM_CHAR
) {
285 UINT selstart
, selend
;
287 edit_getsel(hTTYWnd
, &selstart
, &selend
);
289 /* ignore backspaces at the start of the input region */
290 if (selstart
== instart
&& selstart
== selend
&& wParam
== '\b') {
295 /* move the insertion point to the end if it is before the */
296 /* input text start */
297 if (selstart
< instart
) {
298 int text_end
= Edit_GetTextLength(hTTYWnd
);
299 Edit_SetSel(hTTYWnd
, text_end
, text_end
);
303 /* adjust spacing on tab */
304 if (wParam
== '\t') {
305 do_tab(hTTYWnd
, instart
);
310 /* jump to end of input on shift-return */
311 if (wParam
== '\r' && HIBIT(GetKeyState(VK_SHIFT
))) {
312 selstart
= selend
= Edit_GetTextLength(hTTYWnd
);
313 Edit_SetSel(hTTYWnd
, selstart
, selend
);
318 /* insert the character using the inherited method */
319 CallWindowProc(fpOldEditProc
, hWnd
, message
, wParam
, lParam
);
321 /* flash matching parenthesis */
322 if (wParam
== ')') flash_matching_paren(hTTYWnd
, instart
);
325 /* check the character for a return */
326 if (wParam
== '\r' && input_complete(FALSE
)) {
327 inend
= Edit_GetTextLength(hTTYWnd
);
335 else return(CallWindowProc(fpOldEditProc
, hWnd
, message
, wParam
, lParam
));
338 /**************************************************************************/
339 /**************************************************************************/
341 /** Internal Routines **/
343 /**************************************************************************/
344 /**************************************************************************/
347 static void waitforline(void)
354 static BOOL
input_complete(int check_return
)
358 UINT text_end
, selstart
;
361 text_end
= Edit_GetTextLength(hTTYWnd
);
363 if (! pText
) { SysBeep(10); return(FALSE
); }
364 edit_getsel(hTTYWnd
, &selstart
, NULL
);
365 checkstart
= (selstart
> 0) ? selstart
- 1 : selstart
;
367 result
= check_parens(pText
+ instart
, text_end
- instart
)
368 && at_text_end(pText
+ selstart
, text_end
- selstart
)
370 || has_return(pText
+ checkstart
, text_end
- checkstart
));
376 static BOOL
at_text_end(char *s
, int n
)
378 int i
, result
= TRUE
;
380 for (i
= 0; result
&& i
< n
; i
++)
381 if (! isspace(s
[i
]) && s
[i
] != '\n' && s
[i
] != '\r')
386 static BOOL
has_return(char *s
, int n
)
388 int i
, result
= FALSE
;
390 for (i
= 0; ! result
&& i
< n
; i
++)
391 if (s
[i
] == '\n' || s
[i
] == '\r')
396 static BOOL
check_parens(s
, n
)
400 int parcount
= 0, inquotes
= FALSE
, incomment
= FALSE
;
406 case '"': inquotes
= ! inquotes
; break;
407 case ';': if (! inquotes
) incomment
= TRUE
; break;
409 case '\n': incomment
= FALSE
; break;
410 case '(': if (! inquotes
&& ! incomment
) parcount
++; break;
411 case ')': if (! inquotes
&& ! incomment
) parcount
--; break;
414 return (parcount
<= 0 ? TRUE
: FALSE
);
418 static BOOL
flash_matching_paren(HWND hWnd
, int start
)
420 BOOL inquotes
= FALSE
;
421 UINT parcount
= 0, sel
, par
;
424 edit_getsel(hWnd
, &sel
, NULL
);
427 if (! s
) { SysBeep(10); return(FALSE
); }
435 case '"': inquotes
= ! inquotes
; break;
436 case '(': if (! inquotes
) parcount
--; break;
437 case ')': if (! inquotes
) parcount
++; break;
439 } while (par
> start
&& parcount
> 0);
443 if (ch
== '(' && parcount
== 0) {
444 Edit_SetSel(hWnd
, par
, par
+ 1);
446 Edit_SetSel(hWnd
, sel
, sel
);
449 return (parcount
<= 0 ? TRUE
: FALSE
);
452 static void pardelay(void)
457 #define ISRETURNCHAR(c) ((c) == '\r' || (c) == '\n')
459 static void do_tab(HWND hWnd
, int start
)
462 UINT sel
, curline
, lastline
, nblanks
, length
;
466 edit_getsel(hWnd
, &sel
, NULL
);
469 if (! s
) { SysBeep(10); return; }
470 length
= Edit_GetTextLength(hWnd
);
472 /* find beginning of the line */
474 while (curline
> start
&& ! ISRETURNCHAR(s
[curline
- 1])) curline
--;
475 if (curline
== start
) return;
477 /* find unmatched paren */
481 while (parcount
>= 0 && --pos
>= start
) {
484 case ')': if (! inquote
) parcount
++; break;
485 case '(': if (! inquote
) parcount
--; break;
486 case '"': inquote
= ! inquote
; break;
489 if (parcount
== 0) return;
491 /* find beginning of the line containing the expression start */
493 while (lastline
> 0 && ! ISRETURNCHAR(s
[lastline
- 1])) lastline
--;
495 /* skip forward an s-expression or to first non blank */
496 pos
+= num_to_skip(s
+ pos
, curline
- pos
);
498 if (pos
> curline
) pos
= curline
;
499 nblanks
= pos
- lastline
;
501 /* adjust for the number of blanks already present, replace tabs by blanks */
503 pos
< length
&& (s
[pos
] == ' ' || s
[pos
] == '\t');
505 if (s
[pos
] == '\t') s
[pos
] = ' ';
509 /* insert or delete the appropriate number of blanks */
510 if (nblanks
== 0) return;
513 if (pos
> length
) pos
= length
;
514 Edit_SetSel(hWnd
, pos
, pos
);
515 fix_blanks(hWnd
, nblanks
, curline
);
516 length
= Edit_GetTextLength(hWnd
);
517 if (pos
> length
) pos
= length
;
518 Edit_SetSel(hWnd
, sel
, sel
);
521 static void fix_blanks(HWND hWnd
, int nblanks
, int curline
)
526 for (i
= 0; i
< nblanks
&& i
< BUFSIZE
-3; i
++) obuf
[i
] = ' ';
528 Edit_SetSel(hWnd
, curline
, curline
);
529 Edit_ReplaceSel(hWnd
, obuf
);
533 Edit_SetSel(hWnd
, curline
, curline
- nblanks
);
534 Edit_ReplaceSel(hWnd
, obuf
);
538 static int num_to_skip(char *s
, int n
)
546 else if (*s
== '(') {
551 while (n
> 0 && (*s
== ' ' || *s
== '\t')) { s
++; n
--; pos
++; }
553 /* check for end of line or list or lisp comment*/
554 if (n
> 0 && ! ISRETURNCHAR(*s
) && *s
!= ';' && *s
!= '(') {
556 /* check for special symbols */
557 for (i
= 0; i
< 3 && i
< n
; i
++)
558 str
[i
] = islower(s
[i
]) ? (char) toupper(s
[i
]) : s
[i
];
560 if (is_special(s
, n
) /* strcmp(str, "DEF") == 0 || strcmp(str, "LET") == 0
561 || strcmp(str, "FLE") == 0 */ )
565 /* skip over the s-expression */
567 while (n
> 0 && *s
!= ' ' && *s
!= '\t' && ! ISRETURNCHAR(*s
))
570 /* check for another s expression */
571 for (i
= 0; n
> 0 && (*s
== ' ' || *s
== '\t'); s
++, n
--, i
++) ;
572 if (n
== 0 || ISRETURNCHAR(*s
))
573 pos
= (oldpos
== pos
) ? oldpos
+ 1 : oldpos
;
580 /* skip over any blanks */
581 for (i
= 0; n
> 0 && (*s
== ' ' || *s
== '\t'); s
++, n
--, i
++) ;
582 if (n
> 0 && ! ISRETURNCHAR(*s
)) pos
+= i
;
587 static BOOL
is_special(char *s
, int n
)
592 for (i
= 0; i
< n
&& i
< 9; i
++)
593 str
[i
] = islower(s
[i
]) ? (char) toupper(s
[i
]) : s
[i
];
596 if (n
>= 5 && strncmp(str
, "DEFUN", 5) == 0) return(TRUE
);
597 if (n
>= 8 && strncmp(str
, "DEFMACRO", 8) == 0) return(TRUE
);
598 if (n
>= 7 && strncmp(str
, "DEFMETH", 7) == 0) return(TRUE
);
599 if (n
>= 8 && strncmp(str
, "DEFPROTO", 8) == 0) return(TRUE
);
600 if (n
>= 3 && strncmp(str
, "LET", 3) == 0) return(TRUE
);
601 if (n
>= 4 && strncmp(str
, "FLET", 4) == 0) return(TRUE
);
602 if (n
>= 4 && strncmp(str
, "COND", 4) == 0) return(TRUE
);
603 if (n
>= 4 && strncmp(str
, "CASE", 4) == 0) return(TRUE
);
604 if (n
>= 6 && strncmp(str
, "LABELS", 6) == 0) return(TRUE
);
605 if (n
>= 6 && strncmp(str
, "LAMBDA", 6) == 0) return(TRUE
);
610 static void check_trim_buffer(int maxonly
)
613 UINT selstart
, selend
;
615 length
= Edit_GetTextLength(hTTYWnd
);
617 if (length
> (maxonly
? MAXTTYBUF
: TRIMTTYTO
)) {
618 start
= length
- TRIMTTYTO
;
619 edit_getsel(hTTYWnd
, &selstart
, &selend
);
621 Edit_SetSel(hTTYWnd
, 0, start
);
622 Edit_ReplaceSel(hTTYWnd
, obuf
);
627 Edit_SetSel(hTTYWnd
, selstart
, selend
);
632 static void edit_getsel(HWND hWnd
, UINT
*pstart
, UINT
*pend
)
636 /**** this doesn't make sense for edit records larget than 64K */
637 sel
= Edit_GetSel(hWnd
);
638 if (pstart
!= NULL
) *pstart
= LOWORD(sel
);
639 if (pend
!= NULL
) *pend
= HIWORD(sel
);
642 #define TBUFSIZ 31000
643 static char *tbuf
= NULL
;
645 static char *LockText(void)
651 h
= GlobalAlloc(GMEM_MOVEABLE
, TBUFSIZ
+ 1);
652 tbuf
= h
? GlobalLock(h
) : 0;
653 if (tbuf
== NULL
) return NULL
;
656 length
= Edit_GetTextLength(hTTYWnd
);
657 GetWindowText(hTTYWnd
, tbuf
, TBUFSIZ
);
662 static void UnlockText(void) {}