Subversion Repositories Open64

[/] [sim/] [fsim/] [shell/] [tclsh/] [readline/] [vi_mode.c] - Blame information for rev 2072

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2072 malin
/* vi_mode.c -- A vi emulation mode for Bash.
2
   Derived from code written by Jeff Sparkes (jsparkes@bnr.ca).  */
3
 
4
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
5
 
6
   This file is part of the GNU Readline Library, a library for
7
   reading lines of text with interactive input and history editing.
8
 
9
   The GNU Readline Library is free software; you can redistribute it
10
   and/or modify it under the terms of the GNU General Public License
11
   as published by the Free Software Foundation; either version 2, or
12
   (at your option) any later version.
13
 
14
   The GNU Readline Library is distributed in the hope that it will be
15
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16
   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
 
19
   The GNU General Public License is often shipped with GNU software, and
20
   is generally kept in a file called COPYING or LICENSE.  If you do not
21
   have a copy of the license, write to the Free Software Foundation,
22
   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23
#define READLINE_LIBRARY
24
 
25
/* **************************************************************** */
26
/*                    */
27
/*      VI Emulation Mode         */
28
/*                    */
29
/* **************************************************************** */
30
#include "rlconf.h"
31
 
32
#if defined (VI_MODE)
33
 
34
#if defined (HAVE_CONFIG_H)
35
#  include <config.h>
36
#endif
37
 
38
#include <sys/types.h>
39
 
40
#if defined (HAVE_STDLIB_H)
41
#  include <stdlib.h>
42
#else
43
#  include "ansi_stdlib.h"
44
#endif /* HAVE_STDLIB_H */
45
 
46
#if defined (HAVE_UNISTD_H)
47
#  include <unistd.h>
48
#endif
49
 
50
#include <stdio.h>
51
 
52
/* Some standard library routines. */
53
#include "rldefs.h"
54
#include "rlmbutil.h"
55
 
56
#include "readline.h"
57
#include "history.h"
58
 
59
#include "rlprivate.h"
60
#include "xmalloc.h"
61
 
62
#ifndef member
63
#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
64
#endif
65
 
66
int _rl_vi_last_command = 'i';  /* default `.' puts you in insert mode */
67
 
68
/* Non-zero means enter insertion mode. */
69
static int _rl_vi_doing_insert;
70
 
71
/* Command keys which do movement for xxx_to commands. */
72
static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|";
73
 
74
/* Keymap used for vi replace characters.  Created dynamically since
75
   rarely used. */
76
static Keymap vi_replace_map;
77
 
78
/* The number of characters inserted in the last replace operation. */
79
static int vi_replace_count;
80
 
81
/* If non-zero, we have text inserted after a c[motion] command that put
82
   us implicitly into insert mode.  Some people want this text to be
83
   attached to the command so that it is `redoable' with `.'. */
84
static int vi_continued_command;
85
static char *vi_insert_buffer;
86
static int vi_insert_buffer_size;
87
 
88
static int _rl_vi_last_repeat = 1;
89
static int _rl_vi_last_arg_sign = 1;
90
static int _rl_vi_last_motion;
91
#if defined (HANDLE_MULTIBYTE)
92
static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
93
static int _rl_vi_last_search_mblen;
94
#else
95
static int _rl_vi_last_search_char;
96
#endif
97
static int _rl_vi_last_replacement;
98
 
99
static int _rl_vi_last_key_before_insert;
100
 
101
static int vi_redoing;
102
 
103
/* Text modification commands.  These are the `redoable' commands. */
104
static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
105
 
106
/* Arrays for the saved marks. */
107
static int vi_mark_chars['z' - 'a' + 1];
108
 
109
static void _rl_vi_stuff_insert PARAMS((int));
110
static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
111
 
112
static void _rl_vi_backup PARAMS((void));
113
 
114
static int _rl_vi_arg_dispatch PARAMS((int));
115
static int rl_digit_loop1 PARAMS((void));
116
 
117
static int _rl_vi_set_mark PARAMS((void));
118
static int _rl_vi_goto_mark PARAMS((void));
119
 
120
static void _rl_vi_append_forward PARAMS((int));
121
 
122
static int _rl_vi_callback_getchar PARAMS((char *, int));
123
 
124
#if defined (READLINE_CALLBACKS)
125
static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *));
126
static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *));
127
static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *));
128
static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
129
#endif
130
 
131
void
132
_rl_vi_initialize_line ()
133
{
134
  register int i;
135
 
136
  for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
137
    vi_mark_chars[i] = -1;
138
 
139
  RL_UNSETSTATE(RL_STATE_VICMDONCE);
140
}
141
 
142
void
143
_rl_vi_reset_last ()
144
{
145
  _rl_vi_last_command = 'i';
146
  _rl_vi_last_repeat = 1;
147
  _rl_vi_last_arg_sign = 1;
148
  _rl_vi_last_motion = 0;
149
}
150
 
151
void
152
_rl_vi_set_last (key, repeat, sign)
153
     int key, repeat, sign;
154
{
155
  _rl_vi_last_command = key;
156
  _rl_vi_last_repeat = repeat;
157
  _rl_vi_last_arg_sign = sign;
158
}
159
 
160
/* A convenience function that calls _rl_vi_set_last to save the last command
161
   information and enters insertion mode. */
162
void
163
rl_vi_start_inserting (key, repeat, sign)
164
     int key, repeat, sign;
165
{
166
  _rl_vi_set_last (key, repeat, sign);
167
  rl_vi_insertion_mode (1, key);
168
}
169
 
170
/* Is the command C a VI mode text modification command? */
171
int
172
_rl_vi_textmod_command (c)
173
     int c;
174
{
175
  return (member (c, vi_textmod));
176
}
177
 
178
static void
179
_rl_vi_stuff_insert (count)
180
     int count;
181
{
182
  rl_begin_undo_group ();
183
  while (count--)
184
    rl_insert_text (vi_insert_buffer);
185
  rl_end_undo_group ();
186
}
187
 
188
/* Bound to `.'.  Called from command mode, so we know that we have to
189
   redo a text modification command.  The default for _rl_vi_last_command
190
   puts you back into insert mode. */
191
int
192
rl_vi_redo (count, c)
193
     int count, c;
