diff options
Diffstat (limited to 'lib/readline/display.c')
-rw-r--r-- | lib/readline/display.c | 210 |
1 files changed, 140 insertions, 70 deletions
diff --git a/lib/readline/display.c b/lib/readline/display.c index 0d3ae6e..47ff061 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -1,6 +1,6 @@ /* display.c -- readline redisplay facility. */ -/* Copyright (C) 1987-2005 Free Software Foundation, Inc. +/* Copyright (C) 1987-2006 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -59,10 +59,6 @@ extern char *strchr (), *strrchr (); #endif /* !strchr && !__STDC__ */ -#if defined (HACK_TERMCAP_MOTION) -extern char *_rl_term_forward_char; -#endif - static void update_line PARAMS((char *, char *, int, int, int, int)); static void space_to_eol PARAMS((int)); static void delete_chars PARAMS((int)); @@ -80,9 +76,18 @@ static int *inv_lbreaks, *vis_lbreaks; static int inv_lbsize, vis_lbsize; /* Heuristic used to decide whether it is faster to move from CUR to NEW - by backing up or outputting a carriage return and moving forward. */ + by backing up or outputting a carriage return and moving forward. CUR + and NEW are either both buffer positions or absolute screen positions. */ #define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) +/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a + buffer index in others. This macro is used when deciding whether the + current cursor position is in the middle of a prompt string containing + invisible characters. */ +#define PROMPT_ENDING_INDEX \ + ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1) + + /* **************************************************************** */ /* */ /* Display stuff */ @@ -135,6 +140,7 @@ int _rl_last_c_pos = 0; int _rl_last_v_pos = 0; static int cpos_adjusted; +static int cpos_buffer_position; /* Number of lines currently on screen minus 1. */ int _rl_vis_botlin = 0; @@ -162,6 +168,7 @@ static int line_size = 1024; include invisible characters. */ static char *local_prompt, *local_prompt_prefix; +static int local_prompt_len; static int prompt_visible_length, prompt_prefix_length; /* The number of invisible characters in the line currently being @@ -197,6 +204,7 @@ static char *saved_local_prefix; static int saved_last_invisible; static int saved_visible_length; static int saved_prefix_length; +static int saved_local_length; static int saved_invis_chars_first_line; static int saved_physical_chars; @@ -220,7 +228,7 @@ expand_prompt (pmt, lp, lip, niflp, vlp) char *pmt; int *lp, *lip, *niflp, *vlp; { - char *r, *ret, *p; + char *r, *ret, *p, *igstart; int l, rl, last, ignoring, ninvis, invfl, invflset, ind, pind, physchars; /* Short-circuit if we can. */ @@ -244,19 +252,21 @@ expand_prompt (pmt, lp, lip, niflp, vlp) invfl = 0; /* invisible chars in first line of prompt */ invflset = 0; /* we only want to set invfl once */ + igstart = 0; for (rl = ignoring = last = ninvis = physchars = 0, p = pmt; p && *p; p++) { /* This code strips the invisible character string markers RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */ - if (*p == RL_PROMPT_START_IGNORE) + if (ignoring == 0 && *p == RL_PROMPT_START_IGNORE) /* XXX - check ignoring? */ { - ignoring++; + ignoring = 1; + igstart = p; continue; } else if (ignoring && *p == RL_PROMPT_END_IGNORE) { ignoring = 0; - if (p[-1] != RL_PROMPT_START_IGNORE) + if (p != (igstart + 1)) last = r - ret - 1; continue; } @@ -356,6 +366,7 @@ rl_expand_prompt (prompt) FREE (local_prompt_prefix); local_prompt = local_prompt_prefix = (char *)0; + local_prompt_len = 0; prompt_last_invisible = prompt_invis_chars_first_line = 0; prompt_visible_length = prompt_physical_chars = 0; @@ -371,6 +382,7 @@ rl_expand_prompt (prompt) &prompt_invis_chars_first_line, &prompt_physical_chars); local_prompt_prefix = (char *)0; + local_prompt_len = local_prompt ? strlen (local_prompt) : 0; return (prompt_visible_length); } else @@ -389,6 +401,7 @@ rl_expand_prompt (prompt) &prompt_invis_chars_first_line, (int *)NULL); *t = c; + local_prompt_len = local_prompt ? strlen (local_prompt) : 0; return (prompt_prefix_length); } } @@ -445,7 +458,7 @@ rl_redisplay () { register int in, out, c, linenum, cursor_linenum; register char *line; - int c_pos, inv_botlin, lb_botlin, lb_linenum, o_cpos; + int inv_botlin, lb_botlin, lb_linenum, o_cpos; int newlines, lpos, temp, modmark, n0, num; char *prompt_this_line; #if defined (HANDLE_MULTIBYTE) @@ -469,7 +482,7 @@ rl_redisplay () } /* Draw the line into the buffer. */ - c_pos = -1; + cpos_buffer_position = -1; line = invisible_line; out = inv_botlin = 0; @@ -496,24 +509,23 @@ rl_redisplay () number of non-visible characters in the prompt string. */ if (rl_display_prompt == rl_prompt || local_prompt) { - int local_len = local_prompt ? strlen (local_prompt) : 0; if (local_prompt_prefix && forced_display) _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); - if (local_len > 0) + if (local_prompt_len > 0) { - temp = local_len + out + 2; + temp = local_prompt_len + out + 2; if (temp >= line_size) { line_size = (temp + 1024) - (temp % 1024); visible_line = (char *)xrealloc (visible_line, line_size); line = invisible_line = (char *)xrealloc (invisible_line, line_size); } - strncpy (line + out, local_prompt, local_len); - out += local_len; + strncpy (line + out, local_prompt, local_prompt_len); + out += local_prompt_len; } line[out] = '\0'; - wrap_offset = local_len - prompt_visible_length; + wrap_offset = local_prompt_len - prompt_visible_length; } else { @@ -614,6 +626,7 @@ rl_redisplay () contents of the command line? */ while (lpos >= _rl_screenwidth) { + int z; /* fix from Darin Johnson <darin@acuson.com> for prompt string with invisible characters that is longer than the screen width. The prompt_invis_chars_first_line variable could be made into an array @@ -622,37 +635,46 @@ rl_redisplay () prompts that exceed two physical lines? Additional logic fix from Edward Catmur <ed@catmur.co.uk> */ #if defined (HANDLE_MULTIBYTE) - n0 = num; - temp = local_prompt ? strlen (local_prompt) : 0; - while (num < temp) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { - if (_rl_col_width (local_prompt, n0, num) > _rl_screenwidth) + n0 = num; + temp = local_prompt_len; + while (num < temp) { - num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY); - break; + z = _rl_col_width (local_prompt, n0, num); + if (z > _rl_screenwidth) + { + num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY); + break; + } + else if (z == _rl_screenwidth) + break; + num++; } - num++; + temp = num; } - temp = num + -#else - temp = ((newlines + 1) * _rl_screenwidth) + + else #endif /* !HANDLE_MULTIBYTE */ - ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line - : ((newlines == 1) ? wrap_offset : 0)) - : ((newlines == 0) ? wrap_offset :0)); + temp = ((newlines + 1) * _rl_screenwidth); + + /* Now account for invisible characters in the current line. */ + temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line + : ((newlines == 1) ? wrap_offset : 0)) + : ((newlines == 0) ? wrap_offset :0)); inv_lbreaks[++newlines] = temp; #if defined (HANDLE_MULTIBYTE) - lpos -= _rl_col_width (local_prompt, n0, num); -#else - lpos -= _rl_screenwidth; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + lpos -= _rl_col_width (local_prompt, n0, num); + else #endif + lpos -= _rl_screenwidth; } prompt_last_screen_line = newlines; /* Draw the rest of the line (after the prompt) into invisible_line, keeping - track of where the cursor is (c_pos), the number of the line containing + track of where the cursor is (cpos_buffer_position), the number of the line containing the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin). It maintains an array of line breaks for display (inv_lbreaks). This handles expanding tabs for display and displaying meta characters. */ @@ -705,7 +727,7 @@ rl_redisplay () if (in == rl_point) { - c_pos = out; + cpos_buffer_position = out; lb_linenum = newlines; } @@ -799,7 +821,7 @@ rl_redisplay () } if (in == rl_point) { - c_pos = out; + cpos_buffer_position = out; lb_linenum = newlines; } for (i = in; i < in+wc_bytes; i++) @@ -830,9 +852,9 @@ rl_redisplay () } line[out] = '\0'; - if (c_pos < 0) + if (cpos_buffer_position < 0) { - c_pos = out; + cpos_buffer_position = out; lb_linenum = newlines; } @@ -841,7 +863,7 @@ rl_redisplay () inv_lbreaks[newlines+1] = out; cursor_linenum = lb_linenum; - /* C_POS == position in buffer where cursor should be placed. + /* CPOS_BUFFER_POSITION == position in buffer where cursor should be placed. CURSOR_LINENUM == line number where the cursor should be placed. */ /* PWP: now is when things get a bit hairy. The visible and invisible @@ -886,6 +908,8 @@ rl_redisplay () /* For each line in the buffer, do the updating display. */ for (linenum = 0; linenum <= inv_botlin; linenum++) { + /* This can lead us astray if we execute a program that changes + the locale from a non-multibyte to a multibyte one. */ o_cpos = _rl_last_c_pos; cpos_adjusted = 0; update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, @@ -898,7 +922,11 @@ rl_redisplay () change update_line itself. There is one case in which update_line adjusts _rl_last_c_pos itself (so it can pass _rl_move_cursor_relative accurate values); it communicates - this back by setting cpos_adjusted */ + this back by setting cpos_adjusted. If we assume that + _rl_last_c_pos is correct (an absolute cursor position) each + time update_line is called, then we can assume in our + calculations that o_cpos does not need to be adjusted by + wrap_offset. */ if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && cpos_adjusted == 0 && _rl_last_c_pos != o_cpos && @@ -967,7 +995,11 @@ rl_redisplay () invisible character in the prompt string. */ nleft = prompt_visible_length + wrap_offset; if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 && - _rl_last_c_pos <= prompt_last_invisible && local_prompt) +#if 0 + _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt) +#else + _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt) +#endif { #if defined (__MSDOS__) putc ('\r', rl_outstream); @@ -986,8 +1018,8 @@ rl_redisplay () in the buffer? */ pos = inv_lbreaks[cursor_linenum]; /* nleft == number of characters in the line buffer between the - start of the line and the cursor position. */ - nleft = c_pos - pos; + start of the line and the desired cursor position. */ + nleft = cpos_buffer_position - pos; /* NLEFT is now a number of characters in a buffer. When in a multibyte locale, however, _rl_last_c_pos is an absolute cursor @@ -999,6 +1031,7 @@ rl_redisplay () those characters here and call _rl_backspace() directly. */ if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) { + /* TX == new physical cursor position in multibyte locale. */ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset; else @@ -1032,11 +1065,11 @@ rl_redisplay () will be LMARGIN. */ /* The number of characters that will be displayed before the cursor. */ - ndisp = c_pos - wrap_offset; + ndisp = cpos_buffer_position - wrap_offset; nleft = prompt_visible_length + wrap_offset; /* Where the new cursor position will be on the screen. This can be longer than SCREENWIDTH; if it is, lmargin will be adjusted. */ - phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset); + phys_c_pos = cpos_buffer_position - (last_lmargin ? last_lmargin : wrap_offset); t = _rl_screenwidth / 3; /* If the number of characters had already exceeded the screenwidth, @@ -1047,7 +1080,7 @@ rl_redisplay () two-thirds of the way across the screen. */ if (phys_c_pos > _rl_screenwidth - 2) { - lmargin = c_pos - (2 * t); + lmargin = cpos_buffer_position - (2 * t); if (lmargin < 0) lmargin = 0; /* If the left margin would be in the middle of a prompt with @@ -1061,7 +1094,7 @@ rl_redisplay () { /* If we are moving back towards the beginning of the line and the last margin is no longer correct, compute a new one. */ - lmargin = ((c_pos - 1) / t) * t; /* XXX */ + lmargin = ((cpos_buffer_position - 1) / t) * t; /* XXX */ if (wrap_offset && lmargin > 0 && lmargin < nleft) lmargin = nleft; } @@ -1106,7 +1139,7 @@ rl_redisplay () if (visible_first_line_len > _rl_screenwidth) visible_first_line_len = _rl_screenwidth; - _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); + _rl_move_cursor_relative (cpos_buffer_position - lmargin, &invisible_line[lmargin]); last_lmargin = lmargin; } } @@ -1164,7 +1197,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) int col_lendiff, col_temp; #if defined (HANDLE_MULTIBYTE) mbstate_t ps_new, ps_old; - int new_offset, old_offset, tmp; + int new_offset, old_offset; #endif /* If we're at the right edge of a terminal that supports xn, we're @@ -1397,11 +1430,11 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) sequences (like drawing the `unbold' sequence without a corresponding `bold') that manifests itself on certain terminals. */ - lendiff = local_prompt ? strlen (local_prompt) : 0; + lendiff = local_prompt_len; od = ofd - old; /* index of first difference in visible line */ if (current_line == 0 && !_rl_horizontal_scroll_mode && _rl_term_cr && lendiff > prompt_visible_length && _rl_last_c_pos > 0 && - od >= lendiff && _rl_last_c_pos <= prompt_last_invisible) + od >= lendiff && _rl_last_c_pos < PROMPT_ENDING_INDEX) { #if defined (__MSDOS__) putc ('\r', rl_outstream); @@ -1420,7 +1453,19 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) _rl_last_c_pos = lendiff; } + /* When this function returns, _rl_last_c_pos is correct, and an absolute + cursor postion in multibyte mode, but a buffer index when not in a + multibyte locale. */ _rl_move_cursor_relative (od, old); +#if 1 +#if defined (HANDLE_MULTIBYTE) + /* We need to indicate that the cursor position is correct in the presence of + invisible characters in the prompt string. Let's see if setting this when + we make sure we're at the end of the drawn prompt string works. */ + if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 && _rl_last_c_pos == prompt_physical_chars) + cpos_adjusted = 1; +#endif +#endif /* if (len (new) > len (old)) lendiff == difference in buffer @@ -1648,10 +1693,11 @@ rl_on_new_line_with_prompt () int rl_forced_update_display () { + register char *temp; + if (visible_line) { - register char *temp = visible_line; - + temp = visible_line; while (*temp) *temp++ = '\0'; } @@ -1686,8 +1732,14 @@ _rl_move_cursor_relative (new, data) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { dpos = _rl_col_width (data, 0, new); - if (dpos > woff) - dpos -= woff; + if (dpos > prompt_last_invisible) /* XXX - don't use woff here */ + { + dpos -= woff; + /* Since this will be assigned to _rl_last_c_pos at the end (more + precisely, _rl_last_c_pos == dpos when this function returns), + let the caller know. */ + cpos_adjusted = 1; + } } else #endif @@ -1706,7 +1758,7 @@ _rl_move_cursor_relative (new, data) else #endif i = _rl_last_c_pos - woff; - if (new == 0 || CR_FASTER (new, _rl_last_c_pos) || + if (dpos == 0 || CR_FASTER (dpos, _rl_last_c_pos) || (_rl_term_autowrap && i == _rl_screenwidth)) { #if defined (__MSDOS__) @@ -1728,19 +1780,27 @@ _rl_move_cursor_relative (new, data) sequence telling the terminal to move forward one character. That kind of control is for people who don't know what the data is underneath the cursor. */ -#if defined (HACK_TERMCAP_MOTION) - if (_rl_term_forward_char) - { - for (i = cpos; i < dpos; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - else -#endif /* HACK_TERMCAP_MOTION */ + + /* However, we need a handle on where the current display position is + in the buffer for the immediately preceding comment to be true. + In multibyte locales, we don't currently have that info available. + Without it, we don't know where the data we have to display begins + in the buffer and we have to go back to the beginning of the screen + line. In this case, we can use the terminal sequence to move forward + if it's available. */ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); + if (_rl_term_forward_char) + { + for (i = cpos; i < dpos; i++) + tputs (_rl_term_forward_char, 1, _rl_output_character_function); + } + else + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } } else for (i = cpos; i < new; i++) @@ -1889,6 +1949,7 @@ rl_message (va_alist) &prompt_invis_chars_first_line, &prompt_physical_chars); local_prompt_prefix = (char *)NULL; + local_prompt_len = local_prompt ? strlen (local_prompt) : 0; (*rl_redisplay_function) (); return 0; @@ -1912,6 +1973,7 @@ rl_message (format, arg1, arg2) &prompt_invis_chars_first_line, &prompt_physical_chars); local_prompt_prefix = (char *)NULL; + local_prompt_len = local_prompt ? strlen (local_prompt) : 0; (*rl_redisplay_function) (); return 0; @@ -1948,12 +2010,14 @@ rl_save_prompt () saved_local_prompt = local_prompt; saved_local_prefix = local_prompt_prefix; saved_prefix_length = prompt_prefix_length; + saved_local_length = local_prompt_len; saved_last_invisible = prompt_last_invisible; saved_visible_length = prompt_visible_length; saved_invis_chars_first_line = prompt_invis_chars_first_line; saved_physical_chars = prompt_physical_chars; local_prompt = local_prompt_prefix = (char *)0; + local_prompt_len = 0; prompt_last_invisible = prompt_visible_length = prompt_prefix_length = 0; prompt_invis_chars_first_line = prompt_physical_chars = 0; } @@ -1966,6 +2030,7 @@ rl_restore_prompt () local_prompt = saved_local_prompt; local_prompt_prefix = saved_local_prefix; + local_prompt_len = saved_local_length; prompt_prefix_length = saved_prefix_length; prompt_last_invisible = saved_last_invisible; prompt_visible_length = saved_visible_length; @@ -1974,6 +2039,7 @@ rl_restore_prompt () /* can test saved_local_prompt to see if prompt info has been saved. */ saved_local_prompt = saved_local_prefix = (char *)0; + saved_local_length = 0; saved_last_invisible = saved_visible_length = saved_prefix_length = 0; saved_invis_chars_first_line = saved_physical_chars = 0; } @@ -2162,7 +2228,8 @@ _rl_update_final () char *last_line; last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]]; - _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); + cpos_buffer_position = -1; /* don't know where we are in buffer */ + _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */ _rl_clear_to_eol (0); putc (last_line[_rl_screenwidth - 1], rl_outstream); } @@ -2205,6 +2272,7 @@ redraw_prompt (t) &prompt_invis_chars_first_line, &prompt_physical_chars); local_prompt_prefix = (char *)NULL; + local_prompt_len = local_prompt ? strlen (local_prompt) : 0; rl_forced_update_display (); @@ -2307,12 +2375,14 @@ _rl_col_width (str, start, end) int start, end; { wchar_t wc; - mbstate_t ps = {0}; + mbstate_t ps; int tmp, point, width, max; if (end <= start) return 0; + memset (&ps, 0, sizeof (mbstate_t)); + point = 0; max = end; |