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