194
{
195
  int r;
196
 
197
  if (!rl_explicit_arg)
198
    {
199
      rl_numeric_arg = _rl_vi_last_repeat;
200
      rl_arg_sign = _rl_vi_last_arg_sign;
201
    }
202
 
203
  r = 0;
204
  vi_redoing = 1;
205
  /* If we're redoing an insert with `i', stuff in the inserted text
206
     and do not go into insertion mode. */
207
  if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
208
    {
209
      _rl_vi_stuff_insert (count);
210
      /* And back up point over the last character inserted. */
211
      if (rl_point > 0)
212
  _rl_vi_backup ();
213
    }
214
  /* Ditto for redoing an insert with `a', but move forward a character first
215
     like the `a' command does. */
216
  else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
217
    {
218
      _rl_vi_append_forward ('a');
219
      _rl_vi_stuff_insert (count);
220
      if (rl_point > 0)
221
  _rl_vi_backup ();
222
    }
223
  else
224
    r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
225
  vi_redoing = 0;
226
 
227
  return (r);
228
}
229
 
230
/* A placeholder for further expansion. */
231
int
232
rl_vi_undo (count, key)
233
     int count, key;
234
{
235
  return (rl_undo_command (count, key));
236
}
237
 
238
/* Yank the nth arg from the previous line into this line at point. */
239
int
240
rl_vi_yank_arg (count, key)
241
     int count, key;
242
{
243
  /* Readline thinks that the first word on a line is the 0th, while vi
244
     thinks the first word on a line is the 1st.  Compensate. */
245
  if (rl_explicit_arg)
246
    rl_yank_nth_arg (count - 1, 0);
247
  else
248
    rl_yank_nth_arg ('$', 0);
249
 
250
  return (0);
251
}
252
 
253
/* With an argument, move back that many history lines, else move to the
254
   beginning of history. */
255
int
256
rl_vi_fetch_history (count, c)
257
     int count, c;
258
{
259
  int wanted;
260
 
261
  /* Giving an argument of n means we want the nth command in the history
262
     file.  The command number is interpreted the same way that the bash
263
     `history' command does it -- that is, giving an argument count of 450
264
     to this command would get the command listed as number 450 in the
265
     output of `history'. */
266
  if (rl_explicit_arg)
267
    {
268
      wanted = history_base + where_history () - count;
269
      if (wanted <= 0)
270
        rl_beginning_of_history (0, 0);
271
      else
272
        rl_get_previous_history (wanted, c);
273
    }
274
  else
275
    rl_beginning_of_history (count, 0);
276
  return (0);
277
}
278
 
279
/* Search again for the last thing searched for. */
280
int
281
rl_vi_search_again (count, key)
282
     int count, key;
283
{
284
  switch (key)
285
    {
286
    case 'n':
287
      rl_noninc_reverse_search_again (count, key);
288
      break;
289
 
290
    case 'N':
291
      rl_noninc_forward_search_again (count, key);
292
      break;
293
    }
294
  return (0);
295
}
296
 
297
/* Do a vi style search. */
298
int
299
rl_vi_search (count, key)
300
     int count, key;
301
{
302
  switch (key)
303
    {
304
    case '?':
305
      _rl_free_saved_history_line ();
306
      rl_noninc_forward_search (count, key);
307
      break;
308
 
309
    case '/':
310
      _rl_free_saved_history_line ();
311
      rl_noninc_reverse_search (count, key);
312
      break;
313
 
314
    default:
315
      rl_ding ();
316
      break;
317
    }
318
  return (0);
319
}
320
 
321
/* Completion, from vi's point of view. */
322
int
323
rl_vi_complete (ignore, key)
324
     int ignore, key;
325
{
326
  if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
327
    {
328
      if (!whitespace (rl_line_buffer[rl_point + 1]))
329
  rl_vi_end_word (1, 'E');
330
      rl_point++;
331
    }
332
 
333
  if (key == '*')
334
    rl_complete_internal ('*'); /* Expansion and replacement. */
335
  else if (key == '=')
336
    rl_complete_internal ('?'); /* List possible completions. */
337
  else if (key == '\\')
338
    rl_complete_internal (TAB); /* Standard Readline completion. */
339
  else
340
    rl_complete (0, key);
341
 
342
  if (key == '*' || key == '\\')
343
    rl_vi_start_inserting (key, 1, rl_arg_sign);
344
 
345
  return (0);
346
}
347
 
348
/* Tilde expansion for vi mode. */
349
int
350
rl_vi_tilde_expand (ignore, key)
351
     int ignore, key;
352
{
353
  rl_tilde_expand (0, key);
354
  rl_vi_start_inserting (key, 1, rl_arg_sign);
355
  return (0);
356
}
357
 
358
/* Previous word in vi mode. */
359
int
360
rl_vi_prev_word (count, key)
361
     int count, key;
362
{
363
  if (count < 0)
364
    return (rl_vi_next_word (-count, key));
365
 
366
  if (rl_point == 0)
367
    {
368
      rl_ding ();
369
      return (0);
370
    }
371
 
372
  if (_rl_uppercase_p (key))
373
    rl_vi_bWord (count, key);
374
  else
375
    rl_vi_bword (count, key);
376
 
377
  return (0);
378
}
379
 
380
/* Next word in vi mode. */
381
int
382
rl_vi_next_word (count, key)
383
     int count, key;
384
{
385
  if (count < 0)
386
    return (rl_vi_prev_word (-count, key));
387
 
388
  if (rl_point >= (rl_end - 1))
389
    {
390
      rl_ding ();
391
      return (0);
392
    }
393
 
394
  if (_rl_uppercase_p (key))
395
    rl_vi_fWord (count, key);
396
  else
397
    rl_vi_fword (count, key);
398
  return (0);
399
}
400
 
401
/* Move to the end of the ?next? word. */
402
int
403
rl_vi_end_word (count, key)
404
     int count, key;
405
{
406
  if (count < 0)
407
    {
408
      rl_ding ();
409
      return -1;
410
    }
411
 
412
  if (_rl_uppercase_p (key))
413
    rl_vi_eWord (count, key);
414
  else
415
    rl_vi_eword (count, key);
416
  return (0);
417
}
418
 
419
/* Move forward a word the way that 'W' does. */
420
int
421
rl_vi_fWord (count, ignore)
422
     int count, ignore;
