local_prompt_invis_chars[0] = 0;
if (prompt == 0 || *prompt == 0)
- return (0);
+ {
+ local_prompt = xmalloc (sizeof (char));
+ local_prompt[0] = '\0';
+ return (0);
+ }
p = strrchr (prompt, '\n');
if (p == 0)
wc_width = (temp >= 0) ? temp : 1;
}
}
+ else
+ wc_width = 1; /* make sure it's set for the META_CHAR check */
#endif
if (in == rl_point)
}
#if defined (HANDLE_MULTIBYTE)
- if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */
+ if (META_CHAR (c) && wc_bytes == 1 && wc_width == 1)
#else
if (META_CHAR (c))
#endif
{
+#if 0
+ /* TAG: readline-8.3 20230227 */
+ /* https://savannah.gnu.org/support/index.php?110830
+ asking for non-printing meta characters to be printed using an
+ escape sequence. */
+
+ /* isprint(c) handles bytes up to UCHAR_MAX */
+ if (_rl_output_meta_chars == 0 || isprint (c) == 0)
+#else
if (_rl_output_meta_chars == 0)
+#endif
{
char obuf[5];
int olen;
squote = 0;
if (string[i])
i++;
+ if (i >= l)
+ i = l;
}
for ( ; string[i]; i++)
flag = (i > 0 && string[i - 1] == '$');
i++;
hist_string_extract_single_quoted (string, &i, flag);
+ if (i >= l)
+ {
+ i = l;
+ break;
+ }
}
else if (history_quotes_inhibit_expansion && string[i] == '\\')
{
}
}
-
+
if (string[i] != history_expansion_char)
{
xfree (result);
(delimiter != '"' || member (string[i], slashify_in_quotes)))
{
i++;
+ if (string[i] == 0)
+ break;
continue;
}
/* histlib.h -- internal definitions for the history library. */
-/* Copyright (C) 1989-2009,2021-2022 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2009,2021-2023 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
/* history.c */
extern void _hs_replace_history_data (int, histdata_t *, histdata_t *);
+extern int _hs_search_history_data (histdata_t *);
extern int _hs_at_end_of_history (void);
/* histfile.c */
/* history.c -- standalone history library */
-/* Copyright (C) 1989-2021 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2023 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
}
last = -1;
- for (i = 0; i < history_length; i++)
+ for (i = history_length - 1; i >= 0; i--)
{
entry = the_history[i];
if (entry == 0)
entry = the_history[last];
entry->data = new; /* XXX - we don't check entry->old */
}
-}
+}
+
+int
+_hs_search_history_data (histdata_t *needle)
+{
+ register int i;
+ HIST_ENTRY *entry;
+
+ if (history_length == 0 || the_history == 0)
+ return -1;
+
+ for (i = history_length - 1; i >= 0; i--)
+ {
+ entry = the_history[i];
+ if (entry == 0)
+ continue;
+ if (entry->data == needle)
+ return i;
+ }
+ return -1;
+}
/* Remove history element WHICH from the history. The removed
element is returned to you so you can free the line, data,
else
cxt->sline_index += cxt->direction;
- if (cxt->sline_index < 0)
+ if (cxt->sline_index < 0 || cxt->sline_index > cxt->sline_len)
{
cxt->sline_index = 0;
break;
if (cxt->sflags & SF_FAILED)
{
- /* XXX - reset sline_index if < 0 */
- if (cxt->sline_index < 0)
+ /* XXX - reset sline_index if < 0 or longer than the history line */
+ if (cxt->sline_index < 0 || cxt->sline_index > cxt->sline_len)
cxt->sline_index = 0;
break;
}
if (count <= 0)
count = 1;
- while (count--)
+ while (rl_point > 0 && count--)
{
c = rl_line_buffer[rl_point - 1];
/* First move backwards through whitespace */
while (rl_point && whitespace (c))
{
- rl_point--;
- c = rl_line_buffer[rl_point - 1];
+ if (--rl_point)
+ c = rl_line_buffer[rl_point - 1];
}
/* Consume one or more slashes. */
while (rl_point && (whitespace (c) || c == '/'))
{
- rl_point--;
- c = rl_line_buffer[rl_point - 1];
+ if (--rl_point)
+ c = rl_line_buffer[rl_point - 1];
}
while (rl_point && (whitespace (c) == 0) && c != '/')
{
- rl_point--; /* XXX - multibyte? */
- c = rl_line_buffer[rl_point - 1];
+ if (--rl_point) /* XXX - multibyte? */
+ c = rl_line_buffer[rl_point - 1];
}
}
xfree (temp->line);
FREE (temp->timestamp);
xfree (temp);
+ /* XXX - what about _rl_saved_line_for_history? if the saved undo list
+ is rl_undo_list, and we just put that into a history entry, should
+ we set the saved undo list to NULL? */
}
return 0;
}
{
if (_rl_saved_line_for_history)
{
- if (rl_undo_list && rl_undo_list == (UNDO_LIST *)_rl_saved_line_for_history->data)
- rl_undo_list = 0;
- /* Have to free this separately because _rl_free_history entry can't:
- it doesn't know whether or not this has application data. Only the
- callers that know this is _rl_saved_line_for_history can know that
- it's an undo list. */
- if (_rl_saved_line_for_history->data)
- _rl_free_undo_list ((UNDO_LIST *)_rl_saved_line_for_history->data);
+ UNDO_LIST *sentinel;
+
+ sentinel = (UNDO_LIST *)_rl_saved_line_for_history->data;
+
+ /* We should only free `data' if it's not the current rl_undo_list and
+ it's not the `data' member in a history entry somewhere. We have to
+ free it separately because only the callers know it's an undo list. */
+ if (sentinel && sentinel != rl_undo_list && _hs_search_history_data ((histdata_t *)sentinel) < 0)
+ _rl_free_undo_list (sentinel);
+
_rl_free_history_entry (_rl_saved_line_for_history);
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
}
xlist = _rl_saved_line_for_history ? (UNDO_LIST *)_rl_saved_line_for_history->data : 0;
/* At this point, rl_undo_list points to a private search string list. */
- if (rl_undo_list && rl_undo_list != (UNDO_LIST *)entry->data && rl_undo_list != xlist)
+ if (rl_undo_list && rl_undo_list != (UNDO_LIST *)entry->data && rl_undo_list != xlist &&
+ _hs_search_history_data ((histdata_t *)rl_undo_list) < 0)
rl_free_undo_list ();
+ rl_undo_list = 0; /* XXX */
/* Now we create a new undo list with a single insert for this text.
WE DON'T CHANGE THE ORIGINAL HISTORY ENTRY UNDO LIST */
if (rl_point)
{
/* Allocate enough space for anchored and non-anchored searches */
- if (_rl_history_search_len >= history_string_size - 2)
+ if (_rl_history_search_len + 2 >= history_string_size)
{
history_string_size = _rl_history_search_len + 2;
history_search_string = (char *)xrealloc (history_search_string, history_string_size);
#define INCREMENT_POS(start) (start)++
#endif /* !HANDLE_MULTIBYTE */
+/* Flags for the motion context */
+#define MOVE_SUCCESS 0
+#define MOVE_FAILED 0x01
+
/* This is global so other parts of the code can check whether the last
command was a text modification command. */
int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
static int
rl_domove_motion_callback (_rl_vimotion_cxt *m)
{
- int c;
+ int c, r, opoint;
_rl_vi_last_motion = c = m->motion;
rl_extend_line_buffer (rl_end + 1);
rl_line_buffer[rl_end++] = ' ';
rl_line_buffer[rl_end] = '\0';
+ opoint = rl_point;
+
+ r = _rl_dispatch (c, _rl_keymap);
- _rl_dispatch (c, _rl_keymap);
+ /* Note in the context that the motion command failed. Right now we only do
+ this for unsuccessful searches (ones where _rl_dispatch returns non-zero
+ and point doesn't move). */
+ if (r != 0 && rl_point == opoint && (c == 'f' || c == 'F'))
+ m->flags |= MOVE_FAILED;
#if defined (READLINE_CALLBACKS)
if (RL_ISSTATE (RL_STATE_CALLBACK))
{
/* 'c' and 'C' enter insert mode after the delete even if the motion
didn't delete anything, as long as the motion command is valid. */
- if (_rl_to_upper (m->key) == 'C' && _rl_vi_motion_command (c))
+ if (_rl_to_upper (m->key) == 'C' && _rl_vi_motion_command (c) && (m->flags & MOVE_FAILED) == 0)
return (vidomove_dispatch (m));
RL_UNSETSTATE (RL_STATE_VIMOTION);
return (-1);
_rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key);
}
else if (_rl_vimvcxt)
- _rl_mvcxt_init (_rl_vimvcxt, VIM_DELETE, key);
+ {
+ /* are we being called recursively or by `y' or `c'? */
+ savecxt = _rl_vimvcxt;
+ _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key);
+ }
else
_rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key);
_rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
}
else if (_rl_vimvcxt)
- _rl_mvcxt_init (_rl_vimvcxt, VIM_CHANGE, key);
+ {
+ /* are we being called recursively or by `y' or `d'? */
+ savecxt = _rl_vimvcxt;
+ _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
+ }
else
_rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
_rl_vimvcxt->start = rl_point;
_rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
}
else if (_rl_vimvcxt)
- _rl_mvcxt_init (_rl_vimvcxt, VIM_YANK, key);
+ {
+ /* are we being called recursively or by `c' or `d'? */
+ savecxt = _rl_vimvcxt;
+ _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
+ }
else
_rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
_rl_vimvcxt->start = rl_point;