refresh.c revision 1.33 1 1.33 christos /* $NetBSD: refresh.c,v 1.33 2009/12/28 21:52:43 christos Exp $ */
2 1.2 lukem
3 1.1 cgd /*-
4 1.1 cgd * Copyright (c) 1992, 1993
5 1.1 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software contributed to Berkeley by
8 1.1 cgd * Christos Zoulas of Cornell University.
9 1.1 cgd *
10 1.1 cgd * Redistribution and use in source and binary forms, with or without
11 1.1 cgd * modification, are permitted provided that the following conditions
12 1.1 cgd * are met:
13 1.1 cgd * 1. Redistributions of source code must retain the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer.
15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cgd * notice, this list of conditions and the following disclaimer in the
17 1.1 cgd * documentation and/or other materials provided with the distribution.
18 1.26 agc * 3. Neither the name of the University nor the names of its contributors
19 1.1 cgd * may be used to endorse or promote products derived from this software
20 1.1 cgd * without specific prior written permission.
21 1.1 cgd *
22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.1 cgd * SUCH DAMAGE.
33 1.1 cgd */
34 1.1 cgd
35 1.18 christos #include "config.h"
36 1.1 cgd #if !defined(lint) && !defined(SCCSID)
37 1.2 lukem #if 0
38 1.1 cgd static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93";
39 1.2 lukem #else
40 1.33 christos __RCSID("$NetBSD: refresh.c,v 1.33 2009/12/28 21:52:43 christos Exp $");
41 1.2 lukem #endif
42 1.1 cgd #endif /* not lint && not SCCSID */
43 1.1 cgd
44 1.1 cgd /*
45 1.1 cgd * refresh.c: Lower level screen refreshing functions
46 1.1 cgd */
47 1.1 cgd #include <stdio.h>
48 1.1 cgd #include <ctype.h>
49 1.1 cgd #include <unistd.h>
50 1.1 cgd #include <string.h>
51 1.1 cgd
52 1.1 cgd #include "el.h"
53 1.1 cgd
54 1.31 christos private void re_nextline(EditLine *);
55 1.15 lukem private void re_addc(EditLine *, int);
56 1.15 lukem private void re_update_line(EditLine *, char *, char *, int);
57 1.15 lukem private void re_insert (EditLine *, char *, int, int, char *, int);
58 1.15 lukem private void re_delete(EditLine *, char *, int, int, int);
59 1.15 lukem private void re_fastputc(EditLine *, int);
60 1.27 christos private void re_clear_eol(EditLine *, int, int, int);
61 1.15 lukem private void re__strncopy(char *, char *, size_t);
62 1.18 christos private void re__copy_and_pad(char *, const char *, size_t);
63 1.1 cgd
64 1.1 cgd #ifdef DEBUG_REFRESH
65 1.20 christos private void re_printstr(EditLine *, const char *, char *, char *);
66 1.15 lukem #define __F el->el_errfile
67 1.17 lukem #define ELRE_ASSERT(a, b, c) do \
68 1.20 christos if (/*CONSTCOND*/ a) { \
69 1.1 cgd (void) fprintf b; \
70 1.1 cgd c; \
71 1.1 cgd } \
72 1.20 christos while (/*CONSTCOND*/0)
73 1.17 lukem #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
74 1.15 lukem
75 1.1 cgd /* re_printstr():
76 1.1 cgd * Print a string on the debugging pty
77 1.1 cgd */
78 1.1 cgd private void
79 1.20 christos re_printstr(EditLine *el, const char *str, char *f, char *t)
80 1.1 cgd {
81 1.15 lukem
82 1.17 lukem ELRE_DEBUG(1, (__F, "%s:\"", str));
83 1.15 lukem while (f < t)
84 1.17 lukem ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
85 1.17 lukem ELRE_DEBUG(1, (__F, "\"\r\n"));
86 1.8 simonb }
87 1.1 cgd #else
88 1.17 lukem #define ELRE_ASSERT(a, b, c)
89 1.17 lukem #define ELRE_DEBUG(a, b)
90 1.1 cgd #endif
91 1.1 cgd
92 1.31 christos /* re_nextline():
93 1.31 christos * Move to the next line or scroll
94 1.31 christos */
95 1.31 christos private void
96 1.31 christos re_nextline(EditLine *el)
97 1.31 christos {
98 1.31 christos el->el_refresh.r_cursor.h = 0; /* reset it. */
99 1.31 christos
100 1.31 christos /*
101 1.31 christos * If we would overflow (input is longer than terminal size),
102 1.31 christos * emulate scroll by dropping first line and shuffling the rest.
103 1.31 christos * We do this via pointer shuffling - it's safe in this case
104 1.31 christos * and we avoid memcpy().
105 1.31 christos */
106 1.31 christos if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) {
107 1.31 christos int i, lins = el->el_term.t_size.v;
108 1.31 christos char *firstline = el->el_vdisplay[0];
109 1.31 christos
110 1.31 christos for(i = 1; i < lins; i++)
111 1.31 christos el->el_vdisplay[i - 1] = el->el_vdisplay[i];
112 1.31 christos
113 1.31 christos firstline[0] = '\0'; /* empty the string */
114 1.31 christos el->el_vdisplay[i - 1] = firstline;
115 1.31 christos } else
116 1.31 christos el->el_refresh.r_cursor.v++;
117 1.31 christos
118 1.31 christos ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
119 1.31 christos (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
120 1.31 christos el->el_refresh.r_cursor.v, el->el_term.t_size.v),
121 1.31 christos abort());
122 1.31 christos }
123 1.1 cgd
124 1.1 cgd /* re_addc():
125 1.1 cgd * Draw c, expanding tabs, control chars etc.
126 1.1 cgd */
127 1.1 cgd private void
128 1.15 lukem re_addc(EditLine *el, int c)
129 1.1 cgd {
130 1.15 lukem
131 1.15 lukem if (isprint(c)) {
132 1.16 jdolecek re_putc(el, c, 1);
133 1.15 lukem return;
134 1.15 lukem }
135 1.15 lukem if (c == '\n') { /* expand the newline */
136 1.15 lukem int oldv = el->el_refresh.r_cursor.v;
137 1.16 jdolecek re_putc(el, '\0', 0); /* assure end of line */
138 1.31 christos if (oldv == el->el_refresh.r_cursor.v) /* XXX */
139 1.31 christos re_nextline(el);
140 1.15 lukem return;
141 1.15 lukem }
142 1.15 lukem if (c == '\t') { /* expand the tab */
143 1.15 lukem for (;;) {
144 1.16 jdolecek re_putc(el, ' ', 1);
145 1.15 lukem if ((el->el_refresh.r_cursor.h & 07) == 0)
146 1.15 lukem break; /* go until tab stop */
147 1.15 lukem }
148 1.15 lukem } else if (iscntrl(c)) {
149 1.16 jdolecek re_putc(el, '^', 1);
150 1.15 lukem if (c == '\177')
151 1.16 jdolecek re_putc(el, '?', 1);
152 1.15 lukem else
153 1.15 lukem /* uncontrolify it; works only for iso8859-1 like sets */
154 1.16 jdolecek re_putc(el, (c | 0100), 1);
155 1.15 lukem } else {
156 1.16 jdolecek re_putc(el, '\\', 1);
157 1.16 jdolecek re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1);
158 1.16 jdolecek re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1);
159 1.16 jdolecek re_putc(el, (c & 07) + '0', 1);
160 1.15 lukem }
161 1.15 lukem }
162 1.1 cgd
163 1.1 cgd
164 1.1 cgd /* re_putc():
165 1.1 cgd * Draw the character given
166 1.1 cgd */
167 1.1 cgd protected void
168 1.16 jdolecek re_putc(EditLine *el, int c, int shift)
169 1.1 cgd {
170 1.1 cgd
171 1.17 lukem ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
172 1.15 lukem
173 1.15 lukem el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
174 1.16 jdolecek if (!shift)
175 1.16 jdolecek return;
176 1.16 jdolecek
177 1.15 lukem el->el_refresh.r_cursor.h++; /* advance to next place */
178 1.15 lukem if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
179 1.15 lukem /* assure end of line */
180 1.31 christos el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h]
181 1.31 christos = '\0';
182 1.31 christos re_nextline(el);
183 1.31 christos }
184 1.16 jdolecek
185 1.15 lukem }
186 1.15 lukem
187 1.1 cgd
188 1.1 cgd /* re_refresh():
189 1.1 cgd * draws the new virtual screen image from the current input
190 1.1 cgd * line, then goes line-by-line changing the real image to the new
191 1.1 cgd * virtual image. The routine to re-draw a line can be replaced
192 1.1 cgd * easily in hopes of a smarter one being placed there.
193 1.1 cgd */
194 1.1 cgd protected void
195 1.15 lukem re_refresh(EditLine *el)
196 1.1 cgd {
197 1.15 lukem int i, rhdiff;
198 1.16 jdolecek char *cp, *st;
199 1.15 lukem coord_t cur;
200 1.16 jdolecek #ifdef notyet
201 1.16 jdolecek size_t termsz;
202 1.16 jdolecek #endif
203 1.15 lukem
204 1.15 lukem ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
205 1.17 lukem el->el_line.buffer));
206 1.15 lukem
207 1.15 lukem /* reset the Drawing cursor */
208 1.15 lukem el->el_refresh.r_cursor.h = 0;
209 1.15 lukem el->el_refresh.r_cursor.v = 0;
210 1.15 lukem
211 1.15 lukem /* temporarily draw rprompt to calculate its size */
212 1.15 lukem prompt_print(el, EL_RPROMPT);
213 1.15 lukem
214 1.15 lukem /* reset the Drawing cursor */
215 1.15 lukem el->el_refresh.r_cursor.h = 0;
216 1.15 lukem el->el_refresh.r_cursor.v = 0;
217 1.15 lukem
218 1.22 christos if (el->el_line.cursor >= el->el_line.lastchar) {
219 1.22 christos if (el->el_map.current == el->el_map.alt
220 1.22 christos && el->el_line.lastchar != el->el_line.buffer)
221 1.22 christos el->el_line.cursor = el->el_line.lastchar - 1;
222 1.22 christos else
223 1.22 christos el->el_line.cursor = el->el_line.lastchar;
224 1.22 christos }
225 1.22 christos
226 1.15 lukem cur.h = -1; /* set flag in case I'm not set */
227 1.15 lukem cur.v = 0;
228 1.15 lukem
229 1.15 lukem prompt_print(el, EL_PROMPT);
230 1.15 lukem
231 1.15 lukem /* draw the current input buffer */
232 1.16 jdolecek #if notyet
233 1.16 jdolecek termsz = el->el_term.t_size.h * el->el_term.t_size.v;
234 1.16 jdolecek if (el->el_line.lastchar - el->el_line.buffer > termsz) {
235 1.16 jdolecek /*
236 1.16 jdolecek * If line is longer than terminal, process only part
237 1.16 jdolecek * of line which would influence display.
238 1.16 jdolecek */
239 1.16 jdolecek size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
240 1.16 jdolecek
241 1.16 jdolecek st = el->el_line.lastchar - rem
242 1.16 jdolecek - (termsz - (((rem / el->el_term.t_size.v) - 1)
243 1.16 jdolecek * el->el_term.t_size.v));
244 1.16 jdolecek } else
245 1.16 jdolecek #endif
246 1.16 jdolecek st = el->el_line.buffer;
247 1.16 jdolecek
248 1.16 jdolecek for (cp = st; cp < el->el_line.lastchar; cp++) {
249 1.15 lukem if (cp == el->el_line.cursor) {
250 1.16 jdolecek /* save for later */
251 1.15 lukem cur.h = el->el_refresh.r_cursor.h;
252 1.15 lukem cur.v = el->el_refresh.r_cursor.v;
253 1.15 lukem }
254 1.15 lukem re_addc(el, (unsigned char) *cp);
255 1.15 lukem }
256 1.15 lukem
257 1.15 lukem if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
258 1.15 lukem cur.h = el->el_refresh.r_cursor.h;
259 1.15 lukem cur.v = el->el_refresh.r_cursor.v;
260 1.15 lukem }
261 1.15 lukem rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h -
262 1.15 lukem el->el_rprompt.p_pos.h;
263 1.15 lukem if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
264 1.15 lukem !el->el_refresh.r_cursor.v && rhdiff > 1) {
265 1.15 lukem /*
266 1.15 lukem * have a right-hand side prompt that will fit
267 1.15 lukem * on the end of the first line with at least
268 1.15 lukem * one character gap to the input buffer.
269 1.15 lukem */
270 1.15 lukem while (--rhdiff > 0) /* pad out with spaces */
271 1.16 jdolecek re_putc(el, ' ', 1);
272 1.15 lukem prompt_print(el, EL_RPROMPT);
273 1.15 lukem } else {
274 1.15 lukem el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
275 1.15 lukem el->el_rprompt.p_pos.v = 0;
276 1.15 lukem }
277 1.15 lukem
278 1.16 jdolecek re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
279 1.16 jdolecek
280 1.15 lukem el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
281 1.15 lukem
282 1.15 lukem ELRE_DEBUG(1, (__F,
283 1.15 lukem "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
284 1.15 lukem el->el_term.t_size.h, el->el_refresh.r_cursor.h,
285 1.17 lukem el->el_refresh.r_cursor.v, el->el_vdisplay[0]));
286 1.15 lukem
287 1.17 lukem ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
288 1.15 lukem for (i = 0; i <= el->el_refresh.r_newcv; i++) {
289 1.15 lukem /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
290 1.15 lukem re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
291 1.15 lukem
292 1.15 lukem /*
293 1.15 lukem * Copy the new line to be the current one, and pad out with
294 1.15 lukem * spaces to the full width of the terminal so that if we try
295 1.15 lukem * moving the cursor by writing the character that is at the
296 1.15 lukem * end of the screen line, it won't be a NUL or some old
297 1.15 lukem * leftover stuff.
298 1.15 lukem */
299 1.15 lukem re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
300 1.15 lukem (size_t) el->el_term.t_size.h);
301 1.15 lukem }
302 1.15 lukem ELRE_DEBUG(1, (__F,
303 1.15 lukem "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
304 1.17 lukem el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
305 1.15 lukem
306 1.15 lukem if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
307 1.15 lukem for (; i <= el->el_refresh.r_oldcv; i++) {
308 1.15 lukem term_move_to_line(el, i);
309 1.15 lukem term_move_to_char(el, 0);
310 1.15 lukem term_clear_EOL(el, (int) strlen(el->el_display[i]));
311 1.1 cgd #ifdef DEBUG_REFRESH
312 1.30 christos term_overwrite(el, "C\b", (size_t)2);
313 1.1 cgd #endif /* DEBUG_REFRESH */
314 1.16 jdolecek el->el_display[i][0] = '\0';
315 1.15 lukem }
316 1.8 simonb
317 1.15 lukem el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
318 1.15 lukem ELRE_DEBUG(1, (__F,
319 1.15 lukem "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
320 1.15 lukem el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
321 1.17 lukem cur.h, cur.v));
322 1.15 lukem term_move_to_line(el, cur.v); /* go to where the cursor is */
323 1.15 lukem term_move_to_char(el, cur.h);
324 1.15 lukem }
325 1.1 cgd
326 1.1 cgd
327 1.1 cgd /* re_goto_bottom():
328 1.8 simonb * used to go to last used screen line
329 1.1 cgd */
330 1.1 cgd protected void
331 1.15 lukem re_goto_bottom(EditLine *el)
332 1.1 cgd {
333 1.15 lukem
334 1.15 lukem term_move_to_line(el, el->el_refresh.r_oldcv);
335 1.28 christos term__putc(el, '\n');
336 1.15 lukem re_clear_display(el);
337 1.28 christos term__flush(el);
338 1.15 lukem }
339 1.1 cgd
340 1.1 cgd
341 1.1 cgd /* re_insert():
342 1.1 cgd * insert num characters of s into d (in front of the character)
343 1.8 simonb * at dat, maximum length of d is dlen
344 1.1 cgd */
345 1.1 cgd private void
346 1.1 cgd /*ARGSUSED*/
347 1.25 christos re_insert(EditLine *el __attribute__((__unused__)),
348 1.25 christos char *d, int dat, int dlen, char *s, int num)
349 1.1 cgd {
350 1.15 lukem char *a, *b;
351 1.1 cgd
352 1.15 lukem if (num <= 0)
353 1.15 lukem return;
354 1.15 lukem if (num > dlen - dat)
355 1.15 lukem num = dlen - dat;
356 1.1 cgd
357 1.15 lukem ELRE_DEBUG(1,
358 1.15 lukem (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
359 1.17 lukem num, dat, dlen, d));
360 1.27 christos ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
361 1.1 cgd
362 1.15 lukem /* open up the space for num chars */
363 1.15 lukem if (num > 0) {
364 1.15 lukem b = d + dlen - 1;
365 1.15 lukem a = b - num;
366 1.15 lukem while (a >= &d[dat])
367 1.15 lukem *b-- = *a--;
368 1.15 lukem d[dlen] = '\0'; /* just in case */
369 1.15 lukem }
370 1.15 lukem ELRE_DEBUG(1, (__F,
371 1.1 cgd "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
372 1.17 lukem num, dat, dlen, d));
373 1.27 christos ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
374 1.1 cgd
375 1.15 lukem /* copy the characters */
376 1.15 lukem for (a = d + dat; (a < d + dlen) && (num > 0); num--)
377 1.15 lukem *a++ = *s++;
378 1.15 lukem
379 1.15 lukem ELRE_DEBUG(1,
380 1.15 lukem (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
381 1.17 lukem num, dat, dlen, d, s));
382 1.27 christos ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
383 1.15 lukem }
384 1.1 cgd
385 1.1 cgd
386 1.1 cgd /* re_delete():
387 1.8 simonb * delete num characters d at dat, maximum length of d is dlen
388 1.1 cgd */
389 1.1 cgd private void
390 1.1 cgd /*ARGSUSED*/
391 1.25 christos re_delete(EditLine *el __attribute__((__unused__)),
392 1.25 christos char *d, int dat, int dlen, int num)
393 1.1 cgd {
394 1.15 lukem char *a, *b;
395 1.1 cgd
396 1.15 lukem if (num <= 0)
397 1.15 lukem return;
398 1.15 lukem if (dat + num >= dlen) {
399 1.15 lukem d[dat] = '\0';
400 1.15 lukem return;
401 1.15 lukem }
402 1.15 lukem ELRE_DEBUG(1,
403 1.15 lukem (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
404 1.17 lukem num, dat, dlen, d));
405 1.1 cgd
406 1.15 lukem /* open up the space for num chars */
407 1.15 lukem if (num > 0) {
408 1.15 lukem b = d + dat;
409 1.15 lukem a = b + num;
410 1.15 lukem while (a < &d[dlen])
411 1.15 lukem *b++ = *a++;
412 1.15 lukem d[dlen] = '\0'; /* just in case */
413 1.15 lukem }
414 1.15 lukem ELRE_DEBUG(1,
415 1.15 lukem (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
416 1.17 lukem num, dat, dlen, d));
417 1.15 lukem }
418 1.1 cgd
419 1.1 cgd
420 1.1 cgd /* re__strncopy():
421 1.1 cgd * Like strncpy without padding.
422 1.1 cgd */
423 1.1 cgd private void
424 1.15 lukem re__strncopy(char *a, char *b, size_t n)
425 1.1 cgd {
426 1.15 lukem
427 1.15 lukem while (n-- && *b)
428 1.15 lukem *a++ = *b++;
429 1.15 lukem }
430 1.1 cgd
431 1.27 christos /* re_clear_eol():
432 1.27 christos * Find the number of characters we need to clear till the end of line
433 1.27 christos * in order to make sure that we have cleared the previous contents of
434 1.27 christos * the line. fx and sx is the number of characters inserted or deleted
435 1.27 christos * int the first or second diff, diff is the difference between the
436 1.27 christos * number of characters between the new and old line.
437 1.27 christos */
438 1.27 christos private void
439 1.27 christos re_clear_eol(EditLine *el, int fx, int sx, int diff)
440 1.27 christos {
441 1.27 christos
442 1.27 christos ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
443 1.27 christos sx, fx, diff));
444 1.27 christos
445 1.27 christos if (fx < 0)
446 1.27 christos fx = -fx;
447 1.27 christos if (sx < 0)
448 1.27 christos sx = -sx;
449 1.27 christos if (fx > diff)
450 1.27 christos diff = fx;
451 1.27 christos if (sx > diff)
452 1.27 christos diff = sx;
453 1.27 christos
454 1.27 christos ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
455 1.27 christos term_clear_EOL(el, diff);
456 1.27 christos }
457 1.1 cgd
458 1.15 lukem /*****************************************************************
459 1.1 cgd re_update_line() is based on finding the middle difference of each line
460 1.1 cgd on the screen; vis:
461 1.1 cgd
462 1.1 cgd /old first difference
463 1.1 cgd /beginning of line | /old last same /old EOL
464 1.1 cgd v v v v
465 1.1 cgd old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
466 1.1 cgd new: eddie> Oh, my little buggy says to me, as lurgid as
467 1.1 cgd ^ ^ ^ ^
468 1.1 cgd \beginning of line | \new last same \new end of line
469 1.1 cgd \new first difference
470 1.1 cgd
471 1.1 cgd all are character pointers for the sake of speed. Special cases for
472 1.1 cgd no differences, as well as for end of line additions must be handled.
473 1.1 cgd **************************************************************** */
474 1.1 cgd
475 1.1 cgd /* Minimum at which doing an insert it "worth it". This should be about
476 1.1 cgd * half the "cost" of going into insert mode, inserting a character, and
477 1.1 cgd * going back out. This should really be calculated from the termcap
478 1.1 cgd * data... For the moment, a good number for ANSI terminals.
479 1.1 cgd */
480 1.15 lukem #define MIN_END_KEEP 4
481 1.1 cgd
482 1.1 cgd private void
483 1.15 lukem re_update_line(EditLine *el, char *old, char *new, int i)
484 1.1 cgd {
485 1.15 lukem char *o, *n, *p, c;
486 1.15 lukem char *ofd, *ols, *oe, *nfd, *nls, *ne;
487 1.15 lukem char *osb, *ose, *nsb, *nse;
488 1.15 lukem int fx, sx;
489 1.30 christos size_t len;
490 1.15 lukem
491 1.15 lukem /*
492 1.15 lukem * find first diff
493 1.15 lukem */
494 1.15 lukem for (o = old, n = new; *o && (*o == *n); o++, n++)
495 1.15 lukem continue;
496 1.15 lukem ofd = o;
497 1.15 lukem nfd = n;
498 1.15 lukem
499 1.15 lukem /*
500 1.15 lukem * Find the end of both old and new
501 1.15 lukem */
502 1.15 lukem while (*o)
503 1.15 lukem o++;
504 1.15 lukem /*
505 1.15 lukem * Remove any trailing blanks off of the end, being careful not to
506 1.15 lukem * back up past the beginning.
507 1.15 lukem */
508 1.15 lukem while (ofd < o) {
509 1.15 lukem if (o[-1] != ' ')
510 1.15 lukem break;
511 1.15 lukem o--;
512 1.15 lukem }
513 1.15 lukem oe = o;
514 1.15 lukem *oe = '\0';
515 1.15 lukem
516 1.15 lukem while (*n)
517 1.15 lukem n++;
518 1.15 lukem
519 1.15 lukem /* remove blanks from end of new */
520 1.15 lukem while (nfd < n) {
521 1.15 lukem if (n[-1] != ' ')
522 1.15 lukem break;
523 1.15 lukem n--;
524 1.15 lukem }
525 1.15 lukem ne = n;
526 1.15 lukem *ne = '\0';
527 1.15 lukem
528 1.15 lukem /*
529 1.15 lukem * if no diff, continue to next line of redraw
530 1.15 lukem */
531 1.15 lukem if (*ofd == '\0' && *nfd == '\0') {
532 1.17 lukem ELRE_DEBUG(1, (__F, "no difference.\r\n"));
533 1.15 lukem return;
534 1.15 lukem }
535 1.15 lukem /*
536 1.15 lukem * find last same pointer
537 1.15 lukem */
538 1.15 lukem while ((o > ofd) && (n > nfd) && (*--o == *--n))
539 1.15 lukem continue;
540 1.15 lukem ols = ++o;
541 1.15 lukem nls = ++n;
542 1.15 lukem
543 1.15 lukem /*
544 1.15 lukem * find same begining and same end
545 1.15 lukem */
546 1.1 cgd osb = ols;
547 1.15 lukem nsb = nls;
548 1.1 cgd ose = ols;
549 1.1 cgd nse = nls;
550 1.1 cgd
551 1.15 lukem /*
552 1.15 lukem * case 1: insert: scan from nfd to nls looking for *ofd
553 1.15 lukem */
554 1.15 lukem if (*ofd) {
555 1.15 lukem for (c = *ofd, n = nfd; n < nls; n++) {
556 1.15 lukem if (c == *n) {
557 1.15 lukem for (o = ofd, p = n;
558 1.15 lukem p < nls && o < ols && *o == *p;
559 1.15 lukem o++, p++)
560 1.15 lukem continue;
561 1.15 lukem /*
562 1.15 lukem * if the new match is longer and it's worth
563 1.15 lukem * keeping, then we take it
564 1.15 lukem */
565 1.15 lukem if (((nse - nsb) < (p - n)) &&
566 1.15 lukem (2 * (p - n) > n - nfd)) {
567 1.15 lukem nsb = n;
568 1.15 lukem nse = p;
569 1.15 lukem osb = ofd;
570 1.15 lukem ose = o;
571 1.15 lukem }
572 1.15 lukem }
573 1.15 lukem }
574 1.15 lukem }
575 1.15 lukem /*
576 1.15 lukem * case 2: delete: scan from ofd to ols looking for *nfd
577 1.15 lukem */
578 1.15 lukem if (*nfd) {
579 1.15 lukem for (c = *nfd, o = ofd; o < ols; o++) {
580 1.15 lukem if (c == *o) {
581 1.15 lukem for (n = nfd, p = o;
582 1.15 lukem p < ols && n < nls && *p == *n;
583 1.15 lukem p++, n++)
584 1.15 lukem continue;
585 1.15 lukem /*
586 1.15 lukem * if the new match is longer and it's worth
587 1.15 lukem * keeping, then we take it
588 1.15 lukem */
589 1.15 lukem if (((ose - osb) < (p - o)) &&
590 1.15 lukem (2 * (p - o) > o - ofd)) {
591 1.15 lukem nsb = nfd;
592 1.15 lukem nse = n;
593 1.15 lukem osb = o;
594 1.15 lukem ose = p;
595 1.15 lukem }
596 1.15 lukem }
597 1.15 lukem }
598 1.15 lukem }
599 1.15 lukem /*
600 1.15 lukem * Pragmatics I: If old trailing whitespace or not enough characters to
601 1.15 lukem * save to be worth it, then don't save the last same info.
602 1.15 lukem */
603 1.15 lukem if ((oe - ols) < MIN_END_KEEP) {
604 1.15 lukem ols = oe;
605 1.15 lukem nls = ne;
606 1.15 lukem }
607 1.15 lukem /*
608 1.15 lukem * Pragmatics II: if the terminal isn't smart enough, make the data
609 1.15 lukem * dumber so the smart update doesn't try anything fancy
610 1.15 lukem */
611 1.15 lukem
612 1.15 lukem /*
613 1.15 lukem * fx is the number of characters we need to insert/delete: in the
614 1.15 lukem * beginning to bring the two same begins together
615 1.15 lukem */
616 1.29 christos fx = (int)((nsb - nfd) - (osb - ofd));
617 1.15 lukem /*
618 1.15 lukem * sx is the number of characters we need to insert/delete: in the
619 1.15 lukem * end to bring the two same last parts together
620 1.15 lukem */
621 1.29 christos sx = (int)((nls - nse) - (ols - ose));
622 1.15 lukem
623 1.15 lukem if (!EL_CAN_INSERT) {
624 1.15 lukem if (fx > 0) {
625 1.15 lukem osb = ols;
626 1.15 lukem ose = ols;
627 1.15 lukem nsb = nls;
628 1.15 lukem nse = nls;
629 1.15 lukem }
630 1.15 lukem if (sx > 0) {
631 1.15 lukem ols = oe;
632 1.15 lukem nls = ne;
633 1.15 lukem }
634 1.15 lukem if ((ols - ofd) < (nls - nfd)) {
635 1.15 lukem ols = oe;
636 1.15 lukem nls = ne;
637 1.15 lukem }
638 1.15 lukem }
639 1.15 lukem if (!EL_CAN_DELETE) {
640 1.15 lukem if (fx < 0) {
641 1.15 lukem osb = ols;
642 1.15 lukem ose = ols;
643 1.15 lukem nsb = nls;
644 1.15 lukem nse = nls;
645 1.15 lukem }
646 1.15 lukem if (sx < 0) {
647 1.15 lukem ols = oe;
648 1.15 lukem nls = ne;
649 1.15 lukem }
650 1.15 lukem if ((ols - ofd) > (nls - nfd)) {
651 1.15 lukem ols = oe;
652 1.15 lukem nls = ne;
653 1.15 lukem }
654 1.15 lukem }
655 1.15 lukem /*
656 1.15 lukem * Pragmatics III: make sure the middle shifted pointers are correct if
657 1.15 lukem * they don't point to anything (we may have moved ols or nls).
658 1.15 lukem */
659 1.15 lukem /* if the change isn't worth it, don't bother */
660 1.15 lukem /* was: if (osb == ose) */
661 1.15 lukem if ((ose - osb) < MIN_END_KEEP) {
662 1.15 lukem osb = ols;
663 1.15 lukem ose = ols;
664 1.15 lukem nsb = nls;
665 1.15 lukem nse = nls;
666 1.15 lukem }
667 1.15 lukem /*
668 1.15 lukem * Now that we are done with pragmatics we recompute fx, sx
669 1.15 lukem */
670 1.29 christos fx = (int)((nsb - nfd) - (osb - ofd));
671 1.29 christos sx = (int)((nls - nse) - (ols - ose));
672 1.15 lukem
673 1.27 christos ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
674 1.15 lukem ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
675 1.17 lukem ofd - old, osb - old, ose - old, ols - old, oe - old));
676 1.15 lukem ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
677 1.17 lukem nfd - new, nsb - new, nse - new, nls - new, ne - new));
678 1.15 lukem ELRE_DEBUG(1, (__F,
679 1.17 lukem "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
680 1.15 lukem ELRE_DEBUG(1, (__F,
681 1.17 lukem "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
682 1.1 cgd #ifdef DEBUG_REFRESH
683 1.15 lukem re_printstr(el, "old- oe", old, oe);
684 1.15 lukem re_printstr(el, "new- ne", new, ne);
685 1.15 lukem re_printstr(el, "old-ofd", old, ofd);
686 1.15 lukem re_printstr(el, "new-nfd", new, nfd);
687 1.15 lukem re_printstr(el, "ofd-osb", ofd, osb);
688 1.15 lukem re_printstr(el, "nfd-nsb", nfd, nsb);
689 1.15 lukem re_printstr(el, "osb-ose", osb, ose);
690 1.15 lukem re_printstr(el, "nsb-nse", nsb, nse);
691 1.15 lukem re_printstr(el, "ose-ols", ose, ols);
692 1.15 lukem re_printstr(el, "nse-nls", nse, nls);
693 1.15 lukem re_printstr(el, "ols- oe", ols, oe);
694 1.15 lukem re_printstr(el, "nls- ne", nls, ne);
695 1.1 cgd #endif /* DEBUG_REFRESH */
696 1.1 cgd
697 1.15 lukem /*
698 1.15 lukem * el_cursor.v to this line i MUST be in this routine so that if we
699 1.15 lukem * don't have to change the line, we don't move to it. el_cursor.h to
700 1.15 lukem * first diff char
701 1.15 lukem */
702 1.15 lukem term_move_to_line(el, i);
703 1.15 lukem
704 1.15 lukem /*
705 1.15 lukem * at this point we have something like this:
706 1.15 lukem *
707 1.15 lukem * /old /ofd /osb /ose /ols /oe
708 1.15 lukem * v.....................v v..................v v........v
709 1.15 lukem * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
710 1.15 lukem * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
711 1.15 lukem * ^.....................^ ^..................^ ^........^
712 1.15 lukem * \new \nfd \nsb \nse \nls \ne
713 1.15 lukem *
714 1.15 lukem * fx is the difference in length between the chars between nfd and
715 1.15 lukem * nsb, and the chars between ofd and osb, and is thus the number of
716 1.15 lukem * characters to delete if < 0 (new is shorter than old, as above),
717 1.15 lukem * or insert (new is longer than short).
718 1.15 lukem *
719 1.15 lukem * sx is the same for the second differences.
720 1.15 lukem */
721 1.15 lukem
722 1.15 lukem /*
723 1.15 lukem * if we have a net insert on the first difference, AND inserting the
724 1.15 lukem * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
725 1.15 lukem * character (which is ne if nls != ne, otherwise is nse) off the edge
726 1.15 lukem * of the screen (el->el_term.t_size.h) else we do the deletes first
727 1.15 lukem * so that we keep everything we need to.
728 1.15 lukem */
729 1.15 lukem
730 1.15 lukem /*
731 1.15 lukem * if the last same is the same like the end, there is no last same
732 1.15 lukem * part, otherwise we want to keep the last same part set p to the
733 1.15 lukem * last useful old character
734 1.15 lukem */
735 1.15 lukem p = (ols != oe) ? oe : ose;
736 1.15 lukem
737 1.15 lukem /*
738 1.15 lukem * if (There is a diffence in the beginning) && (we need to insert
739 1.15 lukem * characters) && (the number of characters to insert is less than
740 1.15 lukem * the term width)
741 1.15 lukem * We need to do an insert!
742 1.15 lukem * else if (we need to delete characters)
743 1.15 lukem * We need to delete characters!
744 1.15 lukem * else
745 1.15 lukem * No insert or delete
746 1.15 lukem */
747 1.15 lukem if ((nsb != nfd) && fx > 0 &&
748 1.15 lukem ((p - old) + fx <= el->el_term.t_size.h)) {
749 1.15 lukem ELRE_DEBUG(1,
750 1.17 lukem (__F, "first diff insert at %d...\r\n", nfd - new));
751 1.1 cgd /*
752 1.15 lukem * Move to the first char to insert, where the first diff is.
753 1.15 lukem */
754 1.29 christos term_move_to_char(el, (int)(nfd - new));
755 1.15 lukem /*
756 1.15 lukem * Check if we have stuff to keep at end
757 1.15 lukem */
758 1.15 lukem if (nsb != ne) {
759 1.17 lukem ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
760 1.15 lukem /*
761 1.15 lukem * insert fx chars of new starting at nfd
762 1.15 lukem */
763 1.15 lukem if (fx > 0) {
764 1.15 lukem ELRE_DEBUG(!EL_CAN_INSERT, (__F,
765 1.17 lukem "ERROR: cannot insert in early first diff\n"));
766 1.15 lukem term_insertwrite(el, nfd, fx);
767 1.29 christos re_insert(el, old, (int)(ofd - old),
768 1.15 lukem el->el_term.t_size.h, nfd, fx);
769 1.15 lukem }
770 1.15 lukem /*
771 1.15 lukem * write (nsb-nfd) - fx chars of new starting at
772 1.15 lukem * (nfd + fx)
773 1.15 lukem */
774 1.30 christos len = (size_t) ((nsb - nfd) - fx);
775 1.30 christos term_overwrite(el, (nfd + fx), len);
776 1.30 christos re__strncopy(ofd + fx, nfd + fx, len);
777 1.15 lukem } else {
778 1.17 lukem ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
779 1.30 christos len = (size_t)(nsb - nfd);
780 1.30 christos term_overwrite(el, nfd, len);
781 1.30 christos re__strncopy(ofd, nfd, len);
782 1.15 lukem /*
783 1.15 lukem * Done
784 1.15 lukem */
785 1.15 lukem return;
786 1.15 lukem }
787 1.15 lukem } else if (fx < 0) {
788 1.15 lukem ELRE_DEBUG(1,
789 1.17 lukem (__F, "first diff delete at %d...\r\n", ofd - old));
790 1.15 lukem /*
791 1.15 lukem * move to the first char to delete where the first diff is
792 1.15 lukem */
793 1.29 christos term_move_to_char(el, (int)(ofd - old));
794 1.15 lukem /*
795 1.15 lukem * Check if we have stuff to save
796 1.15 lukem */
797 1.15 lukem if (osb != oe) {
798 1.17 lukem ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
799 1.15 lukem /*
800 1.15 lukem * fx is less than zero *always* here but we check
801 1.15 lukem * for code symmetry
802 1.15 lukem */
803 1.15 lukem if (fx < 0) {
804 1.15 lukem ELRE_DEBUG(!EL_CAN_DELETE, (__F,
805 1.17 lukem "ERROR: cannot delete in first diff\n"));
806 1.15 lukem term_deletechars(el, -fx);
807 1.29 christos re_delete(el, old, (int)(ofd - old),
808 1.15 lukem el->el_term.t_size.h, -fx);
809 1.15 lukem }
810 1.15 lukem /*
811 1.15 lukem * write (nsb-nfd) chars of new starting at nfd
812 1.15 lukem */
813 1.30 christos len = (size_t) (nsb - nfd);
814 1.30 christos term_overwrite(el, nfd, len);
815 1.30 christos re__strncopy(ofd, nfd, len);
816 1.15 lukem
817 1.15 lukem } else {
818 1.15 lukem ELRE_DEBUG(1, (__F,
819 1.17 lukem "but with nothing left to save\r\n"));
820 1.15 lukem /*
821 1.15 lukem * write (nsb-nfd) chars of new starting at nfd
822 1.15 lukem */
823 1.30 christos term_overwrite(el, nfd, (size_t)(nsb - nfd));
824 1.29 christos re_clear_eol(el, fx, sx,
825 1.29 christos (int)((oe - old) - (ne - new)));
826 1.15 lukem /*
827 1.15 lukem * Done
828 1.15 lukem */
829 1.15 lukem return;
830 1.15 lukem }
831 1.15 lukem } else
832 1.15 lukem fx = 0;
833 1.15 lukem
834 1.15 lukem if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) {
835 1.15 lukem ELRE_DEBUG(1, (__F,
836 1.17 lukem "second diff delete at %d...\r\n", (ose - old) + fx));
837 1.15 lukem /*
838 1.15 lukem * Check if we have stuff to delete
839 1.15 lukem */
840 1.15 lukem /*
841 1.15 lukem * fx is the number of characters inserted (+) or deleted (-)
842 1.1 cgd */
843 1.15 lukem
844 1.29 christos term_move_to_char(el, (int)((ose - old) + fx));
845 1.15 lukem /*
846 1.15 lukem * Check if we have stuff to save
847 1.15 lukem */
848 1.15 lukem if (ols != oe) {
849 1.17 lukem ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
850 1.15 lukem /*
851 1.15 lukem * Again a duplicate test.
852 1.15 lukem */
853 1.15 lukem if (sx < 0) {
854 1.15 lukem ELRE_DEBUG(!EL_CAN_DELETE, (__F,
855 1.17 lukem "ERROR: cannot delete in second diff\n"));
856 1.15 lukem term_deletechars(el, -sx);
857 1.15 lukem }
858 1.15 lukem /*
859 1.15 lukem * write (nls-nse) chars of new starting at nse
860 1.15 lukem */
861 1.30 christos term_overwrite(el, nse, (size_t)(nls - nse));
862 1.15 lukem } else {
863 1.15 lukem ELRE_DEBUG(1, (__F,
864 1.17 lukem "but with nothing left to save\r\n"));
865 1.30 christos term_overwrite(el, nse, (size_t)(nls - nse));
866 1.29 christos re_clear_eol(el, fx, sx,
867 1.29 christos (int)((oe - old) - (ne - new)));
868 1.15 lukem }
869 1.15 lukem }
870 1.15 lukem /*
871 1.15 lukem * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
872 1.15 lukem */
873 1.15 lukem if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
874 1.15 lukem ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
875 1.17 lukem nfd - new));
876 1.15 lukem
877 1.29 christos term_move_to_char(el, (int)(nfd - new));
878 1.15 lukem /*
879 1.15 lukem * Check if we have stuff to keep at the end
880 1.15 lukem */
881 1.15 lukem if (nsb != ne) {
882 1.17 lukem ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
883 1.15 lukem /*
884 1.15 lukem * We have to recalculate fx here because we set it
885 1.15 lukem * to zero above as a flag saying that we hadn't done
886 1.15 lukem * an early first insert.
887 1.15 lukem */
888 1.29 christos fx = (int)((nsb - nfd) - (osb - ofd));
889 1.15 lukem if (fx > 0) {
890 1.15 lukem /*
891 1.15 lukem * insert fx chars of new starting at nfd
892 1.15 lukem */
893 1.15 lukem ELRE_DEBUG(!EL_CAN_INSERT, (__F,
894 1.17 lukem "ERROR: cannot insert in late first diff\n"));
895 1.15 lukem term_insertwrite(el, nfd, fx);
896 1.29 christos re_insert(el, old, (int)(ofd - old),
897 1.15 lukem el->el_term.t_size.h, nfd, fx);
898 1.15 lukem }
899 1.15 lukem /*
900 1.15 lukem * write (nsb-nfd) - fx chars of new starting at
901 1.15 lukem * (nfd + fx)
902 1.15 lukem */
903 1.30 christos len = (size_t) ((nsb - nfd) - fx);
904 1.30 christos term_overwrite(el, (nfd + fx), len);
905 1.30 christos re__strncopy(ofd + fx, nfd + fx, len);
906 1.15 lukem } else {
907 1.17 lukem ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
908 1.30 christos len = (size_t) (nsb - nfd);
909 1.30 christos term_overwrite(el, nfd, len);
910 1.30 christos re__strncopy(ofd, nfd, len);
911 1.15 lukem }
912 1.15 lukem }
913 1.15 lukem /*
914 1.15 lukem * line is now NEW up to nse
915 1.15 lukem */
916 1.15 lukem if (sx >= 0) {
917 1.15 lukem ELRE_DEBUG(1, (__F,
918 1.29 christos "second diff insert at %d...\r\n", (int)(nse - new)));
919 1.29 christos term_move_to_char(el, (int)(nse - new));
920 1.15 lukem if (ols != oe) {
921 1.17 lukem ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
922 1.15 lukem if (sx > 0) {
923 1.15 lukem /* insert sx chars of new starting at nse */
924 1.15 lukem ELRE_DEBUG(!EL_CAN_INSERT, (__F,
925 1.17 lukem "ERROR: cannot insert in second diff\n"));
926 1.15 lukem term_insertwrite(el, nse, sx);
927 1.15 lukem }
928 1.15 lukem /*
929 1.15 lukem * write (nls-nse) - sx chars of new starting at
930 1.15 lukem * (nse + sx)
931 1.15 lukem */
932 1.29 christos term_overwrite(el, (nse + sx),
933 1.30 christos (size_t)((nls - nse) - sx));
934 1.15 lukem } else {
935 1.17 lukem ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
936 1.30 christos term_overwrite(el, nse, (size_t)(nls - nse));
937 1.15 lukem
938 1.15 lukem /*
939 1.15 lukem * No need to do a clear-to-end here because we were
940 1.15 lukem * doing a second insert, so we will have over
941 1.15 lukem * written all of the old string.
942 1.15 lukem */
943 1.15 lukem }
944 1.15 lukem }
945 1.17 lukem ELRE_DEBUG(1, (__F, "done.\r\n"));
946 1.15 lukem }
947 1.1 cgd
948 1.1 cgd
949 1.1 cgd /* re__copy_and_pad():
950 1.1 cgd * Copy string and pad with spaces
951 1.1 cgd */
952 1.1 cgd private void
953 1.18 christos re__copy_and_pad(char *dst, const char *src, size_t width)
954 1.1 cgd {
955 1.21 thorpej size_t i;
956 1.1 cgd
957 1.15 lukem for (i = 0; i < width; i++) {
958 1.15 lukem if (*src == '\0')
959 1.15 lukem break;
960 1.15 lukem *dst++ = *src++;
961 1.15 lukem }
962 1.15 lukem
963 1.16 jdolecek for (; i < width; i++)
964 1.15 lukem *dst++ = ' ';
965 1.16 jdolecek
966 1.15 lukem *dst = '\0';
967 1.15 lukem }
968 1.1 cgd
969 1.1 cgd
970 1.1 cgd /* re_refresh_cursor():
971 1.1 cgd * Move to the new cursor position
972 1.1 cgd */
973 1.1 cgd protected void
974 1.15 lukem re_refresh_cursor(EditLine *el)
975 1.1 cgd {
976 1.15 lukem char *cp, c;
977 1.15 lukem int h, v, th;
978 1.15 lukem
979 1.22 christos if (el->el_line.cursor >= el->el_line.lastchar) {
980 1.22 christos if (el->el_map.current == el->el_map.alt
981 1.22 christos && el->el_line.lastchar != el->el_line.buffer)
982 1.22 christos el->el_line.cursor = el->el_line.lastchar - 1;
983 1.22 christos else
984 1.22 christos el->el_line.cursor = el->el_line.lastchar;
985 1.22 christos }
986 1.22 christos
987 1.15 lukem /* first we must find where the cursor is... */
988 1.15 lukem h = el->el_prompt.p_pos.h;
989 1.15 lukem v = el->el_prompt.p_pos.v;
990 1.15 lukem th = el->el_term.t_size.h; /* optimize for speed */
991 1.15 lukem
992 1.15 lukem /* do input buffer to el->el_line.cursor */
993 1.15 lukem for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
994 1.15 lukem c = *cp;
995 1.15 lukem
996 1.32 christos switch (c) {
997 1.32 christos case '\n': /* handle newline in data part too */
998 1.15 lukem h = 0;
999 1.15 lukem v++;
1000 1.32 christos break;
1001 1.32 christos case '\t': /* if a tab, to next tab stop */
1002 1.32 christos while (++h & 07)
1003 1.32 christos continue;
1004 1.32 christos break;
1005 1.32 christos default:
1006 1.32 christos if (iscntrl((unsigned char) c))
1007 1.32 christos h += 2; /* ^x */
1008 1.32 christos else if (!isprint((unsigned char) c))
1009 1.32 christos h += 4; /* octal \xxx */
1010 1.32 christos else
1011 1.15 lukem h++;
1012 1.32 christos break;
1013 1.15 lukem }
1014 1.1 cgd
1015 1.15 lukem if (h >= th) { /* check, extra long tabs picked up here also */
1016 1.32 christos h -= th;
1017 1.15 lukem v++;
1018 1.15 lukem }
1019 1.15 lukem }
1020 1.15 lukem
1021 1.15 lukem /* now go there */
1022 1.15 lukem term_move_to_line(el, v);
1023 1.15 lukem term_move_to_char(el, h);
1024 1.28 christos term__flush(el);
1025 1.15 lukem }
1026 1.1 cgd
1027 1.1 cgd
1028 1.1 cgd /* re_fastputc():
1029 1.1 cgd * Add a character fast.
1030 1.1 cgd */
1031 1.1 cgd private void
1032 1.15 lukem re_fastputc(EditLine *el, int c)
1033 1.1 cgd {
1034 1.15 lukem
1035 1.28 christos term__putc(el, c);
1036 1.15 lukem el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
1037 1.15 lukem if (el->el_cursor.h >= el->el_term.t_size.h) {
1038 1.15 lukem /* if we must overflow */
1039 1.15 lukem el->el_cursor.h = 0;
1040 1.16 jdolecek
1041 1.16 jdolecek /*
1042 1.16 jdolecek * If we would overflow (input is longer than terminal size),
1043 1.16 jdolecek * emulate scroll by dropping first line and shuffling the rest.
1044 1.16 jdolecek * We do this via pointer shuffling - it's safe in this case
1045 1.16 jdolecek * and we avoid memcpy().
1046 1.16 jdolecek */
1047 1.16 jdolecek if (el->el_cursor.v + 1 >= el->el_term.t_size.v) {
1048 1.16 jdolecek int i, lins = el->el_term.t_size.v;
1049 1.16 jdolecek char *firstline = el->el_display[0];
1050 1.16 jdolecek
1051 1.31 christos for(i = 1; i < lins; i++)
1052 1.31 christos el->el_display[i - 1] = el->el_display[i];
1053 1.16 jdolecek
1054 1.16 jdolecek re__copy_and_pad(firstline, "", 0);
1055 1.31 christos el->el_display[i - 1] = firstline;
1056 1.16 jdolecek } else {
1057 1.16 jdolecek el->el_cursor.v++;
1058 1.16 jdolecek el->el_refresh.r_oldcv++;
1059 1.16 jdolecek }
1060 1.15 lukem if (EL_HAS_AUTO_MARGINS) {
1061 1.15 lukem if (EL_HAS_MAGIC_MARGINS) {
1062 1.28 christos term__putc(el, ' ');
1063 1.28 christos term__putc(el, '\b');
1064 1.15 lukem }
1065 1.15 lukem } else {
1066 1.28 christos term__putc(el, '\r');
1067 1.28 christos term__putc(el, '\n');
1068 1.15 lukem }
1069 1.12 christos }
1070 1.15 lukem }
1071 1.1 cgd
1072 1.1 cgd
1073 1.1 cgd /* re_fastaddc():
1074 1.1 cgd * we added just one char, handle it fast.
1075 1.8 simonb * Assumes that screen cursor == real cursor
1076 1.1 cgd */
1077 1.1 cgd protected void
1078 1.15 lukem re_fastaddc(EditLine *el)
1079 1.1 cgd {
1080 1.15 lukem char c;
1081 1.15 lukem int rhdiff;
1082 1.1 cgd
1083 1.15 lukem c = el->el_line.cursor[-1];
1084 1.1 cgd
1085 1.15 lukem if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
1086 1.15 lukem re_refresh(el); /* too hard to handle */
1087 1.15 lukem return;
1088 1.15 lukem }
1089 1.15 lukem rhdiff = el->el_term.t_size.h - el->el_cursor.h -
1090 1.15 lukem el->el_rprompt.p_pos.h;
1091 1.15 lukem if (el->el_rprompt.p_pos.h && rhdiff < 3) {
1092 1.15 lukem re_refresh(el); /* clear out rprompt if less than 1 char gap */
1093 1.15 lukem return;
1094 1.15 lukem } /* else (only do at end of line, no TAB) */
1095 1.15 lukem if (iscntrl((unsigned char) c)) { /* if control char, do caret */
1096 1.15 lukem char mc = (c == '\177') ? '?' : (c | 0100);
1097 1.15 lukem re_fastputc(el, '^');
1098 1.15 lukem re_fastputc(el, mc);
1099 1.15 lukem } else if (isprint((unsigned char) c)) { /* normal char */
1100 1.15 lukem re_fastputc(el, c);
1101 1.15 lukem } else {
1102 1.15 lukem re_fastputc(el, '\\');
1103 1.24 christos re_fastputc(el, (int)(((((unsigned int)c) >> 6) & 3) + '0'));
1104 1.24 christos re_fastputc(el, (int)(((((unsigned int)c) >> 3) & 7) + '0'));
1105 1.15 lukem re_fastputc(el, (c & 7) + '0');
1106 1.15 lukem }
1107 1.28 christos term__flush(el);
1108 1.15 lukem }
1109 1.1 cgd
1110 1.1 cgd
1111 1.1 cgd /* re_clear_display():
1112 1.8 simonb * clear the screen buffers so that new new prompt starts fresh.
1113 1.1 cgd */
1114 1.1 cgd protected void
1115 1.15 lukem re_clear_display(EditLine *el)
1116 1.1 cgd {
1117 1.15 lukem int i;
1118 1.1 cgd
1119 1.15 lukem el->el_cursor.v = 0;
1120 1.15 lukem el->el_cursor.h = 0;
1121 1.15 lukem for (i = 0; i < el->el_term.t_size.v; i++)
1122 1.15 lukem el->el_display[i][0] = '\0';
1123 1.15 lukem el->el_refresh.r_oldcv = 0;
1124 1.15 lukem }
1125 1.1 cgd
1126 1.1 cgd
1127 1.1 cgd /* re_clear_lines():
1128 1.8 simonb * Make sure all lines are *really* blank
1129 1.1 cgd */
1130 1.1 cgd protected void
1131 1.15 lukem re_clear_lines(EditLine *el)
1132 1.1 cgd {
1133 1.15 lukem
1134 1.15 lukem if (EL_CAN_CEOL) {
1135 1.15 lukem int i;
1136 1.33 christos for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
1137 1.15 lukem /* for each line on the screen */
1138 1.15 lukem term_move_to_line(el, i);
1139 1.33 christos term_move_to_char(el, 0);
1140 1.15 lukem term_clear_EOL(el, el->el_term.t_size.h);
1141 1.15 lukem }
1142 1.15 lukem term_move_to_line(el, 0);
1143 1.15 lukem } else {
1144 1.15 lukem term_move_to_line(el, el->el_refresh.r_oldcv);
1145 1.15 lukem /* go to last line */
1146 1.28 christos term__putc(el, '\r'); /* go to BOL */
1147 1.28 christos term__putc(el, '\n'); /* go to new line */
1148 1.15 lukem }
1149 1.15 lukem }
1150