- for the `-v' operator, use a clever trick from Martijn Dekker and
just test whether N is between 0 and $#.
+ 1/21
+ ----
+lib/readline/text.c
+ - rl_change_case: fix argument to rl_extend_line_buffer; make sure to
+ reset s and e after call in case rl_line_buffer was reallocated
+
+lib/readline/vi_mode.c
+ - _rl_vi_save_replace: if start ends up being less than zero, make
+ sure we don't read before the start of rl_line_buffer
+ - rl_vi_overstrike_kill_line,rl_vi_overstrike_kill_word: replacement
+ functions for ^U and ^W in vi overstrike mode, to keep right value
+ for vi_replace_count.
+ - rl_vi_overstrike_yank: similar for ^Y and rl_yank
+
+ 1/22
+ ----
+lib/readline/display.c
+ - update_line: if we're trying to wrap lines on an autowrap terminal,
+ punt and do a dumb update if the number of bytes in the first char
+ on the new line is greater than the number of bytes in the first char
+ of the old line. There's no guarantee we'll be able to extend the
+ old line buffer enough to accommodate the new bytes
+ - update_line: try to avoid some operations when wrapping lines if the
+ number of bytes in the first characters of the old and new lines is
+ the same
+ - update_line: when updating vis_lbreaks after fixing up the lines when
+ wrapping, make sure we don't exceed an index of _rl_vis_botlin when
+ updating the line break offsets
+
+lib/readline/text.c
+ - rl_delete_text: if deleting text leaves the mark past rl_end, adjust
+ it to rl_end
+
+lib/readline/vi_mode.c
+ - _rl_vi_goto_mark: make sure to call _rl_fix_point after setting
+ rl_point to rl_mark
+
+ 1/23
+ ----
+lib/readline/kill.c
+ - rl_kill_region,region_kill_internal: call _rl_fix_point
+
+lib/readline/text.c,lib/readline/rlprivate.h
+ - _rl_fix_mark: new function to clamp rl_mark between 0 and rl_end
+
+ 1/24
+ ----
+lib/readline/bind.c
+ - rl_translate_keyseq: rework how key sequences are translated with
+ the intent of normalizing backslash treatment. Since the current
+ behavior of, e.g., \C-\\, is inconsistent, this change chooses to
+ effectively treat and display \\ as \\ instead of \C-\. This is not
+ completely backwards compatible, but it seems like the most reasonable
+ choice. This allows things like \M-\a but is not compatible with
+ pre-bash-4.4 (readline 7.0) handling of \C-\, which is now treated
+ like \C-\0. If that proves to be a problem, we can add code to
+ understand \C-\ as equivalent to \C-\\. Since attempting to bind
+ "\C-\" has generated an error for a long time, it doesn't seem like
+ it will be too much of a problem.
+ Fixes from Koichi Murase <myoga.murase@gmail.com>
+ - rl_invoking_keyseqs_in_map: make sure to consistently output
+ backslash as `\\' instead of producing `\C-\'
+ Fixes from Koichi Murase <myoga.murase@gmail.com>
static intmax_t asciicode __P((void));
-static WORD_LIST *garglist;
+static WORD_LIST *garglist, *orig_arglist;
static int retval;
static int conversion_error;
format = list->word->word;
tw = 0;
- garglist = list->next;
+ garglist = orig_arglist = list->next;
/* If the format string is empty after preprocessing, return immediately. */
if (format == 0 || *format == 0)
extern void set_posix_options __P((const char *));
extern void save_posix_options __P((void));
-#define save_posix_options() saved_posix_vars = get_posix_options (saved_posix_vars)
#if defined (RLIMTYPE)
extern RLIMTYPE string_to_rlimtype __P((char *));
return 0;
}
-#define ADD_NORMAL_CHAR(c) \
- do { \
- if (META_CHAR (c) && _rl_convert_meta_chars_to_ascii) \
- { \
- array[l++] = ESC; \
- array[l++] = UNMETA (c); \
- } \
- else \
- array[l++] = (c); \
- } while (0)
-
/* Translate the ASCII representation of SEQ, stuffing the values into ARRAY,
an array of characters. LEN gets the final length of ARRAY. Return
non-zero if there was an error parsing SEQ. */
rl_translate_keyseq (const char *seq, char *array, int *len)
{
register int i, l, temp;
+ int has_control, has_meta;
unsigned char c;
- for (i = l = 0; c = seq[i]; i++)
+ has_control = 0;
+ has_meta = 0;
+
+ /* When there are incomplete prefixes \C- or \M- (has_control || has_meta)
+ without base character at the end of SEQ, they are processed as the
+ prefixes for '\0'.
+ */
+ for (i = l = 0; (c = seq[i]) || has_control || has_meta; i++)
{
- if (c == '\\')
+ /* Only backslashes followed by a non-null character are handled
+ specially. Trailing backslash (backslash followed by '\0') is
+ processed as a normal character.
+ */
+ if (c == '\\' && seq[i + 1] != '\0')
{
c = seq[++i];
- if (c == 0)
+ /* Handle \C- and \M- prefixes. */
+ if (c == 'C' && seq[i + 1] == '-')
{
- array[l++] = '\\'; /* preserve trailing backslash */
- break;
+ i++;
+ has_control = 1;
+ continue;
}
-
- /* Handle \C- and \M- prefixes. */
- if ((c == 'C' || c == 'M') && seq[i + 1] == '-')
+ else if (c == 'M' && seq[i + 1] == '-')
{
- /* Handle special case of backwards define. */
- if (strncmp (&seq[i], "C-\\M-", 5) == 0)
- {
- array[l++] = ESC; /* ESC is meta-prefix */
- i += 5;
- array[l++] = CTRL (_rl_to_upper (seq[i]));
- }
- else if (c == 'M')
- {
- i++; /* seq[i] == '-' */
- /* XXX - obey convert-meta setting, convert to key seq */
- /* XXX - doesn't yet handle \M-\C-n if convert-meta is on */
- if (_rl_convert_meta_chars_to_ascii)
- {
- array[l++] = ESC; /* ESC is meta-prefix */
- i++;
- array[l++] = UNMETA (seq[i]); /* UNMETA just in case */
- }
- else if (seq[i+1] == '\\' && seq[i+2] == 'C' && seq[i+3] == '-')
- {
- i += 4;
- temp = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i]));
- array[l++] = META (temp);
- }
- else
- {
- /* This doesn't yet handle things like \M-\a, which may
- or may not have any reasonable meaning. You're
- probably better off using straight octal or hex. */
- i++;
- array[l++] = META (seq[i]);
- }
- }
- else if (c == 'C')
- {
- i += 2;
- /* Special hack for C-?... */
- array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i]));
- }
- if (seq[i] == '\0')
- break;
+ i++;
+ has_meta = 1;
continue;
}
switch (c)
{
case 'a':
- array[l++] = '\007';
+ c = '\007';
break;
case 'b':
- array[l++] = '\b';
+ c = '\b';
break;
case 'd':
- array[l++] = RUBOUT; /* readline-specific */
+ c = RUBOUT; /* readline-specific */
break;
case 'e':
- array[l++] = ESC;
+ c = ESC;
break;
case 'f':
- array[l++] = '\f';
+ c = '\f';
break;
case 'n':
- array[l++] = NEWLINE;
+ c = NEWLINE;
break;
case 'r':
- array[l++] = RETURN;
+ c = RETURN;
break;
case 't':
- array[l++] = TAB;
+ c = TAB;
break;
case 'v':
- array[l++] = 0x0B;
+ c = 0x0B;
break;
case '\\':
- array[l++] = '\\';
+ c = '\\';
break;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
c = (c * 8) + OCTVALUE (seq[i]);
i--; /* auto-increment in for loop */
c &= largest_char;
- ADD_NORMAL_CHAR (c);
break;
case 'x':
i++;
c = 'x';
i--; /* auto-increment in for loop */
c &= largest_char;
- ADD_NORMAL_CHAR (c);
break;
default: /* backslashes before non-special chars just add the char */
c &= largest_char;
- ADD_NORMAL_CHAR (c);
break; /* the backslash is stripped */
}
- continue;
}
- ADD_NORMAL_CHAR (c);
+ /* Process \C- and \M- flags */
+ if (has_control)
+ {
+ /* Special treatment for C-? */
+ c = (c == '?') ? RUBOUT : CTRL (_rl_to_upper (c));
+ has_control = 0;
+ }
+ if (has_meta)
+ {
+ c = META (c);
+ has_meta = 0;
+ }
+
+ /* If convert-meta is turned on, convert a meta char to a key sequence */
+ if (META_CHAR (c) && _rl_convert_meta_chars_to_ascii)
+ {
+ array[l++] = ESC; /* ESC is meta-prefix */
+ array[l++] = UNMETA (c);
+ }
+ else
+ array[l++] = (c);
+
+ /* Null characters may be processed for incomplete prefixes at the end of
+ sequence */
+ if (seq[i] == '\0')
+ break;
}
*len = l;
else
sprintf (keyname, "\\e");
}
- else if (CTRL_CHAR (key))
- sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key)));
- else if (key == RUBOUT)
- sprintf (keyname, "\\C-?");
- else if (key == '\\' || key == '"')
- {
- keyname[0] = '\\';
- keyname[1] = (char) key;
- keyname[2] = '\0';
- }
else
{
- keyname[0] = (char) key;
- keyname[1] = '\0';
+ int c = key, l = 0;
+ if (CTRL_CHAR (c) || c == RUBOUT)
+ {
+ keyname[l++] = '\\';
+ keyname[l++] = 'C';
+ keyname[l++] = '-';
+ c = (c == RUBOUT) ? '?' : _rl_to_lower (UNCTRL (c));
+ }
+
+ if (c == '\\' || c == '"')
+ keyname[l++] = '\\';
+
+ keyname[l++] = (char) c;
+ keyname[l++] = '\0';
}
strcat (keyname, seqs[i]);
_rl_last_v_pos++;
/* 5a. If the number of screen positions doesn't match, punt
- and do a dumb update. */
- if (newwidth != oldwidth)
+ and do a dumb update.
+ 5b. If the number of bytes is greater in the new line than
+ the old, do a dumb update, because there is no guarantee we
+ can extend the old line enough to fit the new bytes. */
+ if (newwidth != oldwidth || newbytes > oldbytes)
{
oe = old + omax;
ne = new + nmax;
memmove call to copy the trailing NUL. */
/* (strlen(old+oldbytes) == (omax - oldbytes - 1)) */
- memmove (old+newbytes, old+oldbytes, strlen (old+oldbytes) + 1);
+ /* Don't bother trying to fit the bytes if the number of bytes
+ doesn't change. */
+ if (oldbytes != newbytes)
+ memmove (old+newbytes, old+oldbytes, strlen (old+oldbytes) + 1);
memcpy (old, new, newbytes);
j = newbytes - oldbytes;
-
omax += j;
/* Fix up indices if we copy data from one line to another */
- for (i = current_line+1; i <= inv_botlin+1; i++)
+ for (i = current_line+1; j != 0 && i <= inv_botlin+1 && i <=_rl_vis_botlin+1; i++)
vis_lbreaks[i] += j;
}
}
_rl_copy_to_kill_ring (text, rl_point < rl_mark);
}
+ _rl_fix_point (1);
_rl_last_command_was_kill++;
return 0;
}
npoint = (rl_point < rl_mark) ? rl_point : rl_mark;
r = region_kill_internal (1);
- _rl_fix_point (1);
rl_point = npoint;
+ _rl_fix_point (1);
return r;
}
/* text.c */
extern void _rl_fix_point PARAMS((int));
+extern void _rl_fix_mark PARAMS((void));
extern int _rl_replace_text PARAMS((const char *, int, int));
extern int _rl_forward_char_internal PARAMS((int));
extern int _rl_backward_char_internal PARAMS((int));
rl_end -= diff;
rl_line_buffer[rl_end] = '\0';
+ _rl_fix_mark ();
return (diff);
}
if (fix_mark_too)
_RL_FIX_POINT (rl_mark);
}
+
+void
+_rl_fix_mark (void)
+{
+ _RL_FIX_POINT (rl_mark);
+}
#undef _RL_FIX_POINT
/* Replace the contents of the line buffer between START and END with
}
else if (m < mlen)
{
- rl_extend_line_buffer (mlen - m + 1);
+ rl_extend_line_buffer (rl_end + mlen + (e - s) - m + 2);
+ s = rl_line_buffer + start; /* have to redo this */
+ e = rl_line_buffer + rl_end;
memmove (s + mlen, s + m, (e - s) - m);
memcpy (s, mb, mlen);
next += mlen - m; /* next char changes */
/* vi_mode.c -- A vi emulation mode for Bash.
Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
-/* Copyright (C) 1987-2019 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of the GNU Readline Library (Readline), a library
for reading lines of text with interactive input and history editing.
start = end - vi_replace_count + 1;
len = vi_replace_count + 1;
+ if (start < 0)
+ {
+ len = end + 1;
+ start = 0;
+ }
+
vi_save_insert_buffer (start, len);
}
s = rl_point;
if (rl_do_undo ())
- vi_replace_count--;
+ vi_replace_count--; /* XXX */
if (rl_point == s)
rl_backward_char (1, key);
return (0);
}
+static int
+rl_vi_overstrike_kill_line (int count, int key)
+{
+ int r, end;
+
+ end = rl_end;
+ r = rl_unix_line_discard (count, key);
+ vi_replace_count -= end - rl_end;
+ return r;
+}
+
+static int
+rl_vi_overstrike_kill_word (int count, int key)
+{
+ int r, end;
+
+ end = rl_end;
+ r = rl_vi_unix_word_rubout (count, key);
+ vi_replace_count -= end - rl_end;
+ return r;
+}
+
+static int
+rl_vi_overstrike_yank (int count, int key)
+{
+ int r, end;
+
+ end = rl_end;
+ r = rl_yank (count, key);
+ vi_replace_count += rl_end - end;
+ return r;
+}
+
/* Read bracketed paste mode pasted text and insert it in overwrite mode */
static int
rl_vi_overstrike_bracketed_paste (int count, int key)
vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
+ /* Same for ^U and unix-line-discard. */
+ if (vi_insertion_keymap[CTRL ('U')].type == ISFUNC &&
+ vi_insertion_keymap[CTRL ('U')].function == rl_unix_line_discard)
+ vi_replace_map[CTRL ('U')].function = rl_vi_overstrike_kill_line;
+
+ /* And for ^W and unix-word-rubout. */
+ if (vi_insertion_keymap[CTRL ('W')].type == ISFUNC &&
+ vi_insertion_keymap[CTRL ('W')].function == rl_vi_unix_word_rubout)
+ vi_replace_map[CTRL ('W')].function = rl_vi_overstrike_kill_word;
+
+ /* And finally for ^Y and yank. */
+ if (vi_insertion_keymap[CTRL ('Y')].type == ISFUNC &&
+ vi_insertion_keymap[CTRL ('Y')].function == rl_yank)
+ vi_replace_map[CTRL ('Y')].function = rl_vi_overstrike_yank;
+
/* Make sure this is the value we need. */
vi_replace_map[ANYOTHERKEY].type = ISFUNC;
vi_replace_map[ANYOTHERKEY].function = (rl_command_func_t *)NULL;
if (ch == '`')
{
rl_point = rl_mark;
+ _rl_fix_point (1);
return 0;
}
else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
return 1;
}
rl_point = vi_mark_chars[ch];
+ _rl_fix_point (1);
return 0;
}
array_needs_making = 1;
if (flags)
- stupidly_hack_special_variables (newname);
+ {
+#if 0 /* TAG:bash-5.1 from Martijn Dekker */
+ if (STREQ (newname, "POSIXLY_CORRECT") || STREQ (newname, "POSIX_PEDANDTIC"))
+ save_posix_options (); /* XXX one level of saving right now */
+#endif
+ stupidly_hack_special_variables (newname);
+ }
if (echo_command_at_execute)
/* The Korn shell prints the `+ ' in front of assignment statements,