423
{
424
  while (count-- && rl_point < (rl_end - 1))
425
    {
426
      /* Skip until whitespace. */
427
      while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
428
  rl_point++;
429
 
430
      /* Now skip whitespace. */
431
      while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
432
  rl_point++;
433
    }
434
  return (0);
435
}
436
 
437
int
438
rl_vi_bWord (count, ignore)
439
     int count, ignore;
440
{
441
  while (count-- && rl_point > 0)
442
    {
443
      /* If we are at the start of a word, move back to whitespace so
444
   we will go back to the start of the previous word. */
445
      if (!whitespace (rl_line_buffer[rl_point]) &&
446
    whitespace (rl_line_buffer[rl_point - 1]))
447
  rl_point--;
448
 
449
      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
450
  rl_point--;
451
 
452
      if (rl_point > 0)
453
  {
454
    while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
455
    rl_point++;
456
  }
457
    }
458
  return (0);
459
}
460
 
461
int
462
rl_vi_eWord (count, ignore)
463
     int count, ignore;
464
{
465
  while (count-- && rl_point < (rl_end - 1))
466
    {
467
      if (!whitespace (rl_line_buffer[rl_point]))
468
  rl_point++;
469
 
470
      /* Move to the next non-whitespace character (to the start of the
471
   next word). */
472
      while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
473
  rl_point++;
474
 
475
      if (rl_point && rl_point < rl_end)
476
  {
477
    /* Skip whitespace. */
478
    while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
479
      rl_point++;
480
 
481
    /* Skip until whitespace. */
482
    while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
483
      rl_point++;
484
 
485
    /* Move back to the last character of the word. */
486
    rl_point--;
487
  }
488
    }
489
  return (0);
490
}
491
 
492
int
493
rl_vi_fword (count, ignore)
494
     int count, ignore;
495
{
496
  while (count-- && rl_point < (rl_end - 1))
497
    {
498
      /* Move to white space (really non-identifer). */
499
      if (_rl_isident (rl_line_buffer[rl_point]))
500
  {
501
    while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
502
      rl_point++;
503
  }
504
      else /* if (!whitespace (rl_line_buffer[rl_point])) */
505
  {
506
    while (!_rl_isident (rl_line_buffer[rl_point]) &&
507
     !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
508
      rl_point++;
509
  }
510
 
511
      /* Move past whitespace. */
512
      while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
513
  rl_point++;
514
    }
515
  return (0);
516
}
517
 
518
int
519
rl_vi_bword (count, ignore)
520
     int count, ignore;
521
{
522
  while (count-- && rl_point > 0)
523
    {
524
      int last_is_ident;
525
 
526
      /* If we are at the start of a word, move back to whitespace
527
   so we will go back to the start of the previous word. */
528
      if (!whitespace (rl_line_buffer[rl_point]) &&
529
    whitespace (rl_line_buffer[rl_point - 1]))
530
  rl_point--;
531
 
532
      /* If this character and the previous character are `opposite', move
533
   back so we don't get messed up by the rl_point++ down there in
534
   the while loop.  Without this code, words like `l;' screw up the
535
   function. */
536
      last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]);
537
      if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
538
    (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident))
539
  rl_point--;
540
 
541
      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
542
  rl_point--;
543
 
544
      if (rl_point > 0)
545
  {
546
    if (_rl_isident (rl_line_buffer[rl_point]))
547
      while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point]));
548
    else
549
      while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
550
       !whitespace (rl_line_buffer[rl_point]));
551
    rl_point++;
552
  }
553
    }
554
  return (0);
555
}
556
 
557
int
558
rl_vi_eword (count, ignore)
559
     int count, ignore;
560
{
561
  while (count-- && rl_point < rl_end - 1)
562
    {
563
      if (!whitespace (rl_line_buffer[rl_point]))
564
  rl_point++;
565
 
566
      while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
567
  rl_point++;
568
 
569
      if (rl_point < rl_end)
570
  {
571
    if (_rl_isident (rl_line_buffer[rl_point]))
572
      while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
573
    else
574
      while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
575
       && !whitespace (rl_line_buffer[rl_point]));
576
  }
577
      rl_point--;
578
    }
579
  return (0);
580
}
581
 
582
int
583
rl_vi_insert_beg (count, key)
584
     int count, key;
585
{
586
  rl_beg_of_line (1, key);
587
  rl_vi_insertion_mode (1, key);
588
  return (0);
589
}
590
 
591
static void
592
_rl_vi_append_forward (key)
593
     int key;
594
{
595
  int point;
596
 
597
  if (rl_point < rl_end)
598
    {
599
      if (MB_CUR_MAX == 1 || rl_byte_oriented)
600
  rl_point++;
601
      else
602
        {
603
          point = rl_point;
604
          rl_forward_char (1, key);
605
          if (point == rl_point)
606
            rl_point = rl_end;
607
        }
608
    }
609
}
610
 
611
int
612
rl_vi_append_mode (count, key)
613
     int count, key;
614
{
615
  _rl_vi_append_forward (key);
616
  rl_vi_start_inserting (key, 1, rl_arg_sign);
617
  return (0);
618
}
619
 
620
int
621
rl_vi_append_eol (count, key)
622
     int count, key;
623
{
624
  rl_end_of_line (1, key);
625
  rl_vi_append_mode (1, key);
626
  return (0);
627
}
628
 
629
/* What to do in the case of C-d. */
630
int
631
rl_vi_eof_maybe (count, c)
632
     int count, c;
633
{
634
  return (rl_newline (1, '\n'));
635
}
636
 
637
/* Insertion mode stuff. */
638
 
639
/* Switching from one mode to the other really just involves
640
   switching keymaps. */
641
int
642
rl_vi_insertion_mode (count, key)
643
     int count, key;
644
{
645
  _rl_keymap = vi_insertion_keymap;
646
  _rl_vi_last_key_before_insert = key;
647
  return (0);
648
}
649
 
650
static void
651
_rl_vi_save_insert (up)
652
      UNDO_LIST *up;
653
{
654
  int len, start, end;
655
 
656
  if (up == 0 || up->what != UNDO_INSERT)
657
    {
658
      if (vi_insert_buffer_size >= 1)
659
  vi_insert_buffer[0] = '\0';
660
      return;
661
    }
662
 
663
  start = up->start;
664
  end = up->end;
665
  len = end - start + 1;
666
  if (len >= vi_insert_buffer_size)
667
    {
668
      vi_insert_buffer_size += (len + 32) - (len % 32);
669
      vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
670
    }
671
  strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
672
  vi_insert_buffer[len-1] = '\0';
673
}
674
 
