Commit | Line | Data |
---|---|---|
2791ff57 | 1 | /*- |
eb035710 KB |
2 | * Copyright (c) 1980, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
2791ff57 KB |
4 | * |
5 | * %sccs.include.proprietary.c% | |
19d73a0e DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
eb035710 | 9 | static char sccsid[] = "@(#)ex_v.c 8.1 (Berkeley) %G%"; |
2791ff57 | 10 | #endif /* not lint */ |
19d73a0e | 11 | |
59ae3464 MH |
12 | #include "ex.h" |
13 | #include "ex_re.h" | |
14 | #include "ex_tty.h" | |
15 | #include "ex_vis.h" | |
16 | ||
17 | /* | |
18 | * Entry points to open and visual from command mode processor. | |
19 | * The open/visual code breaks down roughly as follows: | |
20 | * | |
21 | * ex_v.c entry points, checking of terminal characteristics | |
22 | * | |
23 | * ex_vadj.c logical screen control, use of intelligent operations | |
24 | * insert/delete line and coordination with screen image; | |
25 | * updating of screen after changes. | |
26 | * | |
27 | * ex_vget.c input of single keys and reading of input lines | |
28 | * from the echo area, handling of \ escapes on input for | |
29 | * uppercase only terminals, handling of memory for repeated | |
30 | * commands and small saved texts from inserts and partline | |
31 | * deletes, notification of multi line changes in the echo | |
32 | * area. | |
33 | * | |
34 | * ex_vmain.c main command decoding, some command processing. | |
35 | * | |
36 | * ex_voperate.c decoding of operator/operand sequences and | |
37 | * contextual scans, implementation of word motions. | |
38 | * | |
39 | * ex_vops.c major operator interfaces, undos, motions, deletes, | |
40 | * changes, opening new lines, shifts, replacements and yanks | |
41 | * coordinating logical and physical changes. | |
42 | * | |
43 | * ex_vops2.c subroutines for operator interfaces in ex_vops.c, | |
44 | * insert mode, read input line processing at lowest level. | |
45 | * | |
46 | * ex_vops3.c structured motion definitions of ( ) { } and [ ] operators, | |
47 | * indent for lisp routines, () and {} balancing. | |
48 | * | |
49 | * ex_vput.c output routines, clearing, physical mapping of logical cursor | |
50 | * positioning, cursor motions, handling of insert character | |
51 | * and delete character functions of intelligent and unintelligent | |
52 | * terminals, visual mode tracing routines (for debugging), | |
53 | * control of screen image and its updating. | |
54 | * | |
55 | * ex_vwind.c window level control of display, forward and backward rolls, | |
56 | * absolute motions, contextual displays, line depth determination | |
57 | */ | |
58 | ||
2de97448 | 59 | jmp_buf venv; |
b61c5edc | 60 | void winch(); |
2de97448 | 61 | |
59ae3464 MH |
62 | /* |
63 | * Enter open mode | |
64 | */ | |
3c7b865a MH |
65 | #ifdef u370 |
66 | char atube[TUBESIZE+LBSIZE]; | |
67 | #endif | |
59ae3464 MH |
68 | oop() |
69 | { | |
70 | register char *ic; | |
3c7b865a | 71 | #ifndef u370 |
59ae3464 | 72 | char atube[TUBESIZE + LBSIZE]; |
3c7b865a | 73 | #endif |
299f2784 | 74 | ttymode f; /* mjm: was register */ |
59ae3464 | 75 | |
5a6c967e | 76 | if (setjmp(venv)) { |
2de97448 JB |
77 | setsize(); |
78 | initev = (char *)0; | |
79 | inopen = 0; | |
80 | addr1 = addr2 = dot; | |
81 | } | |
5a6c967e | 82 | #ifdef SIGWINCH |
2de97448 | 83 | (void)signal(SIGWINCH, winch); |
5a6c967e | 84 | #endif |
59ae3464 MH |
85 | ovbeg(); |
86 | if (peekchar() == '/') { | |
5a6c967e | 87 | ignore(compile(ex_getchar(), 1)); |
59ae3464 MH |
88 | savere(scanre); |
89 | if (execute(0, dot) == 0) | |
90 | error("Fail|Pattern not found on addressed line"); | |
91 | ic = loc1; | |
92 | if (ic > linebuf && *ic == 0) | |
93 | ic--; | |
94 | } else { | |
95 | getDOT(); | |
96 | ic = vskipwh(linebuf); | |
97 | } | |
98 | newline(); | |
99 | ||
100 | /* | |
101 | * If overstrike then have to HARDOPEN | |
102 | * else if can move cursor up off current line can use CRTOPEN (~~vi1) | |
103 | * otherwise (ugh) have to use ONEOPEN (like adm3) | |
104 | */ | |
105 | if (OS && !EO) | |
106 | bastate = HARDOPEN; | |
107 | else if (CA || UP) | |
108 | bastate = CRTOPEN; | |
109 | else | |
110 | bastate = ONEOPEN; | |
111 | setwind(); | |
112 | ||
113 | /* | |
114 | * To avoid bombing on glass-crt's when the line is too long | |
115 | * pretend that such terminals are 160 columns wide. | |
116 | * If a line is too wide for display, we will dynamically | |
117 | * switch to hardcopy open mode. | |
118 | */ | |
119 | if (state != CRTOPEN) | |
120 | WCOLS = TUBECOLS; | |
121 | if (!inglobal) | |
122 | savevis(); | |
123 | vok(atube); | |
124 | if (state != CRTOPEN) | |
125 | COLUMNS = WCOLS; | |
126 | Outchar = vputchar; | |
127 | f = ostart(); | |
128 | if (state == CRTOPEN) { | |
129 | if (outcol == UKCOL) | |
130 | outcol = 0; | |
131 | vmoveitup(1, 1); | |
132 | } else | |
133 | outline = destline = WBOT; | |
134 | vshow(dot, NOLINE); | |
135 | vnline(ic); | |
136 | vmain(); | |
137 | if (state != CRTOPEN) | |
138 | vclean(); | |
139 | Command = "open"; | |
140 | ovend(f); | |
5a6c967e | 141 | #ifdef SIGWINCH |
2de97448 | 142 | (void)signal(SIGWINCH, SIG_DFL); |
5a6c967e | 143 | #endif |
59ae3464 MH |
144 | } |
145 | ||
146 | ovbeg() | |
147 | { | |
148 | ||
149 | if (!value(OPEN)) | |
150 | error("Can't use open/visual unless open option is set"); | |
151 | if (inopen) | |
152 | error("Recursive open/visual not allowed"); | |
153 | Vlines = lineDOL(); | |
154 | fixzero(); | |
155 | setdot(); | |
156 | pastwh(); | |
157 | dot = addr2; | |
158 | } | |
159 | ||
160 | ovend(f) | |
d266c416 | 161 | ttymode f; |
59ae3464 MH |
162 | { |
163 | ||
164 | splitw++; | |
165 | vgoto(WECHO, 0); | |
166 | vclreol(); | |
167 | vgoto(WECHO, 0); | |
168 | holdcm = 0; | |
169 | splitw = 0; | |
170 | ostop(f); | |
171 | setoutt(); | |
172 | undvis(); | |
173 | COLUMNS = OCOLUMNS; | |
174 | inopen = 0; | |
175 | flusho(); | |
176 | netchHAD(Vlines); | |
177 | } | |
178 | ||
179 | /* | |
180 | * Enter visual mode | |
181 | */ | |
182 | vop() | |
183 | { | |
184 | register int c; | |
3c7b865a | 185 | #ifndef u370 |
59ae3464 | 186 | char atube[TUBESIZE + LBSIZE]; |
3c7b865a | 187 | #endif |
299f2784 | 188 | ttymode f; /* mjm: was register */ |
59ae3464 MH |
189 | |
190 | if (!CA && UP == NOSTR) { | |
191 | if (initev) { | |
192 | toopen: | |
193 | merror("[Using open mode]"); | |
194 | putNFL(); | |
195 | oop(); | |
196 | return; | |
197 | } | |
198 | error("Visual needs addressible cursor or upline capability"); | |
199 | } | |
200 | if (OS && !EO) { | |
201 | if (initev) | |
202 | goto toopen; | |
203 | error("Can't use visual on a terminal which overstrikes"); | |
204 | } | |
205 | if (!CL) { | |
206 | if (initev) | |
207 | goto toopen; | |
208 | error("Visual requires clear screen capability"); | |
209 | } | |
d266c416 MH |
210 | if (NS && !SF) { |
211 | if (initev) | |
212 | goto toopen; | |
213 | error("Visual requires scrolling"); | |
214 | } | |
5a6c967e | 215 | if (setjmp(venv)) { |
2de97448 JB |
216 | setsize(); |
217 | initev = (char *)0; | |
218 | inopen = 0; | |
219 | addr1 = addr2 = dot; | |
220 | } | |
5a6c967e | 221 | #ifdef SIGWINCH |
2de97448 | 222 | (void)signal(SIGWINCH, winch); |
5a6c967e | 223 | #endif |
59ae3464 MH |
224 | ovbeg(); |
225 | bastate = VISUAL; | |
226 | c = 0; | |
227 | if (any(peekchar(), "+-^.")) | |
5a6c967e | 228 | c = ex_getchar(); |
59ae3464 MH |
229 | pastwh(); |
230 | vsetsiz(isdigit(peekchar()) ? getnum() : value(WINDOW)); | |
231 | setwind(); | |
232 | newline(); | |
233 | vok(atube); | |
234 | if (!inglobal) | |
235 | savevis(); | |
236 | Outchar = vputchar; | |
237 | vmoving = 0; | |
238 | f = ostart(); | |
239 | if (initev == 0) { | |
240 | vcontext(dot, c); | |
241 | vnline(NOSTR); | |
242 | } | |
243 | vmain(); | |
244 | Command = "visual"; | |
245 | ovend(f); | |
5a6c967e | 246 | #ifdef SIGWINCH |
2de97448 | 247 | (void)signal(SIGWINCH, SIG_DFL); |
5a6c967e | 248 | #endif |
59ae3464 MH |
249 | } |
250 | ||
251 | /* | |
252 | * Hack to allow entry to visual with | |
253 | * empty buffer since routines internally | |
254 | * demand at least one line. | |
255 | */ | |
256 | fixzero() | |
257 | { | |
258 | ||
259 | if (dol == zero) { | |
260 | register bool ochng = chng; | |
261 | ||
262 | vdoappend(""); | |
263 | if (!ochng) | |
5a6c967e | 264 | ex_sync(); |
59ae3464 MH |
265 | addr1 = addr2 = one; |
266 | } else if (addr2 == zero) | |
267 | addr2 = one; | |
268 | } | |
269 | ||
270 | /* | |
271 | * Save lines before visual between unddol and truedol. | |
272 | * Accomplish this by throwing away current [unddol,truedol] | |
273 | * and then saving all the lines in the buffer and moving | |
274 | * unddol back to dol. Don't do this if in a global. | |
275 | * | |
276 | * If you do | |
277 | * g/xxx/vi. | |
278 | * and then do a | |
279 | * :e xxxx | |
280 | * at some point, and then quit from the visual and undo | |
281 | * you get the old file back. Somewhat weird. | |
282 | */ | |
283 | savevis() | |
284 | { | |
285 | ||
286 | if (inglobal) | |
287 | return; | |
288 | truedol = unddol; | |
289 | saveall(); | |
290 | unddol = dol; | |
291 | undkind = UNDNONE; | |
292 | } | |
293 | ||
294 | /* | |
295 | * Restore a sensible state after a visual/open, moving the saved | |
296 | * stuff back to [unddol,dol], and killing the partial line kill indicators. | |
297 | */ | |
298 | undvis() | |
299 | { | |
300 | ||
301 | if (ruptible) | |
302 | signal(SIGINT, onintr); | |
303 | squish(); | |
304 | pkill[0] = pkill[1] = 0; | |
305 | unddol = truedol; | |
306 | unddel = zero; | |
307 | undap1 = one; | |
308 | undap2 = dol + 1; | |
309 | undkind = UNDALL; | |
d266c416 MH |
310 | if (undadot <= zero || undadot > dol) |
311 | undadot = zero+1; | |
59ae3464 MH |
312 | } |
313 | ||
314 | /* | |
315 | * Set the window parameters based on the base state bastate | |
316 | * and the available buffer space. | |
317 | */ | |
318 | setwind() | |
319 | { | |
320 | ||
321 | WCOLS = COLUMNS; | |
322 | switch (bastate) { | |
323 | ||
324 | case ONEOPEN: | |
325 | if (AM) | |
326 | WCOLS--; | |
327 | /* fall into ... */ | |
328 | ||
329 | case HARDOPEN: | |
330 | basWTOP = WTOP = WBOT = WECHO = 0; | |
5a6c967e | 331 | ex_ZERO = 0; |
59ae3464 MH |
332 | holdcm++; |
333 | break; | |
334 | ||
335 | case CRTOPEN: | |
336 | basWTOP = LINES - 2; | |
337 | /* fall into */ | |
338 | ||
339 | case VISUAL: | |
5a6c967e CH |
340 | ex_ZERO = LINES - TUBESIZE / WCOLS; |
341 | if (ex_ZERO < 0) | |
342 | ex_ZERO = 0; | |
343 | if (ex_ZERO > basWTOP) | |
59ae3464 MH |
344 | error("Screen too large for internal buffer"); |
345 | WTOP = basWTOP; WBOT = LINES - 2; WECHO = LINES - 1; | |
346 | break; | |
347 | } | |
348 | state = bastate; | |
349 | basWLINES = WLINES = WBOT - WTOP + 1; | |
350 | } | |
351 | ||
352 | /* | |
353 | * Can we hack an open/visual on this terminal? | |
354 | * If so, then divide the screen buffer up into lines, | |
355 | * and initialize a bunch of state variables before we start. | |
356 | */ | |
357 | vok(atube) | |
358 | register char *atube; | |
359 | { | |
360 | register int i; | |
361 | ||
362 | if (WCOLS == 1000) | |
363 | serror("Don't know enough about your terminal to use %s", Command); | |
364 | if (WCOLS > TUBECOLS) | |
365 | error("Terminal too wide"); | |
5a6c967e | 366 | if (WLINES >= TUBELINES || WCOLS * (WECHO - ex_ZERO + 1) > TUBESIZE) |
59ae3464 MH |
367 | error("Screen too large"); |
368 | ||
369 | vtube0 = atube; | |
5a6c967e CH |
370 | vclrbyte(atube, WCOLS * (WECHO - ex_ZERO + 1)); |
371 | for (i = 0; i < ex_ZERO; i++) | |
887e3e0d | 372 | vtube[i] = (char *) 0; |
59ae3464 MH |
373 | for (; i <= WECHO; i++) |
374 | vtube[i] = atube, atube += WCOLS; | |
375 | for (; i < TUBELINES; i++) | |
887e3e0d | 376 | vtube[i] = (char *) 0; |
59ae3464 MH |
377 | vutmp = atube; |
378 | vundkind = VNONE; | |
379 | vUNDdot = 0; | |
380 | OCOLUMNS = COLUMNS; | |
381 | inopen = 1; | |
382 | #ifdef CBREAK | |
383 | signal(SIGINT, vintr); | |
384 | #endif | |
385 | vmoving = 0; | |
386 | splitw = 0; | |
387 | doomed = 0; | |
388 | holdupd = 0; | |
5a6c967e | 389 | Peek_key = 0; |
59ae3464 | 390 | vcnt = vcline = 0; |
5a6c967e CH |
391 | if (ex_vSCROLL == 0) |
392 | ex_vSCROLL = (value(WINDOW)+1)/2; /* round up so dft=6,11 */ | |
59ae3464 MH |
393 | } |
394 | ||
395 | #ifdef CBREAK | |
b61c5edc | 396 | void |
59ae3464 MH |
397 | vintr() |
398 | { | |
b3c5103a | 399 | extern jmp_buf readbuf; |
47bdd628 | 400 | extern int doingread; |
59ae3464 MH |
401 | |
402 | signal(SIGINT, vintr); | |
403 | if (vcatch) | |
404 | onintr(); | |
405 | ungetkey(ATTN); | |
406 | draino(); | |
47bdd628 SL |
407 | if (doingread) { |
408 | doingread = 0; | |
409 | longjmp(readbuf, 1); | |
410 | } | |
59ae3464 MH |
411 | } |
412 | #endif | |
413 | ||
414 | /* | |
415 | * Set the size of the screen to size lines, to take effect the | |
416 | * next time the screen is redrawn. | |
417 | */ | |
418 | vsetsiz(size) | |
419 | int size; | |
420 | { | |
421 | register int b; | |
422 | ||
423 | if (bastate != VISUAL) | |
424 | return; | |
425 | b = LINES - 1 - size; | |
426 | if (b >= LINES - 1) | |
427 | b = LINES - 2; | |
428 | if (b < 0) | |
429 | b = 0; | |
430 | basWTOP = b; | |
431 | basWLINES = WBOT - b + 1; | |
432 | } | |
2de97448 | 433 | |
5a6c967e | 434 | #ifdef SIGWINCH |
b61c5edc | 435 | void |
2de97448 JB |
436 | winch() |
437 | { | |
438 | vsave(); | |
5a6c967e | 439 | ignore(setty(normf)); |
2de97448 JB |
440 | longjmp(venv, 1); |
441 | } | |
5a6c967e | 442 | #endif |