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