675
void
676
_rl_vi_done_inserting ()
677
{
678
  if (_rl_vi_doing_insert)
679
    {
680
      /* The `C', `s', and `S' commands set this. */
681
      rl_end_undo_group ();
682
      /* Now, the text between rl_undo_list->next->start and
683
   rl_undo_list->next->end is what was inserted while in insert
684
   mode.  It gets copied to VI_INSERT_BUFFER because it depends
685
   on absolute indices into the line which may change (though they
686
   probably will not). */
687
      _rl_vi_doing_insert = 0;
688
      _rl_vi_save_insert (rl_undo_list->next);
689
      vi_continued_command = 1;
690
    }
691
  else
692
    {
693
      if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list)
694
        _rl_vi_save_insert (rl_undo_list);
695
      /* XXX - Other keys probably need to be checked. */
696
      else if (_rl_vi_last_key_before_insert == 'C')
697
  rl_end_undo_group ();
698
      while (_rl_undo_group_level > 0)
699
  rl_end_undo_group ();
700
      vi_continued_command = 0;
701
    }
702
}
703
 
704
int
705
rl_vi_movement_mode (count, key)
706
     int count, key;
707
{
708
  if (rl_point > 0)
709
    rl_backward_char (1, key);
710
 
711
  _rl_keymap = vi_movement_keymap;
712
  _rl_vi_done_inserting ();
713
 
714
  /* This is how POSIX.2 says `U' should behave -- everything up until the
715
     first time you go into command mode should not be undone. */
716
  if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
717
    rl_free_undo_list ();
718
 
719
  RL_SETSTATE (RL_STATE_VICMDONCE);
720
  return (0);
721
}
722
 
723
int
724
rl_vi_arg_digit (count, c)
725
     int count, c;
726
{
727
  if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
728
    return (rl_beg_of_line (1, c));
729
  else
730
    return (rl_digit_argument (count, c));
731
}
732
 
733
/* Change the case of the next COUNT characters. */
734
#if defined (HANDLE_MULTIBYTE)
735
static int
736
_rl_vi_change_mbchar_case (count)
737
     int count;
738
{
739
  wchar_t wc;
740
  char mb[MB_LEN_MAX+1];
741
  int mlen, p;
742
  mbstate_t ps;
743
 
744
  memset (&ps, 0, sizeof (mbstate_t));
745
  if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
746
    count--;
747
  while (count-- && rl_point < rl_end)
748
    {
749
      mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
750
      if (iswupper (wc))
751
  wc = towlower (wc);
752
      else if (iswlower (wc))
753
  wc = towupper (wc);
754
      else
755
  {
756
    /* Just skip over chars neither upper nor lower case */
757
    rl_forward_char (1, 0);
758
    continue;
759
  }
760
 
761
      /* Vi is kind of strange here. */
762
      if (wc)
763
  {
764
    p = rl_point;
765
    mlen = wcrtomb (mb, wc, &ps);
766
    if (mlen >= 0)
767
      mb[mlen] = '\0';
768
    rl_begin_undo_group ();
769
    rl_vi_delete (1, 0);
770
    if (rl_point < p) /* Did we retreat at EOL? */
771
      rl_point++; /* XXX - should we advance more than 1 for mbchar? */
772
    rl_insert_text (mb);
773
    rl_end_undo_group ();
774
    rl_vi_check ();
775
  }
776
      else
777
        rl_forward_char (1, 0);
778
    }
779
 
780
  return 0;
781
}
782
#endif
783
 
784
int
785
rl_vi_change_case (count, ignore)
786
     int count, ignore;
787
{
788
  int c, p;
789
 
790
  /* Don't try this on an empty line. */
791
  if (rl_point >= rl_end)
792
    return (0);
793
 
794
  c = 0;
795
#if defined (HANDLE_MULTIBYTE)
796
  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
797
    return (_rl_vi_change_mbchar_case (count));
798
#endif
799
 
800
  while (count-- && rl_point < rl_end)
801
    {
802
      if (_rl_uppercase_p (rl_line_buffer[rl_point]))
803
  c = _rl_to_lower (rl_line_buffer[rl_point]);
804
      else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
805
  c = _rl_to_upper (rl_line_buffer[rl_point]);
806
      else
807
  {
808
    /* Just skip over characters neither upper nor lower case. */
809
    rl_forward_char (1, c);
810
    continue;
811
  }
812
 
813
      /* Vi is kind of strange here. */
814
      if (c)
815
  {
816
    p = rl_point;
817
    rl_begin_undo_group ();
818
    rl_vi_delete (1, c);
819
    if (rl_point < p) /* Did we retreat at EOL? */
820
      rl_point++;
821
    _rl_insert_char (1, c);
822
    rl_end_undo_group ();
823
    rl_vi_check ();
824
        }
825
      else
826
  rl_forward_char (1, c);
827
    }
828
  return (0);
829
}
830
 
831
int
832
rl_vi_put (count, key)
833
     int count, key;
834
{
835
  if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
836
    rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
837
 
838
  while (count--)
839
    rl_yank (1, key);
840
 
841
  rl_backward_char (1, key);
842
  return (0);
843
}
844
 
845
static void
846
_rl_vi_backup ()
847
{
848
  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
849
    rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
850
  else
851
    rl_point--;
852
}
853
 
854
int
855
rl_vi_check ()
856
{
857
  if (rl_point && rl_point == rl_end)
858
    {
859
      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
860
  rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
861
      else
862
        rl_point--;
863
    }
864
  return (0);
865
}
866
 
867
int
868
rl_vi_column (count, key)
869
     int count, key;
870
{
871
  if (count > rl_end)
872
    rl_end_of_line (1, key);
873
  else
874
    rl_point = count - 1;
875
  return (0);
876
}
877
 
878
int
879
rl_vi_domove (key, nextkey)
880
     int key, *nextkey;
