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