1 /* isearch.c - incremental searching */
3 /* **************************************************************** */
5 /* I-Search and Searching */
7 /* **************************************************************** */
9 /* Copyright (C) 1987-2021 Free Software Foundation, Inc.
11 This file is part of the GNU Readline Library (Readline), a library
12 for reading lines of text with interactive input and history editing.
14 Readline is free software: you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
19 Readline is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with Readline. If not, see <http://www.gnu.org/licenses/>.
28 #define READLINE_LIBRARY
30 #if defined (HAVE_CONFIG_H)
34 #include <sys/types.h>
38 #if defined (HAVE_UNISTD_H)
42 #if defined (HAVE_STDLIB_H)
45 # include "ansi_stdlib.h"
54 #include "rlprivate.h"
57 /* Variables exported to other files in the readline library. */
58 char *_rl_isearch_terminators
= (char *)NULL
;
60 _rl_search_cxt
*_rl_iscxt
= 0;
62 static int rl_search_history (int, int);
64 static _rl_search_cxt
*_rl_isearch_init (int);
65 static void _rl_isearch_fini (_rl_search_cxt
*);
67 /* Last line found by the current incremental search, so we don't `find'
68 identical lines many times in a row. Now part of isearch context. */
69 /* static char *prev_line_found; */
71 /* Last search string and its length. */
72 static char *last_isearch_string
;
73 static int last_isearch_string_len
;
75 static char * const default_isearch_terminators
= "\033\012";
78 _rl_scxt_alloc (int type
, int flags
)
82 cxt
= (_rl_search_cxt
*)xmalloc (sizeof (_rl_search_cxt
));
87 cxt
->search_string
= 0;
88 cxt
->search_string_size
= cxt
->search_string_index
= 0;
91 cxt
->allocated_line
= 0;
92 cxt
->hlen
= cxt
->hindex
= 0;
94 cxt
->save_point
= rl_point
;
95 cxt
->save_mark
= rl_mark
;
96 cxt
->save_line
= where_history ();
97 cxt
->last_found_line
= cxt
->save_line
;
98 cxt
->prev_line_found
= 0;
100 cxt
->save_undo_list
= 0;
102 cxt
->keymap
= _rl_keymap
;
103 cxt
->okeymap
= _rl_keymap
;
105 cxt
->history_pos
= 0;
108 cxt
->prevc
= cxt
->lastc
= 0;
111 cxt
->sline_len
= cxt
->sline_index
= 0;
113 cxt
->search_terminators
= 0;
119 _rl_scxt_dispose (_rl_search_cxt
*cxt
, int flags
)
121 FREE (cxt
->search_string
);
122 FREE (cxt
->allocated_line
);
128 /* Search backwards through the history looking for a string which is typed
129 interactively. Start with the current line. */
131 rl_reverse_search_history (int sign
, int key
)
133 return (rl_search_history (-sign
, key
));
136 /* Search forwards through the history looking for a string which is typed
137 interactively. Start with the current line. */
139 rl_forward_search_history (int sign
, int key
)
141 return (rl_search_history (sign
, key
));
144 /* Display the current state of the search in the echo-area.
145 SEARCH_STRING contains the string that is being searched for,
146 DIRECTION is zero for forward, or non-zero for reverse,
147 WHERE is the history list number of the current line. If it is
148 -1, then this line is the starting one. */
150 rl_display_search (char *search_string
, int flags
, int where
)
153 int msglen
, searchlen
;
155 searchlen
= (search_string
&& *search_string
) ? strlen (search_string
) : 0;
157 message
= (char *)xmalloc (searchlen
+ 64);
163 sprintf (message
, "[%d]", where
+ history_base
);
164 msglen
= strlen (message
);
168 message
[msglen
++] = '(';
170 if (flags
& SF_FAILED
)
172 strcpy (message
+ msglen
, "failed ");
176 if (flags
& SF_REVERSE
)
178 strcpy (message
+ msglen
, "reverse-");
182 strcpy (message
+ msglen
, "i-search)`");
185 if (search_string
&& *search_string
)
187 strcpy (message
+ msglen
, search_string
);
191 _rl_optimize_redisplay ();
193 strcpy (message
+ msglen
, "': ");
195 rl_message ("%s", message
);
198 /* rl_message calls this */
199 (*rl_redisplay_function
) ();
203 static _rl_search_cxt
*
204 _rl_isearch_init (int direction
)
210 cxt
= _rl_scxt_alloc (RL_SEARCH_ISEARCH
, 0);
212 cxt
->sflags
|= SF_REVERSE
;
214 cxt
->search_terminators
= _rl_isearch_terminators
? _rl_isearch_terminators
215 : default_isearch_terminators
;
217 /* Create an array of pointers to the lines that we want to search. */
218 hlist
= history_list ();
219 rl_maybe_replace_line ();
222 for (i
= 0; hlist
[i
]; i
++);
224 /* Allocate space for this many lines, +1 for the current input line,
225 and remember those lines. */
226 cxt
->lines
= (char **)xmalloc ((1 + (cxt
->hlen
= i
)) * sizeof (char *));
227 for (i
= 0; i
< cxt
->hlen
; i
++)
228 cxt
->lines
[i
] = hlist
[i
]->line
;
230 if (_rl_saved_line_for_history
)
231 cxt
->lines
[i
] = _rl_saved_line_for_history
->line
;
234 /* Keep track of this so we can free it. */
235 cxt
->allocated_line
= (char *)xmalloc (1 + strlen (rl_line_buffer
));
236 strcpy (cxt
->allocated_line
, &rl_line_buffer
[0]);
237 cxt
->lines
[i
] = cxt
->allocated_line
;
242 /* The line where we start the search. */
243 cxt
->history_pos
= cxt
->save_line
;
247 /* Initialize search parameters. */
248 cxt
->search_string
= (char *)xmalloc (cxt
->search_string_size
= 128);
249 cxt
->search_string
[cxt
->search_string_index
= 0] = '\0';
251 /* Normalize DIRECTION into 1 or -1. */
252 cxt
->direction
= (direction
>= 0) ? 1 : -1;
254 cxt
->sline
= rl_line_buffer
;
255 cxt
->sline_len
= strlen (cxt
->sline
);
256 cxt
->sline_index
= rl_point
;
258 _rl_iscxt
= cxt
; /* save globally */
260 /* experimental right now */
261 _rl_init_executing_keyseq ();
267 _rl_isearch_fini (_rl_search_cxt
*cxt
)
269 /* First put back the original state. */
270 rl_replace_line (cxt
->lines
[cxt
->save_line
], 0);
272 rl_restore_prompt ();
274 /* Save the search string for possible later use. */
275 FREE (last_isearch_string
);
276 last_isearch_string
= cxt
->search_string
;
277 last_isearch_string_len
= cxt
->search_string_index
;
278 cxt
->search_string
= 0;
279 cxt
->search_string_size
= 0;
280 cxt
->search_string_index
= 0;
282 if (cxt
->last_found_line
< cxt
->save_line
)
283 rl_get_previous_history (cxt
->save_line
- cxt
->last_found_line
, 0);
285 rl_get_next_history (cxt
->last_found_line
- cxt
->save_line
, 0);
287 /* If the string was not found, put point at the end of the last matching
288 line. If last_found_line == orig_line, we didn't find any matching
289 history lines at all, so put point back in its original position. */
290 if (cxt
->sline_index
< 0)
292 if (cxt
->last_found_line
== cxt
->save_line
)
293 cxt
->sline_index
= cxt
->save_point
;
295 cxt
->sline_index
= strlen (rl_line_buffer
);
296 rl_mark
= cxt
->save_mark
;
297 rl_deactivate_mark ();
300 rl_point
= cxt
->sline_index
;
301 /* Don't worry about where to put the mark here; rl_get_previous_history
302 and rl_get_next_history take care of it.
303 If we want to highlight the search string, this is where to set the
304 point and mark to do it. */
306 rl_deactivate_mark ();
308 /* _rl_optimize_redisplay (); */
312 /* XXX - we could use _rl_bracketed_read_mbstring () here. */
314 _rl_search_getchar (_rl_search_cxt
*cxt
)
318 /* Read a key and decide how to proceed. */
319 RL_SETSTATE(RL_STATE_MOREINPUT
);
320 c
= cxt
->lastc
= rl_read_key ();
321 RL_UNSETSTATE(RL_STATE_MOREINPUT
);
323 #if defined (HANDLE_MULTIBYTE)
324 /* This ends up with C (and LASTC) being set to the last byte of the
325 multibyte character. In most cases c == lastc == mb[0] */
326 if (c
>= 0 && MB_CUR_MAX
> 1 && rl_byte_oriented
== 0)
327 c
= cxt
->lastc
= _rl_read_mbstring (cxt
->lastc
, cxt
->mb
, MB_LEN_MAX
);
334 #define ENDSRCH_CHAR(c) \
335 ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
337 /* Process just-read character C according to isearch context CXT. Return
338 -1 if the caller should just free the context and return, 0 if we should
339 break out of the loop, and 1 if we should continue to read characters. */
341 _rl_isearch_dispatch (_rl_search_cxt
*cxt
, int c
)
343 int n
, wstart
, wlen
, limit
, cval
, incr
;
347 rl_command_func_t
*f
;
349 f
= (rl_command_func_t
*)NULL
;
353 cxt
->sflags
|= SF_FAILED
;
354 cxt
->history_pos
= cxt
->last_found_line
;
358 _rl_add_executing_keyseq (c
);
360 /* XXX - experimental code to allow users to bracketed-paste into the search
361 string even when ESC is one of the isearch-terminators. Not perfect yet. */
362 if (_rl_enable_bracketed_paste
&& c
== ESC
&& strchr (cxt
->search_terminators
, c
) && (n
= _rl_nchars_available ()) > (BRACK_PASTE_SLEN
-1))
364 j
= _rl_read_bracketed_paste_prefix (c
);
367 cxt
->lastc
= -7; /* bracketed paste, see below */
368 goto opcode_dispatch
;
370 else if (_rl_pushed_input_available ()) /* eat extra char we pushed back */
371 c
= cxt
->lastc
= rl_read_key ();
373 c
= cxt
->lastc
; /* last ditch */
376 /* If we are moving into a new keymap, modify cxt->keymap and go on.
377 This can be a problem if c == ESC and we want to terminate the
378 incremental search, so we check */
379 if (c
>= 0 && cxt
->keymap
[c
].type
== ISKMAP
&& strchr (cxt
->search_terminators
, cxt
->lastc
) == 0)
381 /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued
382 takes microseconds, so multiply by 1000. If we don't get any
383 additional input and this keymap shadows another function, process
384 that key as if it was all we read. */
385 if (_rl_keyseq_timeout
> 0 &&
386 RL_ISSTATE (RL_STATE_CALLBACK
) == 0 &&
387 RL_ISSTATE (RL_STATE_INPUTPENDING
) == 0 &&
388 _rl_pushed_input_available () == 0 &&
389 ((Keymap
)(cxt
->keymap
[c
].function
))[ANYOTHERKEY
].function
&&
390 _rl_input_queued (_rl_keyseq_timeout
*1000) == 0)
393 cxt
->okeymap
= cxt
->keymap
;
394 cxt
->keymap
= FUNCTION_TO_KEYMAP (cxt
->keymap
, c
);
395 cxt
->sflags
|= SF_CHGKMAP
;
396 /* XXX - we should probably save this sequence, so we can do
397 something useful if this doesn't end up mapping to a command we
398 interpret here. Right now we just save the most recent character
399 that caused the index into a new keymap. */
401 #if defined (HANDLE_MULTIBYTE)
402 if (MB_CUR_MAX
> 1 && rl_byte_oriented
== 0)
406 cxt
->pmb
[0] = c
; /* XXX should be == cxt->mb[0] */
410 memcpy (cxt
->pmb
, cxt
->mb
, sizeof (cxt
->pmb
));
418 /* Translate the keys we do something with to opcodes. */
419 if (c
>= 0 && cxt
->keymap
[c
].type
== ISFUNC
)
421 /* If we have a multibyte character, see if it's bound to something that
422 affects the search. */
423 #if defined (HANDLE_MULTIBYTE)
424 if (MB_CUR_MAX
> 1 && rl_byte_oriented
== 0 && cxt
->mb
[1])
425 f
= rl_function_of_keyseq (cxt
->mb
, cxt
->keymap
, (int *)NULL
);
429 f
= cxt
->keymap
[c
].function
;
430 if (f
== rl_do_lowercase_version
)
431 f
= cxt
->keymap
[_rl_to_lower (c
)].function
;
434 if (f
== rl_reverse_search_history
)
435 cxt
->lastc
= (cxt
->sflags
& SF_REVERSE
) ? -1 : -2;
436 else if (f
== rl_forward_search_history
)
437 cxt
->lastc
= (cxt
->sflags
& SF_REVERSE
) ? -2 : -1;
438 else if (f
== rl_rubout
)
440 else if (c
== CTRL ('G') || f
== rl_abort
)
442 else if (c
== CTRL ('W') || f
== rl_unix_word_rubout
) /* XXX */
444 else if (c
== CTRL ('Y') || f
== rl_yank
) /* XXX */
446 else if (f
== rl_bracketed_paste_begin
)
450 /* If we changed the keymap earlier while translating a key sequence into
451 a command, restore it now that we've succeeded. */
452 if (cxt
->sflags
& SF_CHGKMAP
)
454 cxt
->keymap
= cxt
->okeymap
;
455 cxt
->sflags
&= ~SF_CHGKMAP
;
456 /* If we indexed into a new keymap, but didn't map to a command that
457 affects the search (lastc > 0), and the character that mapped to a
458 new keymap would have ended the search (ENDSRCH_CHAR(cxt->prevc)),
459 handle that now as if the previous char would have ended the search
460 and we would have read the current character. */
461 /* XXX - should we check cxt->mb? */
462 if (cxt
->lastc
> 0 && ENDSRCH_CHAR (cxt
->prevc
))
464 rl_stuff_char (cxt
->lastc
);
465 rl_execute_next (cxt
->prevc
);
466 /* XXX - do we insert everything in cxt->pmb? */
469 /* Otherwise, if the current character is mapped to self-insert or
470 nothing (i.e., not an editing command), and the previous character
471 was a keymap index, then we need to insert both the previous
472 character and the current character into the search string. */
473 else if (cxt
->lastc
> 0 && cxt
->prevc
> 0 &&
474 cxt
->keymap
[cxt
->prevc
].type
== ISKMAP
&&
475 (f
== 0 || f
== rl_insert
))
477 /* Make lastc be the next character read */
478 /* XXX - do we insert everything in cxt->mb? */
479 rl_execute_next (cxt
->lastc
);
480 /* Dispatch on the previous character (insert into search string) */
481 cxt
->lastc
= cxt
->prevc
;
482 #if defined (HANDLE_MULTIBYTE)
483 /* Have to overwrite cxt->mb here because dispatch uses it below */
484 if (MB_CUR_MAX
> 1 && rl_byte_oriented
== 0)
486 if (cxt
->pmb
[1] == 0)
488 cxt
->mb
[0] = cxt
->lastc
; /* == cxt->prevc */
492 memcpy (cxt
->mb
, cxt
->pmb
, sizeof (cxt
->mb
));
497 else if (cxt
->lastc
> 0 && cxt
->prevc
> 0 && f
&& f
!= rl_insert
)
499 _rl_term_executing_keyseq (); /* should this go in the caller? */
501 _rl_pending_command
.map
= cxt
->keymap
;
502 _rl_pending_command
.count
= 1; /* XXX */
503 _rl_pending_command
.key
= cxt
->lastc
;
504 _rl_pending_command
.func
= f
;
505 _rl_command_to_execute
= &_rl_pending_command
;
511 /* The characters in isearch_terminators (set from the user-settable
512 variable isearch-terminators) are used to terminate the search but
513 not subsequently execute the character as a command. The default
514 value is "\033\012" (ESC and C-J). */
515 if (cxt
->lastc
> 0 && strchr (cxt
->search_terminators
, cxt
->lastc
))
517 /* ESC still terminates the search, but if there is pending
518 input or if input arrives within 0.1 seconds (on systems
519 with select(2)) it is used as a prefix character
520 with rl_execute_next. WATCH OUT FOR THIS! This is intended
521 to allow the arrow keys to be used like ^F and ^B are used
522 to terminate the search and execute the movement command.
523 XXX - since _rl_input_available depends on the application-
524 settable keyboard timeout value, this could alternatively
525 use _rl_input_queued(100000) */
526 if (cxt
->lastc
== ESC
&& (_rl_pushed_input_available () || _rl_input_available ()))
527 rl_execute_next (ESC
);
531 #if defined (HANDLE_MULTIBYTE)
532 if (MB_CUR_MAX
> 1 && rl_byte_oriented
== 0)
534 if (cxt
->lastc
>= 0 && (cxt
->mb
[0] && cxt
->mb
[1] == '\0') && ENDSRCH_CHAR (cxt
->lastc
))
536 /* This sets rl_pending_input to LASTC; it will be picked up the next
537 time rl_read_key is called. */
538 rl_execute_next (cxt
->lastc
);
544 if (cxt
->lastc
>= 0 && ENDSRCH_CHAR (cxt
->lastc
))
546 /* This sets rl_pending_input to LASTC; it will be picked up the next
547 time rl_read_key is called. */
548 rl_execute_next (cxt
->lastc
);
552 _rl_init_executing_keyseq ();
555 /* Now dispatch on the character. `Opcodes' affect the search string or
556 state. Other characters are added to the string. */
561 if (cxt
->search_string_index
== 0)
563 if (last_isearch_string
)
565 cxt
->search_string_size
= 64 + last_isearch_string_len
;
566 cxt
->search_string
= (char *)xrealloc (cxt
->search_string
, cxt
->search_string_size
);
567 strcpy (cxt
->search_string
, last_isearch_string
);
568 cxt
->search_string_index
= last_isearch_string_len
;
569 rl_display_search (cxt
->search_string
, cxt
->sflags
, -1);
572 /* XXX - restore keymap here? */
575 else if ((cxt
->sflags
& SF_REVERSE
) && cxt
->sline_index
>= 0)
577 else if (cxt
->sline_index
!= cxt
->sline_len
)
583 /* switch directions */
585 cxt
->direction
= -cxt
->direction
;
586 if (cxt
->direction
< 0)
587 cxt
->sflags
|= SF_REVERSE
;
589 cxt
->sflags
&= ~SF_REVERSE
;
592 /* delete character from search string. */
593 case -3: /* C-H, DEL */
594 /* This is tricky. To do this right, we need to keep a
595 stack of search positions for the current search, with
596 sentinels marking the beginning and end. But this will
597 do until we have a real isearch-undo. */
598 if (cxt
->search_string_index
== 0)
600 else if (MB_CUR_MAX
== 1 || rl_byte_oriented
)
601 cxt
->search_string
[--cxt
->search_string_index
] = '\0';
604 wstart
= _rl_find_prev_mbchar (cxt
->search_string
, cxt
->search_string_index
, MB_FIND_NONZERO
);
606 cxt
->search_string
[cxt
->search_string_index
= wstart
] = '\0';
608 cxt
->search_string
[cxt
->search_string_index
= 0] = '\0';
611 if (cxt
->search_string_index
== 0)
616 case -4: /* C-G, abort */
617 rl_replace_line (cxt
->lines
[cxt
->save_line
], 0);
618 rl_point
= cxt
->save_point
;
619 rl_mark
= cxt
->save_mark
;
620 rl_deactivate_mark ();
624 _rl_fix_point (1); /* in case save_line and save_point are out of sync */
628 /* skip over portion of line we already matched and yank word */
629 wstart
= rl_point
+ cxt
->search_string_index
;
630 if (wstart
>= rl_end
)
636 /* if not in a word, move to one. */
637 cval
= _rl_char_value (rl_line_buffer
, wstart
);
638 if (_rl_walphabetic (cval
) == 0)
643 n
= MB_NEXTCHAR (rl_line_buffer
, wstart
, 1, MB_FIND_NONZERO
);;
646 cval
= _rl_char_value (rl_line_buffer
, n
);
647 if (_rl_walphabetic (cval
) == 0)
649 n
= MB_NEXTCHAR (rl_line_buffer
, n
, 1, MB_FIND_NONZERO
);;
651 wlen
= n
- wstart
+ 1;
652 if (cxt
->search_string_index
+ wlen
+ 1 >= cxt
->search_string_size
)
654 cxt
->search_string_size
+= wlen
+ 1;
655 cxt
->search_string
= (char *)xrealloc (cxt
->search_string
, cxt
->search_string_size
);
657 for (; wstart
< n
; wstart
++)
658 cxt
->search_string
[cxt
->search_string_index
++] = rl_line_buffer
[wstart
];
659 cxt
->search_string
[cxt
->search_string_index
] = '\0';
663 /* skip over portion of line we already matched and yank rest */
664 wstart
= rl_point
+ cxt
->search_string_index
;
665 if (wstart
>= rl_end
)
670 n
= rl_end
- wstart
+ 1;
671 if (cxt
->search_string_index
+ n
+ 1 >= cxt
->search_string_size
)
673 cxt
->search_string_size
+= n
+ 1;
674 cxt
->search_string
= (char *)xrealloc (cxt
->search_string
, cxt
->search_string_size
);
676 for (n
= wstart
; n
< rl_end
; n
++)
677 cxt
->search_string
[cxt
->search_string_index
++] = rl_line_buffer
[n
];
678 cxt
->search_string
[cxt
->search_string_index
] = '\0';
681 case -7: /* bracketed paste */
682 paste
= _rl_bracketed_text (&pastelen
);
683 if (paste
== 0 || *paste
== 0)
688 if (_rl_enable_active_region
)
690 if (cxt
->search_string_index
+ pastelen
+ 1 >= cxt
->search_string_size
)
692 cxt
->search_string_size
+= pastelen
+ 2;
693 cxt
->search_string
= (char *)xrealloc (cxt
->search_string
, cxt
->search_string_size
);
695 memcpy (cxt
->search_string
+ cxt
->search_string_index
, paste
, pastelen
);
696 cxt
->search_string_index
+= pastelen
;
697 cxt
->search_string
[cxt
->search_string_index
] = '\0';
701 /* Add character to search string and continue search. */
703 #if defined (HANDLE_MULTIBYTE)
704 wlen
= (cxt
->mb
[0] == 0 || cxt
->mb
[1] == 0) ? 1 : RL_STRLEN (cxt
->mb
);
708 if (cxt
->search_string_index
+ wlen
+ 1 >= cxt
->search_string_size
)
710 cxt
->search_string_size
+= 128; /* 128 much greater than MB_CUR_MAX */
711 cxt
->search_string
= (char *)xrealloc (cxt
->search_string
, cxt
->search_string_size
);
713 #if defined (HANDLE_MULTIBYTE)
714 if (MB_CUR_MAX
> 1 && rl_byte_oriented
== 0)
718 if (cxt
->mb
[0] == 0 || cxt
->mb
[1] == 0)
719 cxt
->search_string
[cxt
->search_string_index
++] = cxt
->mb
[0];
721 for (j
= 0; j
< wlen
; )
722 cxt
->search_string
[cxt
->search_string_index
++] = cxt
->mb
[j
++];
726 cxt
->search_string
[cxt
->search_string_index
++] = cxt
->lastc
; /* XXX - was c instead of lastc */
727 cxt
->search_string
[cxt
->search_string_index
] = '\0';
731 for (cxt
->sflags
&= ~(SF_FOUND
|SF_FAILED
);; )
733 if (cxt
->search_string_index
== 0)
735 cxt
->sflags
|= SF_FAILED
;
739 limit
= cxt
->sline_len
- cxt
->search_string_index
+ 1;
741 /* Search the current line. */
742 while ((cxt
->sflags
& SF_REVERSE
) ? (cxt
->sline_index
>= 0) : (cxt
->sline_index
< limit
))
744 if (STREQN (cxt
->search_string
, cxt
->sline
+ cxt
->sline_index
, cxt
->search_string_index
))
746 cxt
->sflags
|= SF_FOUND
;
750 cxt
->sline_index
+= cxt
->direction
;
752 if (cxt
->sline_index
< 0)
754 cxt
->sline_index
= 0;
758 if (cxt
->sflags
& SF_FOUND
)
761 /* Move to the next line, but skip new copies of the line
762 we just found and lines shorter than the string we're
766 /* Move to the next line. */
767 cxt
->history_pos
+= cxt
->direction
;
769 /* At limit for direction? */
770 if ((cxt
->sflags
& SF_REVERSE
) ? (cxt
->history_pos
< 0) : (cxt
->history_pos
== cxt
->hlen
))
772 cxt
->sflags
|= SF_FAILED
;
776 /* We will need these later. */
777 cxt
->sline
= cxt
->lines
[cxt
->history_pos
];
778 cxt
->sline_len
= strlen (cxt
->sline
);
780 while ((cxt
->prev_line_found
&& STREQ (cxt
->prev_line_found
, cxt
->lines
[cxt
->history_pos
])) ||
781 (cxt
->search_string_index
> cxt
->sline_len
));
783 if (cxt
->sflags
& SF_FAILED
)
785 /* XXX - reset sline_index if < 0 */
786 if (cxt
->sline_index
< 0)
787 cxt
->sline_index
= 0;
791 /* Now set up the line for searching... */
792 cxt
->sline_index
= (cxt
->sflags
& SF_REVERSE
) ? cxt
->sline_len
- cxt
->search_string_index
: 0;
795 /* reset the keymaps for the next time through the loop */
796 cxt
->keymap
= cxt
->okeymap
= _rl_keymap
;
798 if (cxt
->sflags
& SF_FAILED
)
800 /* We cannot find the search string. Ding the bell. */
802 cxt
->history_pos
= cxt
->last_found_line
;
803 rl_deactivate_mark ();
804 rl_display_search (cxt
->search_string
, cxt
->sflags
, (cxt
->history_pos
== cxt
->save_line
) ? -1 : cxt
->history_pos
);
808 /* We have found the search string. Just display it. But don't
809 actually move there in the history list until the user accepts
811 if (cxt
->sflags
& SF_FOUND
)
813 cxt
->prev_line_found
= cxt
->lines
[cxt
->history_pos
];
814 rl_replace_line (cxt
->lines
[cxt
->history_pos
], 0);
815 if (_rl_enable_active_region
)
817 rl_point
= cxt
->sline_index
;
818 if (rl_mark_active_p () && cxt
->search_string_index
> 0)
819 rl_mark
= rl_point
+ cxt
->search_string_index
;
820 cxt
->last_found_line
= cxt
->history_pos
;
821 rl_display_search (cxt
->search_string
, cxt
->sflags
, (cxt
->history_pos
== cxt
->save_line
) ? -1 : cxt
->history_pos
);
828 _rl_isearch_cleanup (_rl_search_cxt
*cxt
, int r
)
831 _rl_isearch_fini (cxt
);
832 _rl_scxt_dispose (cxt
, 0);
835 RL_UNSETSTATE(RL_STATE_ISEARCH
);
840 /* Search through the history looking for an interactively typed string.
841 This is analogous to i-search. We start the search in the current line.
842 DIRECTION is which direction to search; >= 0 means forward, < 0 means
845 rl_search_history (int direction
, int invoking_key
)
847 _rl_search_cxt
*cxt
; /* local for now, but saved globally */
850 RL_SETSTATE(RL_STATE_ISEARCH
);
851 cxt
= _rl_isearch_init (direction
);
853 rl_display_search (cxt
->search_string
, cxt
->sflags
, -1);
855 /* If we are using the callback interface, all we do is set up here and
856 return. The key is that we leave RL_STATE_ISEARCH set. */
857 if (RL_ISSTATE (RL_STATE_CALLBACK
))
863 c
= _rl_search_getchar (cxt
);
864 /* We might want to handle EOF here (c == 0) */
865 r
= _rl_isearch_dispatch (cxt
, cxt
->lastc
);
870 /* The searching is over. The user may have found the string that she
871 was looking for, or else she may have exited a failing search. If
872 LINE_INDEX is -1, then that shows that the string searched for was
873 not found. We use this to determine where to place rl_point. */
874 return (_rl_isearch_cleanup (cxt
, r
));
877 #if defined (READLINE_CALLBACKS)
878 /* Called from the callback functions when we are ready to read a key. The
879 callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH).
880 If _rl_isearch_dispatch finishes searching, this function is responsible
881 for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */
883 _rl_isearch_callback (_rl_search_cxt
*cxt
)
887 c
= _rl_search_getchar (cxt
);
888 /* We might want to handle EOF here */
889 r
= _rl_isearch_dispatch (cxt
, cxt
->lastc
);
891 return (r
<= 0) ? _rl_isearch_cleanup (cxt
, r
) : 0;