881
{
882
  int c, save;
883
  int old_end;
884
 
885
  rl_mark = rl_point;
886
  RL_SETSTATE(RL_STATE_MOREINPUT);
887
  c = rl_read_key ();
888
  RL_UNSETSTATE(RL_STATE_MOREINPUT);
889
  *nextkey = c;
890
 
891
  if (!member (c, vi_motion))
892
    {
893
      if (_rl_digit_p (c))
894
  {
895
    save = rl_numeric_arg;
896
    rl_numeric_arg = _rl_digit_value (c);
897
    rl_explicit_arg = 1;
898
    RL_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION);
899
    rl_digit_loop1 ();
900
    RL_UNSETSTATE (RL_STATE_VIMOTION);
901
    rl_numeric_arg *= save;
902
    RL_SETSTATE(RL_STATE_MOREINPUT);
903
    c = rl_read_key (); /* real command */
904
    RL_UNSETSTATE(RL_STATE_MOREINPUT);
905
    *nextkey = c;
906
  }
907
      else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
908
  {
909
    rl_mark = rl_end;
910
    rl_beg_of_line (1, c);
911
    _rl_vi_last_motion = c;
912
    return (0);
913
  }
914
      else
915
  return (-1);
916
    }
917
 
918
  _rl_vi_last_motion = c;
919
 
920
  /* Append a blank character temporarily so that the motion routines
921
     work right at the end of the line. */
922
  old_end = rl_end;
923
  rl_line_buffer[rl_end++] = ' ';
924
  rl_line_buffer[rl_end] = '\0';
925
 
926
  _rl_dispatch (c, _rl_keymap);
927
 
928
  /* Remove the blank that we added. */
929
  rl_end = old_end;
930
  rl_line_buffer[rl_end] = '\0';
931
  if (rl_point > rl_end)
932
    rl_point = rl_end;
933
 
934
  /* No change in position means the command failed. */
935
  if (rl_mark == rl_point)
936
    return (-1);
937
 
938
  /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
939
     word.  If we are not at the end of the line, and we are on a
940
     non-whitespace character, move back one (presumably to whitespace). */
941
  if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
942
      !whitespace (rl_line_buffer[rl_point]))
943
    rl_point--;
944
 
945
  /* If cw or cW, back up to the end of a word, so the behaviour of ce
946
     or cE is the actual result.  Brute-force, no subtlety. */
947
  if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
948
    {
949
      /* Don't move farther back than where we started. */
950
      while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
951
  rl_point--;
952
 
953
      /* Posix.2 says that if cw or cW moves the cursor towards the end of
954
   the line, the character under the cursor should be deleted. */
955
      if (rl_point == rl_mark)
956
        rl_point++;
957
      else
958
  {
959
    /* Move past the end of the word so that the kill doesn't
960
       remove the last letter of the previous word.  Only do this
961
       if we are not at the end of the line. */
962
    if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
963
      rl_point++;
964
  }
965
    }
966
 
967
  if (rl_mark < rl_point)
968
    SWAP (rl_point, rl_mark);
969
 
970
  return (0);
971
}
972
 
973
/* Process C as part of the current numeric argument.  Return -1 if the
974
   argument should be aborted, 0 if we should not read any more chars, and
975
   1 if we should continue to read chars. */
976
static int
977
_rl_vi_arg_dispatch (c)
978
     int c;
979
{
980
  int key;
981
 
982
  key = c;
983
  if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
984
    {
985
      rl_numeric_arg *= 4;
986
      return 1;
987
    }
988
 
989
  c = UNMETA (c);
990
 
991
  if (_rl_digit_p (c))
992
    {
993
      if (rl_explicit_arg)
994
  rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
995
      else
996
  rl_numeric_arg = _rl_digit_value (c);
997
      rl_explicit_arg = 1;
998
      return 1;
999
    }
1000
  else
1001
    {
1002
      rl_clear_message ();
1003
      rl_stuff_char (key);
1004
      return 0;
1005
    }
1006
}
1007
 
1008
/* A simplified loop for vi. Don't dispatch key at end.
1009
   Don't recognize minus sign?
1010
   Should this do rl_save_prompt/rl_restore_prompt? */
1011
static int
1012
rl_digit_loop1 ()
1013
{
1014
  int c, r;
1015
 
1016
  while (1)
1017
    {
1018
      if (_rl_arg_overflow ())
1019
  return 1;
1020
 
1021
      c = _rl_arg_getchar ();
1022
 
1023
      r = _rl_vi_arg_dispatch (c);
1024
      if (r <= 0)
1025
  break;
1026
    }
1027
 
1028
  RL_UNSETSTATE(RL_STATE_NUMERICARG);
1029
  return (0);
1030
}
1031
 
1032
int
1033
rl_vi_delete_to (count, key)
1034
     int count, key;
1035
{
1036
  int c;
1037
 
1038
  if (_rl_uppercase_p (key))
1039
    rl_stuff_char ('$');
1040
  else if (vi_redoing)
1041
    rl_stuff_char (_rl_vi_last_motion);
1042
 
1043
  if (rl_vi_domove (key, &c))
1044
    {
1045
      rl_ding ();
1046
      return -1;
1047
    }
1048
 
1049
  /* These are the motion commands that do not require adjusting the
1050
     mark. */
1051
  if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
1052
    rl_mark++;
1053
 
1054
  rl_kill_text (rl_point, rl_mark);
1055
  return (0);
1056
}
1057
 
1058
int
1059
rl_vi_change_to (count, key)
1060
     int count, key;
1061
{
1062
  int c, start_pos;
1063
 
1064
  if (_rl_uppercase_p (key))
1065
    rl_stuff_char ('$');
1066
  else if (vi_redoing)
1067
    rl_stuff_char (_rl_vi_last_motion);
1068
 
1069
  start_pos = rl_point;
1070
 
1071
  if (rl_vi_domove (key, &c))
1072
    {
1073
      rl_ding ();
1074
      return -1;
1075
    }
1076
 
1077
  /* These are the motion commands that do not require adjusting the
1078
     mark.  c[wW] are handled by special-case code in rl_vi_domove(),
1079
     and already leave the mark at the correct location. */
1080
  if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
1081
    rl_mark++;
1082
 
1083
  /* The cursor never moves with c[wW]. */
1084
  if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
1085
    rl_point = start_pos;
1086
 
1087
  if (vi_redoing)
1088
    {
1089
      if (vi_insert_buffer && *vi_insert_buffer)
1090
  rl_begin_undo_group ();
1091
      rl_delete_text (rl_point, rl_mark);
1092
      if (vi_insert_buffer && *vi_insert_buffer)
1093
  {
1094
    rl_insert_text (vi_insert_buffer);
1095
    rl_end_undo_group ();
1096
  }
1097
    }
1098
  else
1099
    {
1100
      rl_begin_undo_group ();   /* to make the `u' command work */
1101
      rl_kill_text (rl_point, rl_mark);
1102
      /* `C' does not save the text inserted for undoing or redoing. */
1103
      if (_rl_uppercase_p (key) == 0)
1104
        _rl_vi_doing_insert = 1;
1105
      rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign);
1106
    }
