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