1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)ex_v.c 8.1 (Berkeley) 06/09/93";
10 #endif /* not lint */
11
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
59 jmp_buf venv;
60 void winch();
61
62 /*
63 * Enter open mode
64 */
65 #ifdef u370
66 char atube[TUBESIZE+LBSIZE];
67 #endif
oop()68 oop()
69 {
70 register char *ic;
71 #ifndef u370
72 char atube[TUBESIZE + LBSIZE];
73 #endif
74 ttymode f; /* mjm: was register */
75
76 if (setjmp(venv)) {
77 setsize();
78 initev = (char *)0;
79 inopen = 0;
80 addr1 = addr2 = dot;
81 }
82 #ifdef SIGWINCH
83 (void)signal(SIGWINCH, winch);
84 #endif
85 ovbeg();
86 if (peekchar() == '/') {
87 ignore(compile(ex_getchar(), 1));
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);
141 #ifdef SIGWINCH
142 (void)signal(SIGWINCH, SIG_DFL);
143 #endif
144 }
145
ovbeg()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
ovend(f)160 ovend(f)
161 ttymode f;
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 */
vop()182 vop()
183 {
184 register int c;
185 #ifndef u370
186 char atube[TUBESIZE + LBSIZE];
187 #endif
188 ttymode f; /* mjm: was register */
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 }
210 if (NS && !SF) {
211 if (initev)
212 goto toopen;
213 error("Visual requires scrolling");
214 }
215 if (setjmp(venv)) {
216 setsize();
217 initev = (char *)0;
218 inopen = 0;
219 addr1 = addr2 = dot;
220 }
221 #ifdef SIGWINCH
222 (void)signal(SIGWINCH, winch);
223 #endif
224 ovbeg();
225 bastate = VISUAL;
226 c = 0;
227 if (any(peekchar(), "+-^."))
228 c = ex_getchar();
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);
246 #ifdef SIGWINCH
247 (void)signal(SIGWINCH, SIG_DFL);
248 #endif
249 }
250
251 /*
252 * Hack to allow entry to visual with
253 * empty buffer since routines internally
254 * demand at least one line.
255 */
fixzero()256 fixzero()
257 {
258
259 if (dol == zero) {
260 register bool ochng = chng;
261
262 vdoappend("");
263 if (!ochng)
264 ex_sync();
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 */
savevis()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 */
undvis()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;
310 if (undadot <= zero || undadot > dol)
311 undadot = zero+1;
312 }
313
314 /*
315 * Set the window parameters based on the base state bastate
316 * and the available buffer space.
317 */
setwind()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;
331 ex_ZERO = 0;
332 holdcm++;
333 break;
334
335 case CRTOPEN:
336 basWTOP = LINES - 2;
337 /* fall into */
338
339 case VISUAL:
340 ex_ZERO = LINES - TUBESIZE / WCOLS;
341 if (ex_ZERO < 0)
342 ex_ZERO = 0;
343 if (ex_ZERO > basWTOP)
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 */
vok(atube)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");
366 if (WLINES >= TUBELINES || WCOLS * (WECHO - ex_ZERO + 1) > TUBESIZE)
367 error("Screen too large");
368
369 vtube0 = atube;
370 vclrbyte(atube, WCOLS * (WECHO - ex_ZERO + 1));
371 for (i = 0; i < ex_ZERO; i++)
372 vtube[i] = (char *) 0;
373 for (; i <= WECHO; i++)
374 vtube[i] = atube, atube += WCOLS;
375 for (; i < TUBELINES; i++)
376 vtube[i] = (char *) 0;
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;
389 Peek_key = 0;
390 vcnt = vcline = 0;
391 if (ex_vSCROLL == 0)
392 ex_vSCROLL = (value(WINDOW)+1)/2; /* round up so dft=6,11 */
393 }
394
395 #ifdef CBREAK
396 void
vintr()397 vintr()
398 {
399 extern jmp_buf readbuf;
400 extern int doingread;
401
402 signal(SIGINT, vintr);
403 if (vcatch)
404 onintr();
405 ungetkey(ATTN);
406 draino();
407 if (doingread) {
408 doingread = 0;
409 longjmp(readbuf, 1);
410 }
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 */
vsetsiz(size)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 }
433
434 #ifdef SIGWINCH
435 void
winch()436 winch()
437 {
438 vsave();
439 ignore(setty(normf));
440 longjmp(venv, 1);
441 }
442 #endif
443