1107
 
1108
  return (0);
1109
}
1110
 
1111
int
1112
rl_vi_yank_to (count, key)
1113
     int count, key;
1114
{
1115
  int c, save;
1116
 
1117
  save = rl_point;
1118
  if (_rl_uppercase_p (key))
1119
    rl_stuff_char ('$');
1120
 
1121
  if (rl_vi_domove (key, &c))
1122
    {
1123
      rl_ding ();
1124
      return -1;
1125
    }
1126
 
1127
  /* These are the motion commands that do not require adjusting the
1128
     mark. */
1129
  if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
1130
    rl_mark++;
1131
 
1132
  rl_begin_undo_group ();
1133
  rl_kill_text (rl_point, rl_mark);
1134
  rl_end_undo_group ();
1135
  rl_do_undo ();
1136
  rl_point = save;
1137
 
1138
  return (0);
1139
}
1140
 
1141
int
1142
rl_vi_rubout (count, key)
1143
     int count, key;
1144
{
1145
  int opoint;
1146
 
1147
  if (count < 0)
1148
    return (rl_vi_delete (-count, key));
1149
 
1150
  if (rl_point == 0)
1151
    {
1152
      rl_ding ();
1153
      return -1;
1154
    }
1155
 
1156
  opoint = rl_point;
1157
  if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1158
    rl_backward_char (count, key);
1159
  else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1160
    rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1161
  else
1162
    rl_point -= count;
1163
 
1164
  if (rl_point < 0)
1165
    rl_point = 0;
1166
 
1167
  rl_kill_text (rl_point, opoint);
1168
 
1169
  return (0);
1170
}
1171
 
1172
int
1173
rl_vi_delete (count, key)
1174
     int count, key;
1175
{
1176
  int end;
1177
 
1178
  if (count < 0)
1179
    return (rl_vi_rubout (-count, key));
1180
 
1181
  if (rl_end == 0)
1182
    {
1183
      rl_ding ();
1184
      return -1;
1185
    }
1186
 
1187
  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1188
    end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1189
  else
1190
    end = rl_point + count;
1191
 
1192
  if (end >= rl_end)
1193
    end = rl_end;
1194
 
1195
  rl_kill_text (rl_point, end);
1196
 
1197
  if (rl_point > 0 && rl_point == rl_end)
1198
    rl_backward_char (1, key);
1199
 
1200
  return (0);
1201
}
1202
 
1203
int
1204
rl_vi_back_to_indent (count, key)
1205
     int count, key;
1206
{
1207
  rl_beg_of_line (1, key);
1208
  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1209
    rl_point++;
1210
  return (0);
1211
}
1212
 
1213
int
1214
rl_vi_first_print (count, key)
1215
     int count, key;
1216
{
1217
  return (rl_vi_back_to_indent (1, key));
1218
}
1219
 
1220
static int _rl_cs_dir, _rl_cs_orig_dir;
1221
 
1222
#if defined (READLINE_CALLBACKS)
1223
static int
1224
_rl_vi_callback_char_search (data)
1225
     _rl_callback_generic_arg *data;
1226
{
1227
#if defined (HANDLE_MULTIBYTE)
1228
  _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1229
#else
1230
  RL_SETSTATE(RL_STATE_MOREINPUT);
1231
  _rl_vi_last_search_char = rl_read_key ();
1232
  RL_UNSETSTATE(RL_STATE_MOREINPUT);
1233
#endif
1234
 
1235
  _rl_callback_func = 0;
1236
  _rl_want_redisplay = 1;
1237
 
1238
#if defined (HANDLE_MULTIBYTE)
1239
  return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1240
#else
1241
  return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1242
#endif
1243
}
1244
#endif
1245
 
1246
int
1247
rl_vi_char_search (count, key)
1248
     int count, key;
1249
{
1250
#if defined (HANDLE_MULTIBYTE)
1251
  static char *target;
1252
  static int tlen;
1253
#else
1254
  static char target;
1255
#endif
1256
 
1257
  if (key == ';' || key == ',')
1258
    _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1259
  else
1260
    {
1261
      switch (key)
1262
        {
1263
        case 't':
1264
          _rl_cs_orig_dir = _rl_cs_dir = FTO;
1265
          break;
1266
 
1267
        case 'T':
1268
          _rl_cs_orig_dir = _rl_cs_dir = BTO;
1269
          break;
1270
 
1271
        case 'f':
1272
          _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1273
          break;
1274
 
1275
        case 'F':
1276
          _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1277
          break;
1278
        }
1279
 
1280
      if (vi_redoing)
1281
  {
1282
    /* set target and tlen below */
1283
  }
1284
#if defined (READLINE_CALLBACKS)
1285
      else if (RL_ISSTATE (RL_STATE_CALLBACK))
1286
        {
1287
          _rl_callback_data = _rl_callback_data_alloc (count);
1288
          _rl_callback_data->i1 = _rl_cs_dir;
1289
          _rl_callback_func = _rl_vi_callback_char_search;
1290
          return (0);
1291
        }
1292
#endif
1293
      else
1294
  {
1295
#if defined (HANDLE_MULTIBYTE)
1296
    _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1297
#else
1298
    RL_SETSTATE(RL_STATE_MOREINPUT);
1299
    _rl_vi_last_search_char = rl_read_key ();
1300
    RL_UNSETSTATE(RL_STATE_MOREINPUT);
1301
#endif
1302
  }
1303
    }
1304
 
1305
#if defined (HANDLE_MULTIBYTE)
1306
  target = _rl_vi_last_search_mbchar;
1307
  tlen = _rl_vi_last_search_mblen;
1308
#else
1309
  target = _rl_vi_last_search_char;
1310
#endif
1311
 
1312
#if defined (HANDLE_MULTIBYTE)
1313
  return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
1314
#else
1315
  return (_rl_char_search_internal (count, _rl_cs_dir, target));
1316
#endif
1317
}
1318
 
1319
/* Match brackets */
1320
int
1321
rl_vi_match (ignore, key)
1322
     int ignore, key;
1323
{
1324
  int count = 1, brack, pos, tmp, pre;
1325
 
1326
  pos = rl_point;
1327
  if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1328
    {
1329
      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1330
  {
1331
    while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1332
      {
1333
        pre = rl_point;
1334
        rl_forward_char (1, key);
1335
        if (pre == rl_point)
1336
          break;
1337
      }
1338
  }
1339
      else
1340
  while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1341
    rl_point < rl_end - 1)
1342
    rl_forward_char (1, key);
1343
 
1344
      if (brack <= 0)
1345
  {
1346
    rl_point = pos;
1347
    rl_ding ();
1348
    return -1;
1349
  }
1350
    }
1351
 
1352
  pos = rl_point;
1353
 
1354
  if (brack < 0)
1355
    {
1356
      while (count)
1357
  {
1358
    tmp = pos;
1359
    if (MB_CUR_MAX == 1 || rl_byte_oriented)
1360
      pos--;
1361
    else
1362
      {
1363
        pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1364
        if (tmp == pos)
1365
          pos--;
1366
      }
1367
    if (pos >= 0)
1368
      {
1369
        int b = rl_vi_bracktype (rl_line_buffer[pos]);
1370
        if (b == -brack)
1371
    count--;
1372
        else if (b == brack)
1373
    count++;
1374
      }
1375
    else
1376
      {
1377
        rl_ding ();
1378
        return -1;
1379
      }
1380
  }
1381
    }
1382
  else
1383
    {     /* brack > 0 */
1384
      while (count)
1385
  {
1386
    if (MB_CUR_MAX == 1 || rl_byte_oriented)
1387
      pos++;
1388
    else
1389
      pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1390
 
1391
    if (pos < rl_end)
1392
      {
1393
        int b = rl_vi_bracktype (rl_line_buffer[pos]);
1394
        if (b == -brack)
1395
    count--;
1396
        else if (b == brack)
1397
    count++;
1398
      }
1399
    else
1400
      {
1401
        rl_ding ();
1402
        return -1;
1403
      }
1404
  }
1405
    }
1406
  rl_point = pos;
1407
  return (0);
1408
}
1409
 
1410
int
1411
rl_vi_bracktype (c)
1412
     int c;
1413
{
1414
  switch (c)
1415
    {
1416
    case '(': return  1;
1417
    case ')': return -1;
1418
    case '[': return  2;
1419
    case ']': return -2;
1420
    case '{': return  3;
1421
    case '}': return -3;
1422
    default:  return  0;
1423
    }
1424
}
1425
 
1426
static int
1427
_rl_vi_change_char (count, c, mb)
1428
     int count, c;
1429
     char *mb;
1430
{
1431
  int p;
1432
 
1433
  if (c == '\033' || c == CTRL ('C'))
1434
    return -1;
1435
 
1436
  rl_begin_undo_group ();
1437
  while (count-- && rl_point < rl_end)
1438
    {
1439
      p = rl_point;
1440
      rl_vi_delete (1, c);
1441
      if (rl_point < p)   /* Did we retreat at EOL? */
1442
  rl_point++;
1443
#if defined (HANDLE_MULTIBYTE)
1444
      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1445
  rl_insert_text (mb);
1446
      else
1447
#endif
1448
  _rl_insert_char (1, c);
1449
    }
1450
 
1451
  /* The cursor shall be left on the last character changed. */
1452
  rl_backward_char (1, c);
1453
 
1454
  rl_end_undo_group ();
1455
 
1456
  return (0);
1457
}
1458
 
1459
static int
1460
_rl_vi_callback_getchar (mb, mlen)
1461
     char *mb;
1462
     int mlen;
1463
{
1464
  int c;
1465
 
1466
  RL_SETSTATE(RL_STATE_MOREINPUT);
1467
  c = rl_read_key ();
1468
  RL_UNSETSTATE(RL_STATE_MOREINPUT);
1469
 
1470
#if defined (HANDLE_MULTIBYTE)
1471
  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1472
    c = _rl_read_mbstring (c, mb, mlen);
1473
#endif
1474
 
1475
  return c;
1476
}
1477
 
1478
#if defined (READLINE_CALLBACKS)
1479
static int
1480
_rl_vi_callback_change_char (data)
1481
     _rl_callback_generic_arg *data;
1482
{
1483
  int c;
1484
  char mb[MB_LEN_MAX];
1485
 
1486
  _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1487
 
1488
  _rl_callback_func = 0;
1489
  _rl_want_redisplay = 1;
1490
 
1491
  return (_rl_vi_change_char (data->count, c, mb));
1492
}
1493
#endif
1494
 
1495
int
1496
rl_vi_change_char (count, key)
1497
     int count, key;
1498
{
1499
  int c;
1500
  char mb[MB_LEN_MAX];
1501
 
1502
  if (vi_redoing)
1503
    {
1504
      c = _rl_vi_last_replacement;
1505
      mb[0] = c;
1506
      mb[1] = '\0';
1507
    }
1508
#if defined (READLINE_CALLBACKS)
1509
  else if (RL_ISSTATE (RL_STATE_CALLBACK))
1510
    {
1511
      _rl_callback_data = _rl_callback_data_alloc (count);
1512
      _rl_callback_func = _rl_vi_callback_change_char;
1513
      return (0);
1514
    }
1515
#endif
1516
  else
1517
    _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1518
 
1519
  return (_rl_vi_change_char (count, c, mb));
1520
}
1521
 
1522
int
1523
rl_vi_subst (count, key)
1524
     int count, key;
1525
{
1526
  /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1527
  if (vi_redoing == 0)
1528
    rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */
1529
 
1530
  return (rl_vi_change_to (count, 'c'));
1531
}
1532
 
1533
int
1534
rl_vi_overstrike (count, key)
1535
     int count, key;
1536
{
1537
  if (_rl_vi_doing_insert == 0)
1538
    {
1539
      _rl_vi_doing_insert = 1;
1540
      rl_begin_undo_group ();
1541
    }
1542
 
1543
  if (count > 0)
1544
    {
1545
      _rl_overwrite_char (count, key);
1546
      vi_replace_count += count;
1547
    }
1548
 
1549
  return (0);
1550
}
1551
 
1552
int
1553
rl_vi_overstrike_delete (count, key)
1554
     int count, key;
1555
{
1556
  int i, s;
1557
 
1558
  for (i = 0; i < count; i++)
1559
    {
1560
      if (vi_replace_count == 0)
1561
  {
1562
    rl_ding ();
1563
    break;
1564
  }
1565
      s = rl_point;
1566
 
1567
      if (rl_do_undo ())
1568
  vi_replace_count--;
1569
 
1570
      if (rl_point == s)
1571
  rl_backward_char (1, key);
1572
    }
1573
 
1574
  if (vi_replace_count == 0 && _rl_vi_doing_insert)
1575
    {
1576
      rl_end_undo_group ();
1577
      rl_do_undo ();
1578
      _rl_vi_doing_insert = 0;
1579
    }
1580
  return (0);
1581
}
1582
 
1583
int
1584
rl_vi_replace (count, key)
1585
     int count, key;
1586
{
1587
  int i;
1588
 
1589
  vi_replace_count = 0;
1590
 
1591
  if (!vi_replace_map)
1592
    {
1593
      vi_replace_map = rl_make_bare_keymap ();
1594
 
1595
      for (i = ' '; i < KEYMAP_SIZE; i++)
1596
  vi_replace_map[i].function = rl_vi_overstrike;
1597
 
1598
      vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1599
      vi_replace_map[ESC].function = rl_vi_movement_mode;
1600
      vi_replace_map[RETURN].function = rl_newline;
1601
      vi_replace_map[NEWLINE].function = rl_newline;
1602
 
1603
      /* If the normal vi insertion keymap has ^H bound to erase, do the
1604
         same here.  Probably should remove the assignment to RUBOUT up
1605
         there, but I don't think it will make a difference in real life. */
1606
      if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1607
    vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1608
  vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1609
 
1610
    }
1611
  _rl_keymap = vi_replace_map;
1612
  return (0);
1613
}
1614
 
1615
#if 0
1616
/* Try to complete the word we are standing on or the word that ends with
1617
   the previous character.  A space matches everything.  Word delimiters are
1618
   space and ;. */
1619
int
1620
rl_vi_possible_completions()
1621
{
1622
  int save_pos = rl_point;
1623
 
1624
  if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1625
    {
1626
      while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1627
       rl_line_buffer[rl_point] != ';')
1628
  rl_point++;
1629
    }
1630
  else if (rl_line_buffer[rl_point - 1] == ';')
1631
    {
1632
      rl_ding ();
1633
      return (0);
1634
    }
1635
 
1636
  rl_possible_completions ();
1637
  rl_point = save_pos;
1638
 
1639
  return (0);
1640
}
1641
#endif
1642
 
1643
/* Functions to save and restore marks. */
1644
static int
1645
_rl_vi_set_mark ()
1646
{
1647
  int ch;
1648
 
1649
  RL_SETSTATE(RL_STATE_MOREINPUT);
1650
  ch = rl_read_key ();
1651
  RL_UNSETSTATE(RL_STATE_MOREINPUT);
1652
 
1653
  if (ch < 'a' || ch > 'z')
1654
    {
1655
      rl_ding ();
1656
      return -1;
1657
    }
1658
  ch -= 'a';
1659
  vi_mark_chars[ch] = rl_point;
1660
  return 0;
1661
}
1662
 
1663
#if defined (READLINE_CALLBACKS)
1664
static int
1665
_rl_vi_callback_set_mark (data)
1666
     _rl_callback_generic_arg *data;
1667
{
1668
  _rl_callback_func = 0;
1669
  _rl_want_redisplay = 1;
1670
 
1671
  return (_rl_vi_set_mark ());
1672
}
1673
#endif
1674
 
1675
int
1676
rl_vi_set_mark (count, key)
1677
     int count, key;
1678
{
1679
#if defined (READLINE_CALLBACKS)
1680
  if (RL_ISSTATE (RL_STATE_CALLBACK))
1681
    {
1682
      _rl_callback_data = 0;
1683
      _rl_callback_func = _rl_vi_callback_set_mark;
1684
      return (0);
1685
    }
1686
#endif
1687
 
1688
  return (_rl_vi_set_mark ());
1689
}
1690
 
1691
static int
1692
_rl_vi_goto_mark ()
1693
{
1694
  int ch;
1695
 
1696
  RL_SETSTATE(RL_STATE_MOREINPUT);
1697
  ch = rl_read_key ();
1698
  RL_UNSETSTATE(RL_STATE_MOREINPUT);
1699
 
1700
  if (ch == '`')
1701
    {
1702
      rl_point = rl_mark;
1703
      return 0;
1704
    }
1705
  else if (ch < 'a' || ch > 'z')
1706
    {
1707
      rl_ding ();
1708
      return -1;
1709
    }
1710
 
1711
  ch -= 'a';
1712
  if (vi_mark_chars[ch] == -1)
1713
    {
1714
      rl_ding ();
1715
      return -1;
1716
    }
1717
  rl_point = vi_mark_chars[ch];
1718
  return 0;
1719
}
1720
 
1721
#if defined (READLINE_CALLBACKS)
1722
static int
1723
_rl_vi_callback_goto_mark (data)
1724
     _rl_callback_generic_arg *data;
1725
{
1726
  _rl_callback_func = 0;
1727
  _rl_want_redisplay = 1;
1728
 
1729
  return (_rl_vi_goto_mark ());
1730
}
1731
#endif
1732
 
1733
int
1734
rl_vi_goto_mark (count, key)
1735
     int count, key;
1736
{
1737
#if defined (READLINE_CALLBACKS)
1738
  if (RL_ISSTATE (RL_STATE_CALLBACK))
1739
    {
1740
      _rl_callback_data = 0;
1741
      _rl_callback_func = _rl_vi_callback_goto_mark;
1742
      return (0);
1743
    }
1744
#endif
1745
 
1746
  return (_rl_vi_goto_mark ());
1747
}
1748
#endif /* VI_MODE */