File Coverage

lib/Term/ReadLine/Perl5/readline.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             =head1 NAME
3              
4             Term::ReadLine::Perl5::readline
5              
6             =head1 DESCRIPTION
7              
8             A non-OO package similar to GNU's readline. The preferred OO Package
9             is L. But that uses this internally.
10              
11             It could be made better by removing more of the global state and
12             moving it into the L side.
13              
14             There is some support for EUC-encoded Japanese text. This should be
15             rewritten for Perl Unicode though.
16              
17             Someone please volunteer to rewrite this!
18              
19             See also L.
20              
21             =cut
22 9     9   17598 use warnings;
  9         10  
  9         370  
23             package Term::ReadLine::Perl5::readline;
24 9     9   43 use File::Glob ':glob';
  9         11  
  9         2537  
25              
26             # no critic
27             # Version can be below the version given in Term::ReadLine::Perl5
28             our $VERSION = '1.42';
29              
30             #
31             # Separation into my and vars needs more work.
32             # use strict 'vars';
33             #
34 9         3239 use vars qw(@KeyMap %KeyMap $rl_screen_width $rl_start_default_at_beginning
35             $rl_completion_function $rl_basic_word_break_characters
36             $rl_completer_word_break_characters $rl_special_prefixes
37             $rl_max_numeric_arg $rl_OperateCount
38             $rl_completion_suppress_append
39             $history_stifled
40             $KillBuffer $dumb_term $stdin_not_tty $InsertMode
41             $mode $winsz $force_redraw
42             $have_getpwent
43             $minlength $rl_readline_name
44             @winchhooks
45             $rl_NoInitFromFile
46             $DEBUG;
47 9     9   49 );
  9         15  
48              
49             @ISA = qw(Exporter);
50             @EXPORT = qw($minlength rl_NoInitFromFile rl_bind rl_set
51             rl_read_init_file
52             rl_basic_commands rl_filename_list
53             completion_function);
54              
55              
56 9     9   4964 use File::HomeDir;
  9         43640  
  9         555  
57 9     9   51 use File::Spec;
  9         13  
  9         136  
58 9     9   68647 use Term::ReadKey;
  0            
  0            
59              
60             eval "use rlib '.' "; # rlib is now optional
61             use Term::ReadLine::Perl5::Common;
62             use Term::ReadLine::Perl5::Dumb;
63             use Term::ReadLine::Perl5::History;
64             use Term::ReadLine::Perl5::Keymap
65             qw(KeymapEmacs KeymapVi KeymapVicmd KeymapVipos KeymapVisearch);
66             use Term::ReadLine::Perl5::TermCap; # For ornaments
67              
68             my $autoload_broken = 1; # currently: defined does not work with a-l
69             my $useioctl = 1;
70             my $usestty = 1;
71             my $max_include_depth = 10; # follow $include's in init files this deep
72              
73             my $HOME = File::HomeDir->my_home;
74              
75             BEGIN { # Some old systems have ioctl "unsupported"
76             *ioctl = sub ($$$) { eval { CORE::ioctl $_[0], $_[1], $_[2] } };
77             }
78              
79             $rl_getc = \&rl_getc;
80             $minlength = 1;
81             $history_stifled = 0;
82              
83             &preinit;
84             &init;
85              
86             #
87             # my ($InputLocMsg, $term_OUT, $term_IN);
88             # my ($winsz_t, $TIOCGWINSZ, $winsz, $rl_margin);
89             # my ($hook, %var_HorizontalScrollMode, %var_EditingMode, %var_OutputMeta);
90             # my ($var_HorizontalScrollMode, $var_EditingMode, $var_OutputMeta);
91             # my (%var_ConvertMeta, $var_ConvertMeta, %var_MarkModifiedLines, $var_MarkModifiedLines);
92             my $inDOS;
93             # my (%var_PreferVisibleBell, $var_PreferVisibleBell);
94             # my (%var_TcshCompleteMode, $var_TcshCompleteMode);
95             # my (%var_CompleteAddsuffix, $var_CompleteAddsuffix);
96             # my ($BRKINT, $ECHO, $FIONREAD, $ICANON, $ICRNL, $IGNBRK, $IGNCR, $INLCR,
97             # $ISIG, $ISTRIP, $NCCS, $OPOST, $RAW, $TCGETS, $TCOON, $TCSETS, $TCXONC,
98             # $TERMIOS_CFLAG, $TERMIOS_IFLAG, $TERMIOS_LFLAG, $TERMIOS_NORMAL_IOFF,
99             # $TERMIOS_NORMAL_ION, $TERMIOS_NORMAL_LOFF, $TERMIOS_NORMAL_LON,
100             # $TERMIOS_NORMAL_OOFF, $TERMIOS_NORMAL_OON, $TERMIOS_OFLAG,
101             # $TERMIOS_READLINE_IOFF, $TERMIOS_READLINE_ION, $TERMIOS_READLINE_LOFF,
102             # $TERMIOS_READLINE_LON, $TERMIOS_READLINE_OOFF, $TERMIOS_READLINE_OON,
103             # $TERMIOS_VMIN, $TERMIOS_VTIME, $TIOCGETP, $TIOCGWINSZ, $TIOCSETP,
104             # $fion, $fionread_t, $mode, $sgttyb_t,
105             # $termios, $termios_t, $winsz, $winsz_t);
106             # my ($line, $initialized);
107             #
108             # Global variables added for vi mode (I'm leaving them all commented
109             # out, like the declarations above, until SelfLoader issues
110             # are resolved).
111              
112             # True when we're in one of the vi modes.
113             my $Vi_mode;
114              
115             # Array refs: saves keystrokes for '.' command. Undefined when we're
116             # not doing a '.'-able command.
117             my $Dot_buf; # Working buffer
118             my $Last_vi_command; # Gets $Dot_buf when a command is parsed
119              
120             # These hold state for vi 'u' and 'U'.
121             my($Dot_state, $Vi_undo_state, $Vi_undo_all_state);
122              
123             # Refs to hashes used for cursor movement
124             my($Vi_delete_patterns, $Vi_move_patterns,
125             $Vi_change_patterns, $Vi_yank_patterns);
126              
127             # Array ref: holds parameters from the last [fFtT] command, for ';'
128             # and ','.
129             my $Last_findchar;
130              
131             # Globals for history search commands (/, ?, n, N)
132             my $Vi_search_re; # Regular expression (compiled by qr{})
133             my $Vi_search_reverse; # True for '?' search, false for '/'
134              
135             =head1 SUBROUTINES
136              
137             =cut
138             # Fix: case-sensitivity of inputrc on/off keywords in
139             # `set' commands. readline lib doesn't care about case.
140             # changed case of keys 'On' and 'Off' to 'on' and 'off'
141             # &rl_set changed so that it converts the value to
142             # lower case before hash lookup.
143             sub preinit
144             {
145             $DEBUG = 0;
146              
147             ## Set up the input and output handles
148              
149             $term_IN = \*STDIN unless defined $term_IN;
150             $term_OUT = \*STDOUT unless defined $term_OUT;
151             ## not yet supported... always on.
152             $var_HorizontalScrollMode = 1;
153             $var_HorizontalScrollMode{'On'} = 1;
154             $var_HorizontalScrollMode{'Off'} = 0;
155              
156             $var_EditingMode{'emacs'} = \@emacs_keymap;
157             $var_EditingMode{'vi'} = \@vi_keymap;
158             $var_EditingMode{'vicmd'} = \@vicmd_keymap;
159             $var_EditingMode{'vipos'} = \@vipos_keymap;
160             $var_EditingMode{'visearch'} = \@visearch_keymap;
161              
162             ## this is an addition. Very nice.
163             $var_TcshCompleteMode = 0;
164             $var_TcshCompleteMode{'On'} = 1;
165             $var_TcshCompleteMode{'Off'} = 0;
166              
167             $var_CompleteAddsuffix = 1;
168             $var_CompleteAddsuffix{'On'} = 1;
169             $var_CompleteAddsuffix{'Off'} = 0;
170              
171             $var_DeleteSelection = $var_DeleteSelection{'On'} = 1;
172             $var_DeleteSelection{'Off'} = 0;
173             *rl_delete_selection = \$var_DeleteSelection; # Alias
174              
175             ## not yet supported... always on
176             for ('InputMeta', 'OutputMeta') {
177             ${"var_$_"} = 1;
178             ${"var_$_"}{'Off'} = 0;
179             ${"var_$_"}{'On'} = 1;
180             }
181              
182             ## not yet supported... always off
183             for (
184             qw(
185             BlinkMatchingParen
186             ConvertMeta
187             EnableKeypad
188             PrintCompletionsHorizontally
189             CompletionIgnoreCase
190             DisableCompletion
191             MarkDirectories
192             MarkModifiedLines
193             MetaFlag
194             PreferVisibleBell
195             ShowAllIfAmbiguous
196             VisibleStats
197             )) {
198             ${"var_$_"} = 0;
199             ${"var_$_"}{'Off'} = 0;
200             ${"var_$_"}{'On'} = 1;
201             }
202              
203             # WINCH hooks
204             @winchhooks = ();
205              
206             $inDOS = $^O eq 'os2' || defined $ENV{OS2_SHELL} unless defined $inDOS;
207              
208             # try to get, don't die if not found.
209             eval {require "ioctl.pl"};
210             eval {require "sgtty.ph"};
211              
212             if ($inDOS and !defined $TIOCGWINSZ) {
213             $TIOCGWINSZ=0;
214             $TIOCGETP=1;
215             $TIOCSETP=2;
216             $sgttyb_t="I5 C8";
217             $winsz_t="";
218             $RAW=0xf002;
219             $ECHO=0x0008;
220             }
221             $TIOCGETP = &TIOCGETP if defined(&TIOCGETP);
222             $TIOCSETP = &TIOCSETP if defined(&TIOCSETP);
223             $TIOCGWINSZ = &TIOCGWINSZ if defined(&TIOCGWINSZ);
224             $FIONREAD = &FIONREAD if defined(&FIONREAD);
225             $TCGETS = &TCGETS if defined(&TCGETS);
226             $TCSETS = &TCSETS if defined(&TCSETS);
227             $TCXONC = &TCXONC if defined(&TCXONC);
228             $TIOCGETP = 0x40067408 if !defined($TIOCGETP);
229             $TIOCSETP = 0x80067409 if !defined($TIOCSETP);
230             $TIOCGWINSZ = 0x40087468 if !defined($TIOCGWINSZ);
231             $FIONREAD = 0x4004667f if !defined($FIONREAD);
232             $TCGETS = 0x40245408 if !defined($TCGETS);
233             $TCSETS = 0x80245409 if !defined($TCSETS);
234             $TCXONC = 0x20005406 if !defined($TCXONC);
235              
236             ## TTY modes
237             $ECHO = &ECHO if defined(&ECHO);
238             $RAW = &RAW if defined(&RAW);
239             $RAW = 040 if !defined($RAW);
240             $ECHO = 010 if !defined($ECHO);
241             $mode = $RAW; ## could choose CBREAK for testing....
242              
243             $IGNBRK = 1 if !defined($IGNBRK);
244             $BRKINT = 2 if !defined($BRKINT);
245             $ISTRIP = 040 if !defined($ISTRIP);
246             $INLCR = 0100 if !defined($INLCR);
247             $IGNCR = 0200 if !defined($IGNCR);
248             $ICRNL = 0400 if !defined($ICRNL);
249             $OPOST = 1 if !defined($OPOST);
250             $ISIG = 1 if !defined($ISIG);
251             $ICANON = 2 if !defined($ICANON);
252             $TCOON = 1 if !defined($TCOON);
253             $TERMIOS_READLINE_ION = $BRKINT;
254             $TERMIOS_READLINE_IOFF = $IGNBRK | $ISTRIP | $INLCR | $IGNCR | $ICRNL;
255             $TERMIOS_READLINE_OON = 0;
256             $TERMIOS_READLINE_OOFF = $OPOST;
257             $TERMIOS_READLINE_LON = 0;
258             $TERMIOS_READLINE_LOFF = $ISIG | $ICANON | $ECHO;
259             $TERMIOS_NORMAL_ION = $BRKINT;
260             $TERMIOS_NORMAL_IOFF = $IGNBRK;
261             $TERMIOS_NORMAL_OON = $OPOST;
262             $TERMIOS_NORMAL_OOFF = 0;
263             $TERMIOS_NORMAL_LON = $ISIG | $ICANON | $ECHO;
264             $TERMIOS_NORMAL_LOFF = 0;
265              
266             $sgttyb_t = 'C4 S' if !defined($sgttyb_t);
267             $winsz_t = "S S S S" if !defined($winsz_t);
268             # rows,cols, xpixel, ypixel
269             $winsz = pack($winsz_t,0,0,0,0);
270             $NCCS = 17;
271             $termios_t = "LLLLc" . ("c" x $NCCS); # true for SunOS 4.1.3, at least...
272             $termios = ''; ## just to shut up "perl -w".
273             $termios = pack($termios, 0); # who cares, just make it long enough
274             $TERMIOS_IFLAG = 0;
275             $TERMIOS_OFLAG = 1;
276             ## $TERMIOS_CFLAG = 2;
277             $TERMIOS_LFLAG = 3;
278             $TERMIOS_VMIN = 5 + 4;
279             $TERMIOS_VTIME = 5 + 5;
280             $rl_delete_selection = 1;
281             $rl_correct_sw = ($inDOS ? 1 : 0);
282             $rl_scroll_nextline = 1 unless defined $rl_scroll_nextline;
283             $rl_last_pos_can_backspace = ($inDOS ? 0 : 1) # Can backspace when the
284             unless defined $rl_last_pos_can_backspace; # whole line is filled?
285              
286             $rl_start_default_at_beginning = 0;
287             $rl_vi_replace_default_on_insert = 0;
288             $rl_screen_width = 79; ## default
289              
290             $rl_completion_function = "rl_filename_list"
291             unless defined($rl_completion_function);
292             $rl_basic_word_break_characters = "\\\t\n' \"`\@\$><=;|&{(";
293             $rl_completer_word_break_characters = $rl_basic_word_break_characters;
294             $rl_special_prefixes = '';
295             ($rl_readline_name = $0) =~ s#.*[/\\]## if !defined($rl_readline_name);
296              
297             $rl_max_numeric_arg = 200 if !defined($rl_max_numeric_arg);
298             $rl_OperateCount = 0 if !defined($rl_OperateCount);
299             $rl_completion_suppress_append = 0
300             if !defined($rl_completion_suppress_append);
301              
302             no warnings 'once';
303             $rl_term_set = \@Term::ReadLine::TermCap::rl_term_set;
304             @$rl_term_set or $rl_term_set = ["","","",""];
305              
306             $InsertMode=1;
307             $KillBuffer='';
308             $line='';
309             $D = 0;
310             $InputLocMsg = ' [initialization]';
311              
312             KeymapEmacs(\&InitKeymap, \@emacs_keymap, $inDOS);
313             *KeyMap = \@emacs_keymap;
314             my @add_bindings = ();
315             foreach ('-', '0' .. '9') {
316             push(@add_bindings, "M-$_", 'DigitArgument');
317             }
318             foreach ("A" .. "Z") {
319             next if
320             # defined($KeyMap[27]) && defined (%{"$KeyMap{name}_27"}) &&
321             defined $ {"$KeyMap{name}_27"}[ord $_];
322             push(@add_bindings, "M-$_", 'DoLowercaseVersion');
323             }
324             if ($inDOS) {
325             # Default translation of Alt-char
326             $ {"$KeyMap{name}_0"}{'Esc'} = *{"$KeyMap{name}_27"};
327             $ {"$KeyMap{name}_0"}{'default'} = 'F_DoEscVersion';
328             }
329             &rl_bind(@add_bindings);
330              
331             local(*KeyMap);
332              
333             # Vi input mode.
334             KeymapVi(\&InitKeymap, \@vi_keymap);
335              
336             # Vi command mode.
337             KeymapVicmd(\&InitKeymap, \@vicmd_keymap);
338              
339             # Vi positioning commands (suffixed to vi commands like 'd').
340             KeymapVipos(\&InitKeymap, \@vipos_keymap, $inDOS);
341              
342             # Vi search string input mode for '/' and '?'.
343             KeymapVisearch(\&InitKeymap, \@visearch_keymap);
344              
345             # These constant hashes hold the arguments to &forward_scan() or
346             # &backward_scan() for vi positioning commands, which all
347             # behave a little differently for delete, move, change, and yank.
348             #
349             # Note: I originally coded these as qr{}, but changed them to q{} for
350             # compatibility with older perls at the expense of some performance.
351             #
352             # Note: Some of the more obscure key combinations behave slightly
353             # differently in different vi implementation. This module matches
354             # the behavior of /usr/ucb/vi, which is different from the
355             # behavior of vim, nvi, and the ksh command line. One example is
356             # the command '2de', when applied to the string ('^' represents the
357             # cursor, not a character of the string):
358             #
359             # ^5.6 7...88888888
360             #
361             # With /usr/ucb/vi and with this module, the result is
362             #
363             # ^...88888888
364             #
365             # but with the other three vi implementations, the result is
366             #
367             # ^ 7...88888888
368              
369             $Vi_delete_patterns = {
370             ord('w') => q{(?:\w+|[^\w\s]+|)\s*},
371             ord('W') => q{\S*\s*},
372             ord('b') => q{\w+\s*|[^\w\s]+\s*|^\s+},
373             ord('B') => q{\S+\s*|^\s+},
374             ord('e') => q{.\s*\w+|.\s*[^\w\s]+|.\s*$},
375             ord('E') => q{.\s*\S+|.\s*$},
376             };
377              
378             $Vi_move_patterns = {
379             ord('w') => q{(?:\w+|[^\w\s]+|)\s*},
380             ord('W') => q{\S*\s*},
381             ord('b') => q{\w+\s*|[^\w\s]+\s*|^\s+},
382             ord('B') => q{\S+\s*|^\s+},
383             ord('e') => q{.\s*\w*(?=\w)|.\s*[^\w\s]*(?=[^\w\s])|.?\s*(?=\s$)},
384             ord('E') => q{.\s*\S*(?=\S)|.?\s*(?=\s$)},
385             };
386              
387             $Vi_change_patterns = {
388             ord('w') => q{\w+|[^\w\s]+|\s},
389             ord('W') => q{\S+|\s},
390             ord('b') => q{\w+\s*|[^\w\s]+\s*|^\s+},
391             ord('B') => q{\S+\s*|^\s+},
392             ord('e') => q{.\s*\w+|.\s*[^\w\s]+|.\s*$},
393             ord('E') => q{.\s*\S+|.\s*$},
394             };
395              
396             $Vi_yank_patterns = {
397             ord('w') => q{(?:\w+|[^\w\s]+|)\s*},
398             ord('W') => q{\S*\s*},
399             ord('b') => q{\w+\s*|[^\w\s]+\s*|^\s+},
400             ord('B') => q{\S+\s*|^\s+},
401             ord('e') => q{.\s*\w*(?=\w)|.\s*[^\w\s]*(?=[^\w\s])|.?\s*(?=\s$)},
402             ord('E') => q{.\s*\S*(?=\S)|.?\s*(?=\s$)},
403             };
404              
405             *KeyMap = $var_EditingMode = $var_EditingMode{'emacs'};
406             1; # Returning a glob causes a bug in db5.001m
407             }
408              
409             # FIXME: something in here causes terminal attributes like bold and
410             # underline to work.
411             sub rl_term_set()
412             {
413             $rl_term_set = \@Term::ReadLine::TermCap::rl_term_set;
414             }
415              
416             sub init()
417             {
418             if ($ENV{'TERM'} and ($ENV{'TERM'} eq 'emacs' || $ENV{'TERM'} eq 'dumb')) {
419             $dumb_term = 1;
420             } elsif (! -c $term_IN && $term_IN eq \*STDIN) { # Believe if it is given
421             $stdin_not_tty = 1;
422             } else {
423             &get_window_size;
424             &F_ReReadInitFile if !defined($rl_NoInitFromFile);
425             $InputLocMsg = '';
426             *KeyMap = $var_EditingMode;
427             }
428              
429             $initialized = 1;
430             }
431              
432              
433             =head2 InitKeyMap
434              
435             C
436              
437             =cut
438              
439             sub InitKeymap
440             {
441             local(*KeyMap) = shift(@_);
442             my $default = shift(@_);
443             my $name = $KeyMap{'name'} = shift(@_);
444              
445             # 'default' is now optional - if '', &do_command() defaults it to
446             # 'F_Ding'. Meta-maps now don't set a default - this lets
447             # us detect multiple '\*' default declarations. JP
448             if ($default ne '') {
449             my $func = $KeyMap{'default'} = "F_$default";
450             ### Temporarily disabled
451             die qq/Bad default function [$func] for keymap "$name"/
452             if !$autoload_broken and !defined(&$func);
453             }
454              
455             &rl_bind if @_ > 0; ## The rest of @_ gets passed silently.
456             }
457              
458             sub filler_Pending ($) {
459             my $keys = shift;
460             sub {
461             my $c = shift;
462             push @Pending, map chr, @$keys;
463             return if not @$keys or $c == 1 or not defined(my $in = &getc_with_pending);
464             # provide the numeric argument
465             local(*KeyMap) = $var_EditingMode;
466             $doingNumArg = 1; # Allow NumArg inside NumArg
467             &do_command(*KeyMap, $c, ord $in);
468             return;
469             }
470             }
471              
472              
473             =head2 _unescape
474              
475             _unescape($string) -> List of keys
476              
477             This internal function that takes I<$string> possibly containing
478             escape sequences, and converts to a series of octal keys.
479              
480             It has special rules for dealing with readline-specific escape-sequence
481             commands.
482              
483             New-style key bindings are enclosed in double-quotes.
484             Characters are taken verbatim except the special cases:
485              
486             \C-x Control x (for any x)
487             \M-x Meta x (for any x)
488             \e Escape
489             \* Set the keymap default (JP: added this)
490             (must be the last character of the sequence)
491             \x x (unless it fits the above pattern)
492              
493             Special case "\C-\M-x", should be treated like "\M-\C-x".
494              
495             =cut
496              
497             my @ESCAPE_REGEXPS = (
498             # Ctrl-meta
499             [ qr/^\\C-\\M-(.)/, sub { ord("\e"), ctrl(ord(shift)) } ],
500             # Meta
501             [ qr/^\\(M-|e)/, sub { ord("\e") } ],
502             # Ctrl
503             [ qr/^\\C-(.)/, sub { ctrl(ord(shift)) } ],
504             # hex value
505             [ qr/^\\x([0-9a-fA-F]{2})/, sub { hex(shift) } ],
506             # octal value
507             [ qr/^\\([0-7]{3})/, sub { oct(shift) } ],
508             # default
509             [ qr/^\\\*$/, sub { 'default'; } ],
510             # EOT (Ctrl-D)
511             [ qr/^\\d/, sub { 4 } ],
512             # Backspace
513             [ qr/\\b/, sub { 0x7f } ],
514             # Escape Sequence
515             [ qr/\\(.)/,
516             sub {
517             my $chr = shift;
518             ord(($chr =~ /^[afnrtv]$/) ? eval(qq("\\$chr")) : $chr);
519             } ],
520             );
521              
522             sub _unescape ($) {
523             my($key, @keys) = shift;
524              
525             CHAR: while (length($key) > 0) {
526             foreach my $command (@ESCAPE_REGEXPS) {
527             my $regex = $command->[0];
528             if ($key =~ s/^$regex//) {
529             push @keys, $command->[1]->($1);
530             next CHAR;
531             }
532             }
533             push @keys, ord($key);
534             substr($key,0,1) = '';
535             }
536             @keys
537             }
538              
539             sub RL_func ($) {
540             my $name_or_macro = shift;
541             if ($name_or_macro =~ /^"((?:\\.|[^\\\"])*)"|^'((?:\\.|[^\\\'])*)'/s) {
542             filler_Pending [_unescape "$+"];
543             } else {
544             "F_$name_or_macro";
545             }
546             }
547              
548             =head2 bind_parsed_keyseq
549              
550             B(I<$function1>, I<@sequence1>, ...)
551              
552             Actually inserts the binding for I<@sequence> to I<$function> into the
553             current map. I<@sequence> is an array of character ordinals.
554              
555             If C is more than one element long, all but the last will
556             cause meta maps to be created.
557              
558             I<$Function> will have an implicit I prepended to it.
559              
560             0 is returned if there is no error.
561              
562             =cut
563              
564             sub bind_parsed_keyseq
565             {
566             my $bad = 0;
567             while (@_) {
568             my $func = shift;
569             my ($key, @keys) = @{shift()};
570             $key += 0;
571             local(*KeyMap) = *KeyMap;
572             my $map;
573             while (@keys) {
574             if (defined($KeyMap[$key]) && ($KeyMap[$key] ne 'F_PrefixMeta')) {
575             warn "Warning$InputLocMsg: ".
576             "Re-binding char #$key from [$KeyMap[$key]] to meta for [@keys] => $func.\n" if $^W;
577             }
578             $KeyMap[$key] = 'F_PrefixMeta';
579             $map = "$KeyMap{'name'}_$key";
580             InitKeymap(*$map, '', $map) if !(%$map);
581             *KeyMap = *$map;
582             $key = shift @keys;
583             #&bind_parsed_keyseq($func, \@keys);
584             }
585              
586             my $name = $KeyMap{'name'};
587             if ($key eq 'default') { # JP: added
588             warn "Warning$InputLocMsg: ".
589             " changing default action to $func in $name key map\n"
590             if $^W && defined $KeyMap{'default'};
591              
592             $KeyMap{'default'} = RL_func $func;
593             }
594             else {
595             if (defined($KeyMap[$key]) && $KeyMap[$key] eq 'F_PrefixMeta'
596             && $func ne 'PrefixMeta')
597             {
598             warn "Warning$InputLocMsg: ".
599             " Re-binding char #$key to non-meta ($func) in $name key map\n"
600             if $^W;
601             }
602             $KeyMap[$key] = RL_func $func;
603             }
604             }
605             return $bad;
606             }
607              
608             =head2 GNU ReadLine-ish Routines
609              
610             Many of these aren't the the name GNU readline uses, nor do they
611             correspond to GNU ReadLine functions. Sigh.
612              
613             =head3 rl_bind_keyseq
614              
615             B(I<$keyspec>, I<$function>)
616              
617             Bind the key sequence represented by the string I to the
618             function function, beginning in the current keymap. This makes new
619             keymaps as necessary. The return value is non-zero if keyseq is
620             invalid. I<$keyspec> should be the name of key sequence in one of two
621             forms:
622              
623             Old (GNU readline documented) form:
624              
625             M-x to indicate Meta-x
626             C-x to indicate Ctrl-x
627             M-C-x to indicate Meta-Ctrl-x
628             x simple char x
629              
630             where I above can be a single character, or the special:
631              
632             special means
633             -------- -----
634             space space ( )
635             spc space ( )
636             tab tab (\t)
637             del delete (0x7f)
638             rubout delete (0x7f)
639             newline newline (\n)
640             lfd newline (\n)
641             ret return (\r)
642             return return (\r)
643             escape escape (\e)
644             esc escape (\e)
645              
646             New form:
647             "chars" (note the required double-quotes)
648              
649             where each char in the list represents a character in the sequence, except
650             for the special sequences:
651              
652             \\C-x Ctrl-x
653             \\M-x Meta-x
654             \\M-C-x Meta-Ctrl-x
655             \\e escape.
656             \\x x (if not one of the above)
657              
658              
659             C<$function> should be in the form C or C.
660              
661             It is an error for the function to not be known....
662              
663             As an example, the following lines in .inputrc will bind one's xterm
664             arrow keys:
665              
666             "\e[[A": previous-history
667             "\e[[B": next-history
668             "\e[[C": forward-char
669             "\e[[D": backward-char
670              
671             =cut
672              
673             sub rl_bind_keyseq($$)
674             {
675             my ($key, $func) = @_;
676             $func = canonic_command_function($func);
677              
678             ## print "sequence [$key] func [$func]\n"; ##DEBUG
679              
680             my @keys = ();
681             ## See if it's a new-style binding.
682             if ($key =~ m/"((?:\\.|[^\\])*)"/s) {
683             @keys = _unescape "$1";
684             } else {
685             ## old-style binding... only one key (or Meta+key)
686             my ($isctrl, $orig) = (0, $key);
687             $isctrl = $key =~ s/\b(C|Control|CTRL)-//i;
688             push(@keys, ord("\e")) if $key =~ s/\b(M|Meta)-//i; ## is meta?
689             ## Isolate key part. This matches GNU's implementation.
690             ## If the key is '-', be careful not to delete it!
691             $key =~ s/.*-(.)/$1/;
692             if ($key =~ /^(space|spc)$/i) { $key = ' '; }
693             elsif ($key =~ /^(rubout|del)$/i) { $key = "\x7f"; }
694             elsif ($key =~ /^tab$/i) { $key = "\t"; }
695             elsif ($key =~ /^(return|ret)$/i) { $key = "\r"; }
696             elsif ($key =~ /^(newline|lfd)$/i) { $key = "\n"; }
697             elsif ($key =~ /^(escape|esc)$/i) { $key = "\e"; }
698             elsif (length($key) > 1) {
699             warn "Warning$InputLocMsg: strange binding [$orig]\n" if $^W;
700             }
701             $key = ord($key);
702             $key = ctrl($key) if $isctrl;
703             push(@keys, $key);
704             }
705              
706             # Now do the mapping of the sequence represented in @keys
707             printf "rl_bind(%s, %s)\n", $func, join(', ', @keys) if $DEBUG;
708             &bind_parsed_keyseq($func, \@keys);
709             }
710              
711             =head3 rl_bind
712              
713             Accepts an array as pairs ($keyspec, $function, [$keyspec, $function]...).
714             and maps the associated bindings to the current KeyMap.
715             =cut
716              
717             sub rl_bind
718             {
719             while (defined($key = shift(@_)) && defined($func = shift(@_)))
720             {
721             rl_bind_keyseq($key, $func);
722             }
723             }
724              
725             =head3 rl_set
726              
727             C
728              
729             Sets the named variable as per the given value, if both are appropriate.
730             Allows the user of the package to set such things as HorizontalScrollMode
731             and EditingMode. Value_string may be of the form
732              
733             HorizontalScrollMode
734             horizontal-scroll-mode
735              
736             Also called during the parsing of F<~/.inputrc> for "set var value" lines.
737              
738             The previous value is returned, or undef on error.
739              
740             Consider the following example for how to add additional variables
741             accessible via rl_set (and hence via F<~/.inputrc>).
742              
743             Want:
744              
745             We want an external variable called "FooTime" (or "foo-time").
746             It may have values "January", "Monday", or "Noon".
747             Internally, we'll want those values to translate to 1, 2, and 12.
748              
749             How:
750              
751             Have an internal variable $var_FooTime that will represent the current
752             internal value, and initialize it to the default value.
753             Make an array %var_FooTime whose keys and values are are the external
754             (January, Monday, Noon) and internal (1, 2, 12) values:
755              
756             $var_FooTime = $var_FooTime{'January'} = 1; #default
757             $var_FooTime{'Monday'} = 2;
758             $var_FooTime{'Noon'} = 12;
759              
760             =cut
761              
762             sub rl_set
763             {
764             local($var, $val) = @_;
765              
766             # &preinit's keys are all Capitalized
767             $val = ucfirst lc $val if $val =~ /^(on|off)$/i;
768              
769             $var = 'CompleteAddsuffix' if $var eq 'visible-stats';
770              
771             ## if the variable is in the form "some-name", change to "SomeName"
772             local($_) = "\u$var";
773             local($return) = undef;
774             s/-(.)/\u$1/g;
775              
776             # Skip unknown variables:
777             return unless defined $ {'Term::ReadLine::Perl5::readline::'}{"var_$_"};
778             local(*V); # avoid warning
779             { local $^W; *V = $ {'Term::ReadLine::Perl5::readline::'}{"var_$_"}; }
780             if (!defined($V)) { # XXX Duplicate check?
781             warn("Warning$InputLocMsg:\n".
782             " Invalid variable `$var'\n") if $^W;
783             } elsif (!defined($V{$val})) {
784             local(@selections) = keys(%V);
785             warn("Warning$InputLocMsg:\n".
786             " Invalid value `$val' for variable `$var'.\n".
787             " Choose from [@selections].\n") if $^W;
788             } else {
789             $return = $V;
790             $V = $V{$val}; ## make the setting
791             }
792             $return;
793             }
794              
795             =head3 rl_filename_list
796              
797             rl_filename_list($pattern) => list of files
798              
799             Returns a list of completions that begin with the string I<$pattern>.
800             Can be used to pass to I.
801              
802             This function corresponds to the L function
803             I. But that doesn't handle tilde expansion while
804             this does. Also, directories returned will have the '/' suffix
805             appended as is the case returned by GNU Readline, but not
806             I. Adding the '/' suffix is useful in completion
807             because it forces the next completion to complete inside that
808             directory.
809              
810             GNU Readline also will complete partial I<~> names; for example
811             I<~roo> maybe expanded to C for the root user. When
812             getpwent/setpwent is available we provide that.
813              
814             The user of this package can set I<$rl_completion_function> to
815             'rl_filename_list' to restore the default of filename matching if
816             they'd changed it earlier, either directly or via &rl_basic_commands.
817              
818             =cut
819              
820             sub rl_filename_list
821             {
822             my $pattern = $_[0];
823             if ($pattern =~ m{^~[^/]*$}) {
824             if ($have_getpwent and length($pattern) > 1) {
825             map { -d $_ ? $_ . '/' : $_ }
826             tilde_complete(substr($pattern, 1));
827             } else {
828             map { -d $_ ? $_ . '/' : $_ } bsd_glob($pattern);
829             }
830             } else {
831             map { -d $_ ? $_ . '/' : $_ } bsd_glob($pattern . '*');
832             }
833             }
834              
835             =head3 rl_filename_list_deprecated
836              
837             C
838              
839             This was the I function before version 1.30,
840             and the current I function.
841              
842             For reasons that are a mystery to me (rocky), there seemed to be a the
843             need to classify the result adding a suffix for executable (*),
844             pipe/socket (=), and symbolic link (@), and directory (/). Of these,
845             the only useful one is directory since that will cause a further
846             completion to continue.
847              
848             =cut
849             sub rl_filename_list_deprecated
850             {
851             my $pattern = $_[0];
852             my @files = (<$pattern*>);
853             if ($var_CompleteAddsuffix) {
854             foreach (@files) {
855             if (-l $_) {
856             $_ .= '@';
857             } elsif (-d _) {
858             $_ .= '/';
859             } elsif (-x _) {
860             $_ .= '*';
861             } elsif (-S _ || -p _) {
862             $_ .= '=';
863             }
864             }
865             }
866             return @files;
867             }
868              
869             # Handle one line of an input file. Note we also assume
870             # local-bound arrays I<@action> and I<@level>.
871             sub parse_and_bind($$$)
872             {
873             $_ = shift;
874             my $file = shift;
875             my $include_depth = shift;
876             s/^\s+//;
877             return if m/^\s*(#|$)/;
878             $InputLocMsg = " [$file line $.]";
879             if (/^\$if\s+(.*)/) {
880             my($test) = $1;
881             push(@level, 'if');
882             if ($action[$#action] ne 'exec') {
883             ## We're supposed to be skipping or ignoring this level,
884             ## so for subsequent levels we really ignore completely.
885             push(@action, 'ignore');
886             } else {
887             ## We're executing this IF... do the test.
888             ## The test is either "term=xxxx", or just a string that
889             ## we compare to $rl_readline_name;
890             if ($test =~ /term=([a-z0-9]+)/) {
891             $test = ($ENV{'TERM'} && $1 eq $ENV{'TERM'});
892             } else {
893             $test = $test =~ /^(perl|$rl_readline_name)\s*$/i;
894             }
895             push(@action, $test ? 'exec' : 'skip');
896             }
897             return;
898             } elsif (/^\$endif\b/) {
899             die qq/\rWarning$InputLocMsg: unmatched endif\n/ if @level == 0;
900             pop(@level);
901             pop(@action);
902             return;
903             } elsif (/^\$else\b/) {
904             die qq/\rWarning$InputLocMsg: unmatched else\n/ if
905             @level == 0 || $level[$#level] ne 'if';
906             $level[$#level] = 'else'; ## an IF turns into an ELSE
907             if ($action[$#action] eq 'skip') {
908             $action[$#action] = 'exec'; ## if were SKIPing, now EXEC
909             } else {
910             $action[$#action] = 'ignore'; ## otherwise, just IGNORE.
911             }
912             return;
913             } elsif (/^\$include\s+(\S+)/) {
914             if ($include_depth > $max_include_depth) {
915             warn "Deep recursion in \$include directives in $file.\n";
916             } else {
917             read_an_init_file($1, $include_depth + 1);
918             }
919             } elsif ($action[$#action] ne 'exec') {
920             ## skipping this one....
921             # Readline permits trailing comments in inputrc
922             # For example, /etc/inputrc on Mandrake Linux boxes has trailing
923             # comments
924             } elsif (m/\s*set\s+(\S+)\s+(\S*)/) { # Allow trailing comment
925             &rl_set($1, $2, $file);
926             } elsif (m/^\s*(\S+):\s+("(?:\\.|[^\\\"])*"|'(\\.|[^\\\'])*')/) { # Allow trailing comment
927             &rl_bind($1, $2);
928             } elsif (m/^\s*(\S+|"[^\"]+"):\s+(\S+)/) { # Allow trailing comment
929             &rl_bind($1, $2);
930             } else {
931             chomp;
932             warn "\rWarning$InputLocMsg: Bad line [$_]\n" if $^W;
933             }
934             }
935              
936             =head3 rl_parse_and_bind
937              
938             B(I<$line>)
939              
940             Parse I<$line> as if it had been read from the inputrc file and
941             perform any key bindings and variable assignments found.
942              
943             =cut
944             sub rl_parse_and_bind($)
945             {
946             my $line = shift;
947             parse_and_bind($line, '*bogus*', 0);
948             }
949              
950             =head3 rl_basic_commands
951              
952             Called with a list of possible commands, will allow command completion
953             on those commands, but only for the first word on a line. For
954             example:
955              
956             &rl_basic_commands('set', 'quit', 'type', 'run');
957              
958             This is for people that want quick and simple command completion.
959             A more thoughtful implementation would set I<$rl_completion_function>
960             to a routine that would look at the context of the word being completed
961             and return the appropriate possibilities.
962              
963             =cut
964             sub rl_basic_commands
965             {
966             @rl_basic_commands = @_;
967             $rl_completion_function = 'use_basic_commands';
968             }
969              
970             sub rl_getc() {
971             $Term::ReadLine::Perl5::term->Tk_loop
972             if $Term::ReadLine::toloop && defined &Tk::DoOneEvent;
973             return Term::ReadKey::ReadKey(0, $term_IN);
974             }
975              
976             =head3 rl_read_init_file
977              
978             B(I<$filename>)
979             Read keybindings and variable assignments from filename I<$filename>.
980              
981             =cut
982             sub rl_read_init_file($) {
983             read_an_init_file(shift, 0);
984             }
985              
986              
987             ###########################################################################
988             ## Bindable functions... pretty much in the same order as in readline.c ###
989             ###########################################################################
990             =head1 BINDABLE FUNCTIONS
991              
992             There are pretty much in the same order as in readline.c
993              
994             =head2 Commands For Moving
995              
996             =head3 F_BeginningOfLine
997              
998             Move to the start of the current line.
999              
1000             =cut
1001              
1002             sub F_BeginningOfLine
1003             {
1004             $D = 0;
1005             }
1006              
1007             =head3 F_EndOfLine
1008              
1009             Move to the end of the line.
1010              
1011             =cut
1012              
1013             sub F_EndOfLine
1014             {
1015             &F_ForwardChar(100) while !&at_end_of_line;
1016             }
1017              
1018              
1019             =head3 F_ForwardChar
1020              
1021             Move forward (right) $count characters.
1022              
1023             =cut
1024              
1025             sub F_ForwardChar
1026             {
1027             my $count = shift;
1028             return &F_BackwardChar(-$count) if $count < 0;
1029              
1030             while (!&at_end_of_line && $count-- > 0) {
1031             $D += &CharSize($D);
1032             }
1033             }
1034              
1035             =head3 F_BackwardChar
1036              
1037             Move backward (left) $count characters.
1038              
1039             =cut
1040              
1041             sub F_BackwardChar
1042             {
1043             my $count = shift;
1044             return &F_ForwardChar(-$count) if $count < 0;
1045              
1046             while (($D > 0) && ($count-- > 0)) {
1047             $D--; ## Move back one regardless,
1048             $D-- if &OnSecondByte($D); ## another if over a big char.
1049             }
1050             }
1051              
1052             =head3 F_ForwardWord
1053              
1054             Move forward to the end of the next word. Words are composed of
1055             letters and digits.
1056              
1057             Done as many times as $count says.
1058              
1059             =cut
1060              
1061             sub F_ForwardWord
1062             {
1063             my $count = shift;
1064             return &F_BackwardWord(-$count) if $count < 0;
1065              
1066             while (!&at_end_of_line && $count-- > 0)
1067             {
1068             ## skip forward to the next word (if not already on one)
1069             &F_ForwardChar(1) while !&at_end_of_line && &WordBreak($D);
1070             ## skip forward to end of word
1071             &F_ForwardChar(1) while !&at_end_of_line && !&WordBreak($D);
1072             }
1073             }
1074              
1075             =head3 F_BackwardWord
1076              
1077             Move back to the start of the current or previous word. Words are
1078             composed of letters and digits.
1079              
1080             Done as many times as $count says.
1081              
1082             =cut
1083              
1084             sub F_BackwardWord
1085             {
1086             my $count = shift;
1087             return &F_ForwardWord(-$count) if $count < 0;
1088              
1089             while ($D > 0 && $count-- > 0) {
1090             ## skip backward to the next word (if not already on one)
1091             &F_BackwardChar(1) while (($D > 0) && &WordBreak($D-1));
1092             ## skip backward to start of word
1093             &F_BackwardChar(1) while (($D > 0) && !&WordBreak($D-1));
1094             }
1095             }
1096              
1097             =head3 F_ClearScreen
1098              
1099             Clear the screen and redraw the current line, leaving the current line
1100             at the top of the screen.
1101              
1102             If given a numeric arg other than 1, simply refreshes the line.
1103              
1104             =cut
1105              
1106             sub F_ClearScreen
1107             {
1108             my $count = shift;
1109             return &F_RedrawCurrentLine if $count != 1;
1110              
1111             $rl_CLEAR = `clear` if !defined($rl_CLEAR);
1112             local $\ = '';
1113             print $term_OUT $rl_CLEAR;
1114             $force_redraw = 1;
1115             }
1116              
1117             =head3 F_RedrawCurrentLine
1118              
1119             Refresh the current line. By default, this is unbound.
1120              
1121             =cut
1122              
1123             sub F_RedrawCurrentLine
1124             {
1125             $force_redraw = 1;
1126             }
1127              
1128             ###########################################################################
1129             =head2 Commands tor Manipulating the History
1130              
1131             =head3 F_AcceptLine
1132              
1133             Accept the line regardless of where the cursor is. If this line is
1134             non-empty, it may be added to the history list for future recall with
1135             add_history(). If this line is a modified history line, the history
1136             line is restored to its original state.
1137              
1138             =cut
1139              
1140             sub F_AcceptLine
1141             {
1142             &add_line_to_history($line, $minlength);
1143             $AcceptLine = $line;
1144             local $\ = '';
1145             print $term_OUT "\r\n";
1146             $force_redraw = 0;
1147             (pos $line) = undef; # Another way to force redraw...
1148             }
1149              
1150             =head3 F_PreviousHistory
1151              
1152             Move `back' through the history list, fetching the previous command.
1153              
1154             =cut
1155             sub F_PreviousHistory {
1156             &get_line_from_history($rl_HistoryIndex - shift);
1157             }
1158              
1159             =head3 F_PreviousHistory
1160              
1161             Move `forward' through the history list, fetching the next command.
1162              
1163             =cut
1164             sub F_NextHistory {
1165             &get_line_from_history($rl_HistoryIndex + shift);
1166             }
1167              
1168             =head3 F_BeginningOfHistory
1169              
1170             Move to the first line in the history.
1171              
1172             =cut
1173             sub F_BeginningOfHistory
1174             {
1175             &get_line_from_history(0);
1176             }
1177              
1178             =head3 F_EndOfHistory
1179              
1180             Move to the end of the input history, i.e., the line currently being
1181             entered.
1182              
1183             =cut
1184             sub F_EndOfHistory { &get_line_from_history(@rl_History); }
1185              
1186             =head3 F_ReverseSearchHistory
1187              
1188             Search backward starting at the current line and moving `up' through
1189             the history as necessary. This is an incremental search.
1190              
1191             =cut
1192             sub F_ReverseSearchHistory
1193             {
1194             &DoSearch($_[0] >= 0 ? 1 : 0);
1195             }
1196              
1197             =head3
1198              
1199             Search forward starting at the current line and moving `down' through
1200             the the history as necessary. This is an increment
1201              
1202             =cut
1203              
1204             sub F_ForwardSearchHistory
1205             {
1206             &DoSearch($_[0] >= 0 ? 0 : 1);
1207             }
1208              
1209             =head3 F_HistorySearchBackward
1210              
1211             Search backward through the history for the string of characters
1212             between the start of the current line and the point. The search string
1213             must match at the beginning of a history line. This is a
1214             non-incremental search. By default, this command is unbound.
1215              
1216             =cut
1217             sub F_HistorySearchBackward
1218             {
1219             &DoSearchStart(($_[0] >= 0 ? 1 : 0),substr($line,0,$D));
1220             }
1221              
1222             =head3 F_HistorySearchForward
1223              
1224             Search forward through the history for the string of characters
1225             between the start of the current line and the point. The search string
1226             may match anywhere in a history line. This is a non-incremental
1227             search. By default, this command is unbound.
1228              
1229             =cut
1230              
1231             sub F_HistorySearchForward
1232             {
1233             &DoSearchStart(($_[0] >= 0 ? 0 : 1),substr($line,0,$D));
1234             }
1235              
1236             sub F_PrintHistory {
1237             my($count) = @_;
1238              
1239             $count = 20 if $count == 1; # Default - assume 'H', not '1H'
1240             my $end = $rl_HistoryIndex + $count/2;
1241             $end = @rl_History if $end > @rl_History;
1242             my $start = $end - $count + 1;
1243             $start = 0 if $start < 0;
1244              
1245             my $lmh = length $rl_MaxHistorySize;
1246              
1247             my $lspace = ' ' x ($lmh+3);
1248             my $hdr = "$lspace-----";
1249             $hdr .= " (Use ESC UP to retrieve command ) -----" unless $Vi_mode;
1250             $hdr .= " (Use 'G' to retrieve command ) -----" if $Vi_mode;
1251              
1252             local ($\, $,) = ('','');
1253             print "\n$hdr\n";
1254             print $lspace, ". . .\n" if $start > 0;
1255             my $i;
1256             my $shift = ($Vi_mode != 0);
1257             for $i ($start .. $end) {
1258             print + ($i == $rl_HistoryIndex) ? '>' : ' ',
1259              
1260             sprintf("%${lmh}d: ", @rl_History - $i + $shift),
1261              
1262             ($i < @rl_History) ? $rl_History[$i] :
1263             ($i == $rl_HistoryIndex) ? $line :
1264             $line_for_revert,
1265              
1266             "\n";
1267             }
1268             print $lspace, ". . .\n" if $end < @rl_History;
1269             print "$hdr\n";
1270              
1271             rl_forced_update_display();
1272              
1273             &F_ViInput() if $line eq '' && $Vi_mode;
1274             }
1275              
1276             ###########################################################################
1277             =head2 Commands For Changing Text
1278              
1279             =head3 F_DeleteChar
1280              
1281             Removes the $count chars from under the cursor.
1282             If there is no line and the last command was different, tells
1283             readline to return EOF.
1284             If there is a line, and the cursor is at the end of it, and we're in
1285             tcsh completion mode, then list possible completions.
1286             If $count > 1, deleted chars saved to kill buffer.
1287              
1288             =cut
1289              
1290             sub F_DeleteChar
1291             {
1292             return if remove_selection();
1293              
1294             my $count = shift;
1295             return F_DeleteBackwardChar(-$count) if $count < 0;
1296             if (length($line) == 0) { # EOF sent (probably OK in DOS too)
1297             $AcceptLine = $ReturnEOF = 1 if $lastcommand ne 'F_DeleteChar';
1298             return;
1299             }
1300             if ($D == length ($line))
1301             {
1302             &complete_internal('?') if $var_TcshCompleteMode;
1303             return;
1304             }
1305             my $oldD = $D;
1306             &F_ForwardChar($count);
1307             return if $D == $oldD;
1308             &kill_text($oldD, $D, $count > 1);
1309             }
1310              
1311             =head3 F_BackwardDeleteChar
1312              
1313             Removes $count chars to left of cursor (if not at beginning of line).
1314             If $count > 1, deleted chars saved to kill buffer.
1315              
1316             =cut
1317              
1318             sub F_BackwardDeleteChar
1319             {
1320             return if remove_selection();
1321              
1322             my $count = shift;
1323             return F_DeleteChar(-$count) if $count < 0;
1324             my $oldD = $D;
1325             &F_BackwardChar($count);
1326             return if $D == $oldD;
1327             &kill_text($oldD, $D, $count > 1);
1328             }
1329              
1330             =head3 F_QuotedInsert
1331              
1332             Add the next character typed to the line verbatim. This is how to
1333             insert key sequences like C-q, for example.
1334              
1335             =cut
1336              
1337             sub F_QuotedInsert
1338             {
1339             my $count = shift;
1340             &F_SelfInsert($count, ord(&getc_with_pending));
1341             }
1342              
1343             =head3 F_TabInsert
1344              
1345             Insert a tab character.
1346              
1347             =cut
1348              
1349             sub F_TabInsert
1350             {
1351             my $count = shift;
1352             &F_SelfInsert($count, ord("\t"));
1353             }
1354              
1355             =head3 F_SelfInsert
1356              
1357             B(I<$count>, I<$ord>)
1358              
1359             I<$ord> is an ASCII ordinal; inserts I<$count> of them into global
1360             I<$line>.
1361              
1362             Insert yourself.
1363              
1364             =cut
1365              
1366             sub F_SelfInsert
1367             {
1368             remove_selection();
1369             my ($count, $ord) = @_;
1370             my $text2add = pack('C', $ord) x $count;
1371             if ($InsertMode) {
1372             substr($line,$D,0) .= $text2add;
1373             } else {
1374             ## note: this can screw up with 2-byte characters.
1375             substr($line,$D,length($text2add)) = $text2add;
1376             }
1377             $D += length($text2add);
1378             }
1379              
1380             =head3 F_TransposeChars
1381              
1382             Switch char at dot with char before it.
1383             If at the end of the line, switch the previous two...
1384             I: this could screw up multibyte characters.. should do correctly)
1385              
1386             =cut
1387              
1388             sub F_TransposeChars
1389             {
1390             if ($D == length($line) && $D >= 2) {
1391             substr($line,$D-2,2) = substr($line,$D-1,1).substr($line,$D-2,1);
1392             } elsif ($D >= 1) {
1393             substr($line,$D-1,2) = substr($line,$D,1) .substr($line,$D-1,1);
1394             } else {
1395             F_Ding();
1396             }
1397             }
1398              
1399             =head3 F_TransposeWords
1400              
1401             Drag the word before point past the word after point, moving point
1402             past that word as well. If the insertion point is at the end of the
1403             line, this transposes the last two words on the line.
1404              
1405             =cut
1406             sub F_TransposeWords {
1407             my $c = shift;
1408             return F_Ding() unless $c;
1409             # Find "this" word
1410             F_BackwardWord(1);
1411             my $p0 = $D;
1412             F_ForwardWord(1);
1413             my $p1 = $D;
1414             return F_Ding() if $p1 == $p0;
1415             my ($p2, $p3) = ($p0, $p1);
1416             if ($c > 0) {
1417             F_ForwardWord($c);
1418             $p3 = $D;
1419             F_BackwardWord(1);
1420             $p2 = $D;
1421             } else {
1422             F_BackwardWord(1 - $c);
1423             $p0 = $D;
1424             F_ForwardWord(1);
1425             $p1 = $D;
1426             }
1427             return F_Ding() if $p3 == $p2 or $p2 < $p1;
1428             my $r = substr $line, $p2, $p3 - $p2;
1429             substr($line, $p2, $p3 - $p2) = substr $line, $p0, $p1 - $p0;
1430             substr($line, $p0, $p1 - $p0) = $r;
1431             $D = $c > 0 ? $p3 : $p0 + $p3 - $p2; # End of "this" word after edit
1432             return 1;
1433             }
1434              
1435             =head3 F_UpcaseWord
1436              
1437             Uppercase the current (or following) word. With a negative argument,
1438             uppercase the previous word, but do not move the cursor.
1439              
1440             =cut
1441             sub F_UpcaseWord { &changecase($_[0], 'up'); }
1442              
1443             =head3 F_DownCaseWord
1444              
1445             Lowercase the current (or following) word. With a negative argument,
1446             lowercase the previous word, but do not move the cursor.
1447              
1448             =cut
1449             sub F_DownCaseWord { &changecase($_[0], 'down'); }
1450              
1451             =head3 F_CapitalizeWord
1452              
1453             Capitalize the current (or following) word. With a negative argument,
1454             capitalize the previous word, but do not move the cursor.
1455              
1456             =cut
1457             sub F_CapitalizeWord { &changecase($_[0], 'cap'); }
1458              
1459             =head3 F_OverwriteMode
1460              
1461             Toggle overwrite mode. With an explicit positive numeric argument,
1462             switches to overwrite mode. With an explicit non-positive numeric
1463             argument, switches to insert mode. This command affects only emacs
1464             mode; vi mode does overwrite differently. Each call to readline()
1465             starts in insert mode. In overwrite mode, characters bound to
1466             self-insert replace the text at point rather than pushing the text to
1467             the right. Characters bound to backward-delete-char replace the
1468             character before point with a space.
1469              
1470             By default, this command is unbound.
1471              
1472             =cut
1473             sub F_OverwriteMode
1474             {
1475             $InsertMode = 0;
1476             }
1477              
1478             ###########################################################################
1479             =head2 Killing and Yanking
1480              
1481             =head3 F_KillLine
1482              
1483             delete characters from cursor to end of line.
1484              
1485             =cut
1486              
1487             sub F_KillLine
1488             {
1489             my $count = shift;
1490             return F_BackwardKillLine(-$count) if $count < 0;
1491             kill_text($D, length($line), 1);
1492             }
1493              
1494             =head3 F_BackwardKillLine
1495              
1496             Delete characters from cursor to beginning of line.
1497              
1498             =cut
1499              
1500             sub F_BackwardKillLine
1501             {
1502             my $count = shift;
1503             return F_KillLine(-$count) if $count < 0;
1504             return F_Ding if $D == 0;
1505             kill_text(0, $D, 1);
1506             }
1507              
1508             =head3 F_UnixLineDiscard
1509              
1510             Kill line from cursor to beginning of line.
1511              
1512             =cut
1513              
1514             sub F_UnixLineDiscard
1515             {
1516             return F_Ding() if $D == 0;
1517             kill_text(0, $D, 1);
1518             }
1519              
1520             =head3 F_KillWord
1521              
1522             Delete characters to the end of the current word. If not on a word, delete to
1523             ## the end of the next word.
1524              
1525             =cut
1526              
1527             sub F_KillWord
1528             {
1529             my $count = shift;
1530             return &F_BackwardKillWord(-$count) if $count < 0;
1531             my $oldD = $D;
1532             &F_ForwardWord($count); ## moves forward $count words.
1533             kill_text($oldD, $D, 1);
1534             }
1535              
1536             =head3 F_BackwardKillWord
1537              
1538             Delete characters backward to the start of the current word, or, if
1539             currently not on a word (or just at the start of a word), to the start
1540             of the previous word.
1541              
1542             =cut
1543             sub F_BackwardKillWord
1544             {
1545             my $count = shift;
1546             return F_KillWord(-$count) if $count < 0;
1547             my $oldD = $D;
1548             &F_BackwardWord($count); ## moves backward $count words.
1549             kill_text($D, $oldD, 1);
1550             }
1551              
1552             =head3 F_UnixWordRubout
1553              
1554             Kill to previous whitespace.
1555              
1556             =cut
1557              
1558             sub F_UnixWordRubout
1559             {
1560             return F_Ding() if $D == 0;
1561             (my $oldD, local $rl_basic_word_break_characters) = ($D, "\t ");
1562             # JP: Fixed a bug here - both were 'my'
1563             F_BackwardWord(1);
1564             kill_text($D, $oldD, 1);
1565             }
1566              
1567             =head3 F_KillRegion
1568              
1569             Kill the text in the current region. By default, this command is
1570             unbound.
1571              
1572             =cut
1573             sub F_KillRegion {
1574             return F_Ding() unless $line_rl_mark == $rl_HistoryIndex;
1575             $rl_mark = length $line if $rl_mark > length $line;
1576             kill_text($rl_mark, $D, 1);
1577             $line_rl_mark = -1; # Disable mark
1578             }
1579              
1580             =head3 F_CopyRegionAsKill
1581              
1582             Copy the text in the region to the kill buffer, so it can be yanked right away. By default, this command is unbound.
1583              
1584             =cut
1585             sub F_CopyRegionAsKill {
1586             return F_Ding() unless $line_rl_mark == $rl_HistoryIndex;
1587             $rl_mark = length $line if $rl_mark > length $line;
1588             my ($s, $e) = ($rl_mark, $D);
1589             ($s, $e) = ($e, $s) if $s > $e;
1590             $ThisCommandKilledText = 1 + $s;
1591             $KillBuffer = '' if !$LastCommandKilledText;
1592             $KillBuffer .= substr($line, $s, $e - $s);
1593             }
1594              
1595             =head3 F_Yank
1596              
1597             Yank the top of the kill ring into the buffer at point.
1598              
1599             =cut
1600             sub F_Yank
1601             {
1602             remove_selection();
1603             &TextInsert($_[0], $KillBuffer);
1604             }
1605              
1606             sub F_YankPop {
1607             1;
1608             ## not implemented yet
1609             }
1610              
1611             sub F_YankNthArg {
1612             1;
1613             ## not implemented yet
1614             }
1615              
1616             ###########################################################################
1617             =head2 Specifying Numeric Arguments
1618              
1619             =head3 F_DigitArgument
1620              
1621             Add this digit to the argument already accumulating, or start a new
1622             argument. C starts a negative argument.
1623              
1624             =cut
1625             sub F_DigitArgument
1626             {
1627             my $in = chr $_[1];
1628             my ($NumericArg, $sawDigit) = (1, 0);
1629             my ($increment, $ord);
1630             ($NumericArg, $sawDigit) = ($_[0], $_[0] !~ /e0$/i)
1631             if $doingNumArg; # XXX What if Esc-- 1 ?
1632              
1633             do
1634             {
1635             $ord = ord $in;
1636             if (defined($KeyMap[$ord]) && $KeyMap[$ord] eq 'F_UniversalArgument') {
1637             $NumericArg *= 4;
1638             } elsif ($ord == ord('-') && !$sawDigit) {
1639             $NumericArg = -$NumericArg;
1640             } elsif ($ord >= ord('0') && $ord <= ord('9')) {
1641             $increment = ($ord - ord('0')) * ($NumericArg < 0 ? -1 : 1);
1642             if ($sawDigit) {
1643             $NumericArg = $NumericArg * 10 + $increment;
1644             } else {
1645             $NumericArg = $increment;
1646             $sawDigit = 1;
1647             }
1648             } else {
1649             local(*KeyMap) = $var_EditingMode;
1650             rl_redisplay();
1651             $doingNumArg = 1; # Allow NumArg inside NumArg
1652             &do_command(*KeyMap, $NumericArg . ($sawDigit ? '': 'e0'), $ord);
1653             return;
1654             }
1655             ## make sure it's not toooo big.
1656             if ($NumericArg > $rl_max_numeric_arg) {
1657             $NumericArg = $rl_max_numeric_arg;
1658             } elsif ($NumericArg < -$rl_max_numeric_arg) {
1659             $NumericArg = -$rl_max_numeric_arg;
1660             }
1661             redisplay(sprintf("(arg %d) ", $NumericArg));
1662             } while defined($in = &getc_with_pending);
1663             }
1664              
1665             =head3 F_UniversalArgument
1666              
1667             This is another way to specify an argument. If this command is
1668             followed by one or more digits, optionally with a leading minus sign,
1669             those digits define the argument. If the command is followed by
1670             digits, executing universal-argument again ends the numeric argument,
1671             but is otherwise ignored. As a special case, if this command is
1672             immediately followed by a character that is neither a digit or minus
1673             sign, the argument count for the next command is multiplied by
1674             four. The argument count is initially one, so executing this function
1675             the first time makes the argument count four, a second time makes the
1676             argument count sixteen, and so on. By default, this is not bound to a
1677             key.
1678              
1679             =cut
1680             sub F_UniversalArgument
1681             {
1682             &F_DigitArgument;
1683             }
1684              
1685             ###########################################################################
1686             =head2 Letting Readline Type For You
1687              
1688             =head3 F_Complete
1689              
1690             Do a completion operation. If the last thing we did was a completion
1691             operation, we'll now list the options available (under normal emacs
1692             mode).
1693              
1694             In I, each contiguous subsequent completion
1695             operation lists another of the possible options.
1696              
1697             Returns true if a completion was done, false otherwise, so vi
1698             completion routines can test it.
1699              
1700             =cut
1701              
1702             sub F_Complete
1703             {
1704             if ($lastcommand eq 'F_Complete') {
1705             if ($var_TcshCompleteMode && @tcsh_complete_selections > 0) {
1706             substr($line, $tcsh_complete_start, $tcsh_complete_len)
1707             = $tcsh_complete_selections[0];
1708             $D -= $tcsh_complete_len;
1709             $tcsh_complete_len = length($tcsh_complete_selections[0]);
1710             $D += $tcsh_complete_len;
1711             push(@tcsh_complete_selections, shift(@tcsh_complete_selections));
1712             } else {
1713             &complete_internal('?') or return;
1714             }
1715             } else {
1716             @tcsh_complete_selections = ();
1717             &complete_internal("\t") or return;
1718             }
1719              
1720             1;
1721             }
1722              
1723             =head3 F_PossibleCompletions
1724              
1725             List possible completions
1726              
1727             =cut
1728              
1729             sub F_PossibleCompletions
1730             {
1731             &complete_internal('?');
1732             }
1733              
1734             =head3 F_PossibleCompletions
1735              
1736             Insert all completions of the text before point that would have been
1737             generated by possible-completions.
1738              
1739             =cut
1740              
1741             sub F_InsertCompletions
1742             {
1743             &complete_internal('*');
1744             }
1745              
1746             ###########################################################################
1747             =head2 Miscellaneous Commands
1748              
1749             =head3 F_ReReadInitFile
1750              
1751             Read in the contents of the inputrc file, and incorporate any bindings
1752             or variable assignments found there.
1753              
1754             =cut
1755              
1756             sub F_ReReadInitFile
1757             {
1758             my ($file) = $ENV{'TRP5_INPUTRC'};
1759             $file = $ENV{'INPUTRC'} unless defined $file;
1760             unless (defined $file) {
1761             return unless defined $HOME;
1762             $file = File::Spec->catfile($HOME, '.inputrc');
1763             }
1764             rl_read_init_file($file);
1765             }
1766              
1767             =head3 F_Abort
1768              
1769             Abort the current editing command and ring the terminal's bell
1770             (subject to the setting of bell-style).
1771              
1772             =cut
1773             sub F_Abort
1774             {
1775             F_Ding();
1776             }
1777              
1778              
1779             =head3 F_Undo
1780              
1781             Incremental undo, separately remembered for each line.
1782              
1783             =cut
1784              
1785             sub F_Undo
1786             {
1787             pop(@undo); # unless $undo[-1]->[5]; ## get rid of the state we just put on, so we can go back one.
1788             if (@undo) {
1789             &getstate(pop(@undo));
1790             } else {
1791             F_Ding();
1792             }
1793             }
1794              
1795             =head3 F_RevertLine
1796              
1797             Undo all changes made to this line. This is like executing the undo
1798             command enough times to get back to the beginning.
1799              
1800             =cut
1801              
1802             sub F_RevertLine
1803             {
1804             if ($rl_HistoryIndex >= $#rl_History+1) {
1805             $line = $line_for_revert;
1806             } else {
1807             $line = $rl_History[$rl_HistoryIndex];
1808             }
1809             $D = length($line);
1810             }
1811              
1812             =head3 F_TildeExpand
1813              
1814             Perform tilde expansion on the current word.
1815              
1816             =cut
1817             sub F_TildeExpand {
1818              
1819             my $what_to_do = shift;
1820             my ($point, $end) = ($D, $D);
1821              
1822             # In vi mode, complete if the cursor is at the *end* of a word, not
1823             # after it.
1824             ($point++, $end++) if $Vi_mode;
1825              
1826             # Get text to work complete on.
1827             if ($point) {
1828             ## Not at the beginning of the line; Isolate the word to be
1829             ## completed.
1830             1 while (--$point && (-1 == index($rl_completer_word_break_characters,
1831             substr($line, $point, 1))));
1832              
1833             # Either at beginning of line or at a word break.
1834             # If at a word break (that we don't want to save), skip it.
1835             $point++ if (
1836             (index($rl_completer_word_break_characters,
1837             substr($line, $point, 1)) != -1) &&
1838             (index($rl_special_prefixes, substr($line, $point, 1)) == -1)
1839             );
1840             }
1841              
1842             my $text = substr($line, $point, $end - $point);
1843              
1844             # If the first character of the current word is a tilde, perform
1845             # tilde expansion and insert the result. If not a tilde, do
1846             # nothing.
1847             return if substr($text, 0, 1) ne '~';
1848              
1849             my @matches = tilde_complete($text);
1850             if (@matches == 0) {
1851             return F_Ding();
1852             }
1853             my $replacement = shift(@matches);
1854             $replacement .= $rl_completer_terminator_character
1855             if @matches == 1 && !$rl_completion_suppress_append;
1856             F_Ding() if @matches != 1;
1857             if ($var_TcshCompleteMode) {
1858             @tcsh_complete_selections = (@matches, $text);
1859             $tcsh_complete_start = $point;
1860             $tcsh_complete_len = length($replacement);
1861             }
1862              
1863             if ($replacement ne '') {
1864             # Finally! Do the replacement.
1865             substr($line, $point, $end-$point) = $replacement;
1866             $D = $D - ($end - $point) + length($replacement);
1867             }
1868             }
1869              
1870             =head3 F_SetMark
1871              
1872             Set the mark to the point. If a numeric argument is supplied, the mark
1873             is set to that position.
1874              
1875             =cut
1876              
1877             sub F_SetMark {
1878             $rl_mark = $D;
1879             pos $line = $rl_mark;
1880             $line_rl_mark = $rl_HistoryIndex;
1881             $force_redraw = 1;
1882             }
1883              
1884             =head3 F_ExchangePointAndMark
1885              
1886             Set the mark to the point. If a numeric argument is supplied, the mark
1887             is set to that position.
1888              
1889             =cut
1890              
1891             sub F_ExchangePointAndMark {
1892             return F_Ding unless $line_rl_mark == $rl_HistoryIndex;
1893             ($rl_mark, $D) = ($D, $rl_mark);
1894             pos $line = $rl_mark;
1895             $D = length $line if $D > length $line;
1896             $force_redraw = 1;
1897             }
1898              
1899             =head3 F_OperateAndGetNext
1900              
1901             Accept the current line and fetch from the history the next line
1902             relative to current line for default.
1903              
1904             =cut
1905              
1906             sub F_OperateAndGetNext
1907             {
1908             my $count = shift;
1909              
1910             &F_AcceptLine;
1911              
1912             my $remainingEntries = $#rl_History - $rl_HistoryIndex;
1913             if ($count > 0 && $remainingEntries >= 0) { # there is something to repeat
1914             if ($remainingEntries > 0) { # if we are not on last line
1915             $rl_HistoryIndex++; # fetch next one
1916             $count = $remainingEntries if $count > $remainingEntries;
1917             }
1918             $rl_OperateCount = $count;
1919             }
1920             }
1921              
1922             =head3 F_DoLowercaseVersion
1923              
1924             If the character that got us here is upper case,
1925             do the lower-case equivalent command.
1926              
1927             =cut
1928              
1929             sub F_DoLowercaseVersion
1930             {
1931             my $c = $_[1];
1932             if (isupper($c)) {
1933             &do_command(*KeyMap, $_[0], lc($c));
1934             } else {
1935             &F_Ding;
1936             }
1937             }
1938              
1939             =head3 F_DoControlVersion
1940              
1941             do the equiv with control key...
1942             If the character that got us here is upper case,
1943             do the lower-case equivalent command.
1944              
1945             =cut
1946              
1947             sub F_DoControlVersion
1948             {
1949             local *KeyMap = $var_EditingMode;
1950             my $key = $_[1];
1951              
1952             if ($key == ord('?')) {
1953             $key = 0x7F;
1954             } else {
1955             $key &= ~(0x80 | 0x60);
1956             }
1957             &do_command(*KeyMap, $_[0], $key);
1958             }
1959              
1960             =head3 F_DoMetaVersion
1961              
1962             do the equiv with meta key...
1963              
1964             =cut
1965              
1966             sub F_DoMetaVersion
1967             {
1968             local *KeyMap = $var_EditingMode;
1969             unshift @Pending, chr $_[1];
1970              
1971             &do_command(*KeyMap, $_[0], ord "\e");
1972             }
1973              
1974             =head3 F_DoEscVersion
1975              
1976             If the character that got us here is Alt-Char,
1977             do the Esc Char equiv...
1978              
1979             =cut
1980              
1981             sub F_DoEscVersion
1982             {
1983             my ($ord, $t) = $_[1];
1984             &F_Ding unless $KeyMap{'Esc'};
1985             for $t (([ord 'w', '`1234567890-='],
1986             [ord ',', 'zxcvbnm,./\\'],
1987             [16, 'qwertyuiop[]'],
1988             [ord(' ') - 2, 'asdfghjkl;\''])) {
1989             next unless $ord >= $t->[0] and $ord < $t->[0] + length($t->[1]);
1990             $ord = ord substr $t->[1], $ord - $t->[0], 1;
1991             return &do_command($KeyMap{'Esc'}, $_[0], $ord);
1992             }
1993             &F_Ding;
1994             }
1995              
1996             sub F_EmacsEditingMode
1997             {
1998             $var_EditingMode = $var_EditingMode{'emacs'};
1999             $Vi_mode = 0;
2000             }
2001              
2002             =head3 F_Interrupt
2003              
2004             (Attempt to) interrupt the current program via I
2005             =cut
2006              
2007             sub F_Interrupt
2008             {
2009             local $\ = '';
2010             print $term_OUT "\r\n";
2011             &ResetTTY;
2012             kill ("INT", 0);
2013              
2014             ## We're back.... must not have died.
2015             $force_redraw = 1;
2016             }
2017              
2018             ##
2019             ## Execute the next character input as a command in a meta keymap.
2020             ##
2021             sub F_PrefixMeta
2022             {
2023             my($count, $keymap) = ($_[0], "$KeyMap{'name'}_$_[1]");
2024             print "F_PrefixMeta [$keymap]\n\r" if $DEBUG;
2025             die "" unless %$keymap;
2026             do_command(*$keymap, $count, ord(&getc_with_pending));
2027             }
2028              
2029             sub F_InsertMode
2030             {
2031             $InsertMode = 1;
2032             }
2033              
2034             sub F_ToggleInsertMode
2035             {
2036             $InsertMode = !$InsertMode;
2037             }
2038              
2039             =head3
2040              
2041             (Attempt to) suspend the program via I
2042              
2043             =cut
2044              
2045             sub F_Suspend
2046             {
2047             if ($inDOS && length($line)==0) { # EOF sent
2048             $AcceptLine = $ReturnEOF = 1 if $lastcommand ne 'F_DeleteChar';
2049             return;
2050             }
2051             local $\ = '';
2052             print $term_OUT "\r\n";
2053             &ResetTTY;
2054             eval { kill ("TSTP", 0) };
2055             ## We're back....
2056             &SetTTY;
2057             $force_redraw = 1;
2058             }
2059              
2060             =head3 F_Ding
2061              
2062             Ring the bell.
2063              
2064             Should do something with I<$var_PreferVisibleBel> here, but what?
2065             =cut
2066             sub F_Ding {
2067             Term::ReadLine::Perl5::Common::F_Ding($term_OUT)
2068             }
2069              
2070             =head2 vi Routines
2071              
2072             =cut
2073              
2074             sub F_ViAcceptLine
2075             {
2076             &F_AcceptLine();
2077             &F_ViInput();
2078             }
2079              
2080             =head3 F_ViRepeatLastCommand
2081              
2082             Repeat the most recent one of these vi commands:
2083              
2084             a A c C d D i I p P r R s S x X ~
2085              
2086             =cut
2087             sub F_ViRepeatLastCommand {
2088             my($count) = @_;
2089             return F_Ding() if !$Last_vi_command;
2090              
2091             my @lastcmd = @$Last_vi_command;
2092              
2093             # Multiply @lastcmd's numeric arg by $count.
2094             unless ($count == 1) {
2095              
2096             my $n = '';
2097             while (@lastcmd and $lastcmd[0] =~ /^\d$/) {
2098             $n *= 10;
2099             $n += shift(@lastcmd);
2100             }
2101             $count *= $n unless $n eq '';
2102             unshift(@lastcmd, split(//, $count));
2103             }
2104              
2105             push(@Pending, @lastcmd);
2106             }
2107              
2108             sub F_ViMoveCursor
2109             {
2110             my($count, $ord) = @_;
2111              
2112             my $new_cursor = &get_position($count, $ord, undef, $Vi_move_patterns);
2113             return F_Ding() if !defined $new_cursor;
2114              
2115             $D = $new_cursor;
2116             }
2117              
2118             sub F_ViFindMatchingParens {
2119              
2120             # Move to the first parens at or after $D
2121             my $old_d = $D;
2122             &forward_scan(1, q/[^[\](){}]*/);
2123             my $parens = substr($line, $D, 1);
2124              
2125             my $mate_direction = {
2126             '(' => [ ')', 1 ],
2127             '[' => [ ']', 1 ],
2128             '{' => [ '}', 1 ],
2129             ')' => [ '(', -1 ],
2130             ']' => [ '[', -1 ],
2131             '}' => [ '{', -1 ],
2132              
2133             }->{$parens};
2134              
2135             return &F_Ding() unless $mate_direction;
2136              
2137             my($mate, $direction) = @$mate_direction;
2138              
2139             my $lvl = 1;
2140             while ($lvl) {
2141             last if !$D && ($direction < 0);
2142             &F_ForwardChar($direction);
2143             last if &at_end_of_line;
2144             my $c = substr($line, $D, 1);
2145             if ($c eq $parens) {
2146             $lvl++;
2147             }
2148             elsif ($c eq $mate) {
2149             $lvl--;
2150             }
2151             }
2152              
2153             if ($lvl) {
2154             # We didn't find a match
2155             $D = $old_d;
2156             return &F_Ding();
2157             }
2158             }
2159              
2160             sub F_ViForwardFindChar {
2161             &do_findchar(1, 1, @_);
2162             }
2163              
2164             sub F_ViBackwardFindChar {
2165             &do_findchar(-1, 0, @_);
2166             }
2167              
2168             sub F_ViForwardToChar {
2169             &do_findchar(1, 0, @_);
2170             }
2171              
2172             sub F_ViBackwardToChar {
2173             &do_findchar(-1, 1, @_);
2174             }
2175              
2176             sub F_ViMoveCursorTo
2177             {
2178             &do_findchar(1, -1, @_);
2179             }
2180              
2181             sub F_ViMoveCursorFind
2182             {
2183             &do_findchar(1, 0, @_);
2184             }
2185              
2186              
2187             sub F_ViRepeatFindChar {
2188             my($n) = @_;
2189             return &F_Ding if !defined $Last_findchar;
2190             &findchar(@$Last_findchar, $n);
2191             }
2192              
2193             sub F_ViInverseRepeatFindChar {
2194             my($n) = @_;
2195             return &F_Ding if !defined $Last_findchar;
2196             my($c, $direction, $offset) = @$Last_findchar;
2197             &findchar($c, -$direction, $offset, $n);
2198             }
2199              
2200             sub do_findchar {
2201             my($direction, $offset, $n) = @_;
2202             my $c = &getc_with_pending;
2203             $c = &getc_with_pending if $c eq "\cV";
2204             return &F_ViCommandMode if $c eq "\e";
2205             $Last_findchar = [$c, $direction, $offset];
2206             &findchar($c, $direction, $offset, $n);
2207             }
2208              
2209             sub findchar {
2210             my($c, $direction, $offset, $n) = @_;
2211             my $old_d = $D;
2212             while ($n) {
2213             last if !$D && ($direction < 0);
2214             &F_ForwardChar($direction);
2215             last if &at_end_of_line;
2216             my $char = substr($line, $D, 1);
2217             $n-- if substr($line, $D, 1) eq $c;
2218             }
2219             if ($n) {
2220             # Not found
2221             $D = $old_d;
2222             return &F_Ding;
2223             }
2224             &F_ForwardChar($offset);
2225             }
2226              
2227             sub F_ViMoveToColumn {
2228             my($n) = @_;
2229             $D = 0;
2230             my $col = 1;
2231             while (!&at_end_of_line and $col < $n) {
2232             my $c = substr($line, $D, 1);
2233             if ($c eq "\t") {
2234             $col += 7;
2235             $col -= ($col % 8) - 1;
2236             }
2237             else {
2238             $col++;
2239             }
2240             $D += &CharSize($D);
2241             }
2242             }
2243              
2244             =head3 F_SaveLine
2245              
2246             Prepend line with '#', add to history, and clear the input buffer
2247             (this feature was borrowed from ksh).
2248              
2249             =cut
2250             sub F_SaveLine
2251             {
2252             local $\ = '';
2253             $line = '#'.$line;
2254             rl_redisplay();
2255             print $term_OUT "\r\n";
2256             &add_line_to_history($line, $minlength);
2257             $line_for_revert = '';
2258             &get_line_from_history(scalar @rl_History);
2259             &F_ViInput() if $Vi_mode;
2260             }
2261              
2262             =head3 F_ViNonePosition
2263              
2264             Come here if we see a non-positioning keystroke when a positioning
2265             keystroke is expected.
2266             =cut
2267             sub F_ViNonPosition {
2268             # Not a positioning command - undefine the cursor to indicate the error
2269             # to get_position().
2270             undef $D;
2271             }
2272              
2273             =head3 ViPositionEsc
2274              
2275             Comes here if we see II, but I an arrow key or other
2276             mapped sequence, when a positioning keystroke is expected.
2277             =cut
2278              
2279             sub F_ViPositionEsc {
2280             my($count, $ord) = @_;
2281              
2282             # We got in vipos mode. Put back onto the
2283             # input stream and terminate the positioning command.
2284             unshift(@Pending, pack('c', $ord));
2285             &F_ViNonPosition;
2286             }
2287              
2288             sub F_ViUndo {
2289             return &F_Ding unless defined $Vi_undo_state;
2290             my $state = savestate();
2291             &getstate($Vi_undo_state);
2292             $Vi_undo_state = $state;
2293             }
2294              
2295             sub F_ViUndoAll {
2296             $Vi_undo_state = $Vi_undo_all_state;
2297             &F_ViUndo;
2298             }
2299              
2300             sub F_ViChange
2301             {
2302             my($count, $ord) = @_;
2303             &start_dot_buf(@_);
2304             &do_delete($count, $ord, $Vi_change_patterns) || return();
2305             &vi_input_mode;
2306             }
2307              
2308             sub F_ViDelete
2309             {
2310             my($count, $ord) = @_;
2311             &start_dot_buf(@_);
2312             &do_delete($count, $ord, $Vi_delete_patterns);
2313             &end_dot_buf;
2314             }
2315              
2316             sub F_ViDeleteChar {
2317             my($count) = @_;
2318             &save_dot_buf(@_);
2319             my $other_end = $D + $count;
2320             $other_end = length($line) if $other_end > length($line);
2321             &kill_text($D, $other_end, 1);
2322             }
2323              
2324             sub F_ViBackwardDeleteChar {
2325             my($count) = @_;
2326             &save_dot_buf(@_);
2327             my $other_end = $D - $count;
2328             $other_end = 0 if $other_end < 0;
2329             &kill_text($other_end, $D, 1);
2330             $D = $other_end;
2331             }
2332              
2333             =head3 F_ViFirstWord
2334              
2335             Go to first non-space character of line.
2336             =cut
2337             sub F_ViFirstWord
2338             {
2339             $D = 0;
2340             &forward_scan(1, q{\s+});
2341             }
2342              
2343             =head3 F_ViTtoggleCase
2344              
2345             # Like the emacs case transforms.
2346              
2347             I: this doesn't work for multi-byte characters.
2348             =cut
2349              
2350             sub F_ViToggleCase {
2351             my($count) = @_;
2352             &save_dot_buf(@_);
2353             while ($count-- > 0) {
2354             substr($line, $D, 1) =~ tr/A-Za-z/a-zA-Z/;
2355             &F_ForwardChar(1);
2356             if (&at_end_of_line) {
2357             &F_BackwardChar(1);
2358             last;
2359             }
2360             }
2361             }
2362              
2363             =head3 F_ViHistoryLine
2364              
2365             Go to the numbered history line, as listed by the 'H' command,
2366             i.e. the current $line is line 1, the youngest line in I<@rl_History>
2367             is 2, etc.
2368              
2369             =cut
2370              
2371             sub F_ViHistoryLine {
2372             my($n) = @_;
2373             &get_line_from_history(@rl_History - $n + 1);
2374             }
2375              
2376             =head3 F_ViSearch
2377              
2378             Search history for matching string. As with vi in nomagic mode, the
2379             ^, $, \<, and \> positional assertions, the \* quantifier, the \.
2380             character class, and the \[ character class delimiter all have special
2381             meaning here.
2382             =cut
2383             sub F_ViSearch {
2384             my($n, $ord) = @_;
2385              
2386             my $c = pack('c', $ord);
2387              
2388             my $str = &get_vi_search_str($c);
2389             if (!defined $str) {
2390             # Search aborted by deleting the '/' at the beginning of the line
2391             return &F_ViInput() if $line eq '';
2392             return();
2393             }
2394              
2395             # Null string repeats last search
2396             if ($str eq '') {
2397             return &F_Ding unless defined $Vi_search_re;
2398             }
2399             else {
2400             # Convert to a regular expression. Interpret $str Like vi in nomagic
2401             # mode: '^', '$', '\<', and '\>' positional assertions, '\*'
2402             # quantifier, '\.' and '\[]' character classes.
2403              
2404             my @chars = ($str =~ m{(\\?.)}g);
2405             my(@re, @tail);
2406             unshift(@re, shift(@chars)) if @chars and $chars[0] eq '^';
2407             push (@tail, pop(@chars)) if @chars and $chars[-1] eq '$';
2408             my $in_chclass;
2409             my %chmap = (
2410             '\<' => '\b(?=\w)',
2411             '\>' => '(?<=\w)\b',
2412             '\*' => '*',
2413             '\[' => '[',
2414             '\.' => '.',
2415             );
2416             my $ch;
2417             foreach $ch (@chars) {
2418             if ($in_chclass) {
2419             # Any backslashes in vi char classes are literal
2420             push(@re, "\\") if length($ch) > 1;
2421             push(@re, $ch);
2422             $in_chclass = 0 if $ch =~ /\]$/;
2423             }
2424             else {
2425             push(@re, (length $ch == 2) ? ($chmap{$ch} || $ch) :
2426             ($ch =~ /^\w$/) ? $ch :
2427             ("\\", $ch));
2428             $in_chclass = 1 if $ch eq '\[';
2429             }
2430             }
2431             my $re = join('', @re, @tail);
2432             $Vi_search_re = q{$re};
2433             }
2434              
2435             local $reverse = $Vi_search_reverse = ($c eq '/') ? 1 : 0;
2436             &do_vi_search();
2437             }
2438              
2439             sub F_ViRepeatSearch {
2440             my($n, $ord) = @_;
2441             my $c = pack('c', $ord);
2442             return &F_Ding unless defined $Vi_search_re;
2443             local $reverse = $Vi_search_reverse;
2444             $reverse ^= 1 if $c eq 'N';
2445             &do_vi_search();
2446             }
2447              
2448             sub F_ViEndSearch {}
2449              
2450             sub F_ViSearchBackwardDeleteChar {
2451             if ($line eq '') {
2452             # Backspaced past beginning of line - terminate search mode
2453             undef $line;
2454             }
2455             else {
2456             &F_BackwardDeleteChar(@_);
2457             }
2458             }
2459              
2460             =head3 F_ViChangeEntireLine
2461              
2462             Kill entire line and enter input mode
2463             =cut
2464             sub F_ViChangeEntireLine
2465             {
2466             &start_dot_buf(@_);
2467             kill_text(0, length($line), 1);
2468             &vi_input_mode;
2469             }
2470              
2471             =head3 F_ViChangeChar
2472              
2473             Kill characters and enter input mode
2474             =cut
2475             sub F_ViChangeChar
2476             {
2477             &start_dot_buf(@_);
2478             &F_DeleteChar(@_);
2479             &vi_input_mode;
2480             }
2481              
2482             sub F_ViReplaceChar
2483             {
2484             &start_dot_buf(@_);
2485             my $c = &getc_with_pending;
2486             $c = &getc_with_pending if $c eq "\cV"; # ctrl-V
2487             return &F_ViCommandMode if $c eq "\e";
2488             &end_dot_buf;
2489              
2490             local $InsertMode = 0;
2491             local $D = $D; # Preserve cursor position
2492             &F_SelfInsert(1, ord($c));
2493             }
2494              
2495             =head3 F_ViChangeLine
2496              
2497             Delete characteres from cursor to end of line and enter VI input mode.
2498              
2499             =cut
2500              
2501             sub F_ViChangeLine
2502             {
2503             &start_dot_buf(@_);
2504             &F_KillLine(@_);
2505             &vi_input_mode;
2506             }
2507              
2508             sub F_ViDeleteLine
2509             {
2510             &save_dot_buf(@_);
2511             &F_KillLine(@_);
2512             }
2513              
2514             sub F_ViPut
2515             {
2516             my($count) = @_;
2517             &save_dot_buf(@_);
2518             my $text2add = $KillBuffer x $count;
2519             my $ll = length($line);
2520             $D++;
2521             $D = $ll if $D > $ll;
2522             substr($line, $D, 0) = $KillBuffer x $count;
2523             $D += length($text2add) - 1;
2524             }
2525              
2526             sub F_ViPutBefore
2527             {
2528             &save_dot_buf(@_);
2529             &TextInsert($_[0], $KillBuffer);
2530             }
2531              
2532             sub F_ViYank
2533             {
2534             my($count, $ord) = @_;
2535             my $pos = &get_position($count, undef, $ord, $Vi_yank_patterns);
2536             &F_Ding if !defined $pos;
2537             if ($pos < 0) {
2538             # yy
2539             &F_ViYankLine;
2540             }
2541             else {
2542             my($from, $to) = ($pos > $D) ? ($D, $pos) : ($pos, $D);
2543             $KillBuffer = substr($line, $from, $to-$from);
2544             }
2545             }
2546              
2547             sub F_ViYankLine
2548             {
2549             $KillBuffer = $line;
2550             }
2551              
2552             sub F_ViInput
2553             {
2554             @_ = (1, ord('i')) if !@_;
2555             &start_dot_buf(@_);
2556             &vi_input_mode;
2557             }
2558              
2559             sub F_ViBeginInput
2560             {
2561             &start_dot_buf(@_);
2562             &F_BeginningOfLine;
2563             &vi_input_mode;
2564             }
2565              
2566             sub F_ViReplaceMode
2567             {
2568             &start_dot_buf(@_);
2569             $InsertMode = 0;
2570             $var_EditingMode = $var_EditingMode{'vi'};
2571             $Vi_mode = 1;
2572             }
2573             # The previous keystroke was an escape, but the sequence was not recognized
2574             # as a mapped sequence (like an arrow key). Enter vi comand mode and
2575             # process this keystroke.
2576             sub F_ViAfterEsc {
2577             my($n, $ord) = @_;
2578             &F_ViCommandMode;
2579             &do_command($var_EditingMode, 1, $ord);
2580             }
2581              
2582             sub F_ViAppend
2583             {
2584             &start_dot_buf(@_);
2585             &vi_input_mode;
2586             &F_ForwardChar;
2587             }
2588              
2589             sub F_ViAppendLine
2590             {
2591             &start_dot_buf(@_);
2592             &vi_input_mode;
2593             &F_EndOfLine;
2594             }
2595              
2596             sub F_ViCommandMode
2597             {
2598             $var_EditingMode = $var_EditingMode{'vicmd'};
2599             $Vi_mode = 1;
2600             }
2601              
2602             sub F_ViAcceptInsert {
2603             local $in_accept_line = 1;
2604             &F_ViEndInsert;
2605             &F_ViAcceptLine;
2606             }
2607              
2608             sub F_ViEndInsert
2609             {
2610             if ($Dot_buf) {
2611             if ($line eq '' and $Dot_buf->[0] eq 'i') {
2612             # We inserted nothing into an empty $line - assume it was a
2613             # &F_ViInput() call with no arguments, and don't save command.
2614             undef $Dot_buf;
2615             }
2616             else {
2617             # Regardless of which keystroke actually terminated this insert
2618             # command, replace it with an in the dot buffer.
2619             @{$Dot_buf}[-1] = "\e";
2620             &end_dot_buf;
2621             }
2622             }
2623             &F_ViCommandMode;
2624             # Move cursor back to the last inserted character, but not when
2625             # we're about to accept a line of input
2626             &F_BackwardChar(1) unless $in_accept_line;
2627             }
2628              
2629             sub F_ViDigit {
2630             my($count, $ord) = @_;
2631              
2632             my $n = 0;
2633             my $ord0 = ord('0');
2634             while (1) {
2635              
2636             $n *= 10;
2637             $n += $ord - $ord0;
2638              
2639             my $c = &getc_with_pending;
2640             return unless defined $c;
2641             $ord = ord($c);
2642             last unless $c =~ /^\d$/;
2643             }
2644              
2645             $n *= $count; # So 2d3w deletes six words
2646             $n = $rl_max_numeric_arg if $n > $rl_max_numeric_arg;
2647              
2648             &do_command($var_EditingMode, $n, $ord);
2649             }
2650              
2651             sub F_ViComplete {
2652             my($n, $ord) = @_;
2653              
2654             $Dot_state = savestate(); # Completion is undo-able
2655             undef $Dot_buf; # but not redo-able
2656              
2657             my $ch;
2658             while (1) {
2659              
2660             &F_Complete() or return;
2661              
2662             # Vi likes the cursor one character right of where emacs like it.
2663             &F_ForwardChar(1);
2664             rl_forced_update_display();
2665              
2666             # Look ahead to the next input keystroke.
2667             $ch = &getc_with_pending();
2668             last unless ord($ch) == $ord; # Not a '\' - quit.
2669              
2670             # Another '\' was typed - put the cursor back where &F_Complete left
2671             # it, and try again.
2672             &F_BackwardChar(1);
2673             $lastcommand = 'F_Complete'; # Play along with &F_Complete's kludge
2674             }
2675             unshift(@Pending, $ch); # Unget the lookahead keystroke
2676              
2677             # Successful completion - enter input mode with cursor beyond end of word.
2678             &vi_input_mode;
2679             }
2680              
2681             sub F_ViInsertPossibleCompletions {
2682             $Dot_state = savestate(); # Completion is undo-able
2683             undef $Dot_buf; # but not redo-able
2684              
2685             &complete_internal('*') or return;
2686              
2687             # Successful completion - enter input mode with cursor beyond end of word.
2688             &F_ForwardChar(1);
2689             &vi_input_mode;
2690             }
2691              
2692             sub F_ViPossibleCompletions {
2693              
2694             # List possible completions
2695             &complete_internal('?');
2696              
2697             # Enter input mode with cursor where we left off.
2698             &F_ForwardChar(1);
2699             &vi_input_mode;
2700             }
2701              
2702             sub F_CopyRegionAsKillClipboard {
2703             return clipboard_set($line) unless $line_rl_mark == $rl_HistoryIndex;
2704             &F_CopyRegionAsKill;
2705             clipboard_set($KillBuffer);
2706             }
2707              
2708             sub F_KillRegionClipboard {
2709             &F_KillRegion;
2710             clipboard_set($KillBuffer);
2711             }
2712              
2713             sub F_YankClipboard
2714             {
2715             remove_selection();
2716             my $in;
2717             if ($^O eq 'os2') {
2718             eval {
2719             require OS2::Process;
2720             $in = OS2::Process::ClipbrdText();
2721             $in =~ s/\r\n/\n/g; # With old versions, or what?
2722             }
2723             } elsif ($^O eq 'MSWin32') {
2724             eval {
2725             require Win32::Clipboard;
2726             $in = Win32::Clipboard::GetText();
2727             $in =~ s/\r\n/\n/g; # is this needed?
2728             }
2729             } else {
2730             my $mess;
2731             my $paste_fh;
2732             if ($ENV{RL_PASTE_CMD}) {
2733             $mess = "Reading from pipe `$ENV{RL_PASTE_CMD}'";
2734             open($paste_fh, "$ENV{RL_PASTE_CMD} |") or warn("$mess: $!"), return;
2735             } elsif (defined $HOME) {
2736             my $cutpastefile = File::Spec($HOME, '.rl_cutandpaste');
2737             $mess = "Reading from file `$cutpastefile'";
2738             open($paste_fh, '<:encoding(utf-8)', $cutpastefile)
2739             or warn("$mess: $!"), return;
2740             }
2741             if ($mess) {
2742             local $/;
2743             $in = <$paste_fh>;
2744             close $paste_fh or warn("$mess, closing: $!");
2745             }
2746             }
2747             if (defined $in) {
2748             $in =~ s/\n+$//;
2749             return &TextInsert($_[0], $in);
2750             }
2751             &TextInsert($_[0], $KillBuffer);
2752             }
2753              
2754             sub F_BeginUndoGroup {
2755             push @undoGroupS, $#undo;
2756             }
2757              
2758             sub F_EndUndoGroup {
2759             return F_Ding unless @undoGroupS;
2760             my $last = pop @undoGroupS;
2761             return unless $#undo > $last + 1;
2762             my $now = pop @undo;
2763             $#undo = $last;
2764             push @undo, $now;
2765             }
2766              
2767             sub F_DoNothing { # E.g., reset digit-argument
2768             1;
2769             }
2770              
2771             sub F_ForceMemorizeDigitArgument {
2772             $memorizedArg = shift;
2773             }
2774              
2775             sub F_MemorizeDigitArgument {
2776             return if defined $memorizedArg;
2777             $memorizedArg = shift;
2778             }
2779              
2780             sub F_UnmemorizeDigitArgument {
2781             $memorizedArg = undef;
2782             }
2783              
2784             sub F_MemorizePos {
2785             $memorizedPos = $D;
2786             }
2787              
2788             ###########################################################################
2789              
2790             # It is assumed that F_MemorizePos was called, then something was inserted,
2791             # then F_MergeInserts is called with a prefix argument to multiply
2792             # insertion by
2793              
2794             sub F_MergeInserts {
2795             my $n = shift;
2796             return F_Ding unless defined $memorizedPos and $n > 0;
2797             my ($b, $e) = ($memorizedPos, $D);
2798             ($b, $e) = ($e, $b) if $e < $b;
2799             if ($n) {
2800             substr($line, $e, 0) = substr($line, $b, $e - $b) x ($n - 1);
2801             } else {
2802             substr($line, $b, $e - $b) = '';
2803             }
2804             $D = $b + ($e - $b) * $n;
2805             }
2806              
2807             sub F_ResetDigitArgument {
2808             return F_Ding unless defined $memorizedArg;
2809             my $in = &getc_with_pending;
2810             return unless defined $in;
2811             my $ord = ord $in;
2812             local(*KeyMap) = $var_EditingMode;
2813             &do_command(*KeyMap, $memorizedArg, $ord);
2814             }
2815              
2816             sub F_BeginPasteGroup {
2817             my $c = shift;
2818             $memorizedArg = $c unless defined $memorizedArg;
2819             F_BeginUndoGroup(1);
2820             $memorizedPos = $D;
2821             }
2822              
2823             sub F_EndPasteGroup {
2824             my $c = $memorizedArg;
2825             undef $memorizedArg;
2826             $c = 1 unless defined $c;
2827             F_MergeInserts($c);
2828             F_EndUndoGroup(1);
2829             }
2830              
2831             sub F_BeginEditGroup {
2832             $memorizedArg = shift;
2833             F_BeginUndoGroup(1);
2834             }
2835              
2836             sub F_EndEditGroup {
2837             undef $memorizedArg;
2838             F_EndUndoGroup(1);
2839             }
2840              
2841             ###########################################################################
2842             =head2 Internal Routines
2843              
2844             =head3 get_window_size
2845              
2846             get_window_size([$redisplay])
2847              
2848             I
2849             or the GNU ReadLine library. As such, it may disappear and be replaced
2850             by the corresponding L routines.>
2851              
2852             Causes a query to get the terminal width. If the terminal width can't
2853             be obtained, nothing is done. Otherwise...
2854              
2855             =over
2856              
2857             =item * Set I<$rl_screen_width> and to the current screen width.
2858             I<$rl_margin> is then set to be 1/3 of I<$rl_screen_width>.
2859              
2860             =item * any window-changeing hooks stored in array I<@winchhooks> are
2861             run.
2862              
2863             =item * I is set to run this routine. Any routines set are
2864             lost. A better behavior would be to add existing hooks to
2865             I<@winchhooks>, but hey, this routine is deprecated.
2866              
2867             =item * If I<$redisplay> is passed and is true, then a redisplay of
2868             the input line is done by calling I.
2869              
2870             =back
2871              
2872             =cut
2873              
2874             sub get_window_size
2875             {
2876             my $redraw = shift;
2877              
2878             # Preserve $! etc; the rest for hooks
2879             local($., $@, $!, $^E, $?);
2880              
2881             my ($num_cols,$num_rows) = (undef, undef);
2882             eval {
2883             ($num_cols,$num_rows) = Term::ReadKey::GetTerminalSize($term_OUT);
2884             };
2885             return unless defined($num_cols) and defined($num_rows);
2886             $rl_screen_width = $num_cols - $rl_correct_sw
2887             if defined($num_cols) && $num_cols;
2888             $rl_margin = int($rl_screen_width/3);
2889             if (defined $redraw) {
2890             rl_forced_update_display();
2891             }
2892              
2893             for my $hook (@winchhooks) {
2894             eval {&$hook()}; warn $@ if $@ and $^W;
2895             }
2896             }
2897              
2898              
2899             sub get_ornaments_selected {
2900             return if @$rl_term_set >= 6;
2901             local $^W=0;
2902             my $Orig = Term::ReadLine::TermCap::ornaments(__PACKAGE__);
2903             eval {
2904             # Term::ReadLine does not expose its $terminal, so make another
2905             require Term::Cap;
2906             my $terminal = Tgetent Term::Cap ({OSPEED=>9600});
2907             # and be sure the terminal supports highlighting
2908             $terminal->Trequire('mr');
2909             };
2910             if (!$@ and $Orig ne ',,,'){
2911             my @set = @$rl_term_set;
2912              
2913             Term::ReadLine::TermCap::ornaments(__PACKAGE__,
2914             join(',',
2915             (split(/,/, $Orig))[0,1])
2916             . ',mr,me') ;
2917             @set[4,5] = @$rl_term_set[2,3];
2918             Term::ReadLine::TermCap::ornaments(__PACKAGE__, $Orig);
2919             @$rl_term_set = @set;
2920             } else {
2921             @$rl_term_set[4,5] = @$rl_term_set[2,3];
2922             }
2923             }
2924              
2925             =head3 readline
2926              
2927             &readline::readline($prompt, $default)>
2928              
2929             The main routine to call interactively read lines. Parameter
2930             I<$prompt> is the text you want to prompt with If it is empty string,
2931             no preceding prompt text is given. It is I a default value of
2932             "INPUT> " is used.
2933              
2934             Parameter I<$default> is the default value; it can be can be
2935             omitted. The next input line is returned or I on EOF.
2936              
2937             =cut
2938              
2939             sub readline($;$)
2940             {
2941             no warnings 'once';
2942             $Term::ReadLine::Perl5::term->register_Tk
2943             if not $Term::ReadLine::registered and $Term::ReadLine::toloop
2944             and defined &Tk::DoOneEvent;
2945             if ($stdin_not_tty) {
2946             local $/ = "\n";
2947             return undef if !defined($line = <$term_IN>);
2948             chomp($line);
2949             return $line;
2950             }
2951              
2952             $old = select $term_OUT;
2953             $oldbar = $|;
2954             local($|) = 1;
2955             local($input);
2956              
2957             ## prompt should be given to us....
2958             $prompt = defined($_[0]) ? $_[0] : 'INPUT> ';
2959              
2960             # Try to move cursor to the beginning of the next line if this line
2961             # contains anything.
2962              
2963             # On DOSish 80-wide console
2964             # perl -we "print 1 x shift, qq(\b2\r3); sleep 2" 79
2965             # prints 3 on the same line,
2966             # perl -we "print 1 x shift, qq(\b2\r3); sleep 2" 80
2967             # on the next; $rl_screen_width is 79.
2968              
2969             # on XTerm one needs to increase the number by 1.
2970              
2971             print $term_OUT ' ' x ($rl_screen_width - !$rl_last_pos_can_backspace) . "\b \r"
2972             if $rl_scroll_nextline;
2973              
2974             if ($dumb_term) {
2975             return Term::ReadLine::Perl5::Dumb::readline($prompt, $term_IN,
2976             $term_OUT);
2977             }
2978              
2979             # test if we resume an 'Operate' command
2980             if ($rl_OperateCount > 0 && (!defined $_[1] || $_[1] eq '')) {
2981             ## it's from a valid previous 'Operate' command and
2982             ## user didn't give a default line
2983             ## we leave $rl_HistoryIndex untouched
2984             $line = $rl_History[$rl_HistoryIndex];
2985             } else {
2986             ## set history pointer at the end of history
2987             $rl_HistoryIndex = $#rl_History + 1;
2988             $rl_OperateCount = 0;
2989             $line = defined $_[1] ? $_[1] : '';
2990             }
2991             $rl_OperateCount-- if $rl_OperateCount > 0;
2992              
2993             $line_for_revert = $line;
2994              
2995             # I don't think we need to do this, actually...
2996             # while (&ioctl(STDIN,$FIONREAD,$fion))
2997             # {
2998             # local($n_chars_available) = unpack ($fionread_t, $fion);
2999             # ## print "n_chars = $n_chars_available\n";
3000             # last if $n_chars_available == 0;
3001             # $line .= getc_with_pending; # should we prepend if $rl_start_default_at_beginning?
3002             # }
3003              
3004             $D = $rl_start_default_at_beginning ? 0 : length($line); ## set dot.
3005             $LastCommandKilledText = 0; ## heck, was no last command.
3006             $lastcommand = ''; ## Well, there you go.
3007             $line_rl_mark = -1;
3008              
3009             ##
3010             ## some stuff for rl_redisplay.
3011             ##
3012             $lastredisplay = ''; ## Was no last redisplay for this time.
3013             $lastlen = length($lastredisplay);
3014             $lastpromptlen = 0;
3015             $lastdelta = 0; ## Cursor was nowhere
3016             $si = 0; ## Want line to start left-justified
3017             $force_redraw = 1; ## Want to display with brute force.
3018             if (!eval {SetTTY()}) { ## Put into raw mode.
3019             warn $@ if $@;
3020             $dumb_term = 1;
3021             return Term::ReadLine::Perl5::Dumb::readline($prompt, $term_IN,
3022             $term_OUT);
3023             }
3024              
3025             *KeyMap = $var_EditingMode;
3026             undef($AcceptLine); ## When set, will return its value.
3027             undef($ReturnEOF); ## ...unless this on, then return undef.
3028             @Pending = (); ## Contains characters to use as input.
3029             @undo = (); ## Undo history starts empty for each line.
3030             @undoGroupS = (); ## Undo groups start empty for each line.
3031             undef $memorizedArg; ## No digitArgument memorized
3032             undef $memorizedPos; ## No position memorized
3033              
3034             undef $Vi_undo_state;
3035             undef $Vi_undo_all_state;
3036              
3037             # We need to do some additional initialization for vi mode.
3038             # RS: bug reports/platform issues are welcome: russ@dvns.com
3039             if ($KeyMap{'name'} eq 'vi_keymap'){
3040             &F_ViInput();
3041             if ($rl_vi_replace_default_on_insert){
3042             local $^W=0;
3043             my $Orig = Term::ReadLine::TermCap::ornaments(__PACKAGE__);
3044             eval {
3045             # Term::ReadLine does not expose its $terminal, so make another
3046             require Term::Cap;
3047             my $terminal = Tgetent Term::Cap ({OSPEED=>9600});
3048             # and be sure the terminal supports highlighting
3049             $terminal->Trequire('mr');
3050             };
3051             if (!$@ and $Orig ne ',,,'){
3052             Term::ReadLine::TermCap::ornaments(__PACKAGE__,
3053             join(',',
3054             (split(/,/, $Orig))[0,1])
3055             . ',mr,me');
3056             }
3057             my $F_SelfInsert_Real = \&F_SelfInsert;
3058             *F_SelfInsert = sub {
3059             Term::ReadLine::TermCap::ornaments(__PACKAGE__);
3060             &F_ViChangeEntireLine;
3061             local $^W=0;
3062             *F_SelfInsert = $F_SelfInsert_Real;
3063             &F_SelfInsert;
3064             };
3065             my $F_ViEndInsert_Real = \&F_ViEndInsert;
3066             *F_ViEndInsert = sub {
3067             Term::ReadLine::TermCap::ornaments(__PACKAGE__, $Orig);
3068             local $^W=0;
3069             *F_SelfInsert = $F_SelfInsert_Real;
3070             *F_ViEndInsert = $F_ViEndInsert_Real;
3071             &F_ViEndInsert;
3072             $force_redraw = 1;
3073             rl_redisplay();
3074             };
3075             }
3076             }
3077              
3078             if ($rl_default_selected) {
3079             redisplay_high();
3080             } else {
3081             ## Show the line (prompt+default at this point).
3082             rl_redisplay();
3083             }
3084              
3085             # pretend input if we 'Operate' on more than one line
3086             &F_OperateAndGetNext($rl_OperateCount) if $rl_OperateCount > 0;
3087              
3088             $rl_first_char = 1;
3089             while (!defined($AcceptLine)) {
3090             ## get a character of input
3091             $input = &getc_with_pending(); # bug in debugger, returns 42. - No more!
3092              
3093             unless (defined $input) {
3094             # XXX What to do??? Until this is clear, just pretend we got EOF
3095             $AcceptLine = $ReturnEOF = 1;
3096             last;
3097             }
3098             preserve_state();
3099              
3100             $ThisCommandKilledText = 0;
3101             ##print "\n\rline is @$D:[$line]\n\r"; ##DEBUG
3102             my $cmd = get_command($var_EditingMode, ord($input));
3103             if ( $rl_first_char && $cmd =~ /^F_(SelfInsert$|Yank)/
3104             && length $line && $rl_default_selected ) {
3105             # (Backward)?DeleteChar special-cased in the code.
3106             $line = '';
3107             $D = 0;
3108             $cmd = 'F_BackwardDeleteChar' if $cmd eq 'F_DeleteChar';
3109             }
3110             undef $doingNumArg;
3111              
3112             # Execute input
3113             eval { &$cmd(1, ord($input)); };
3114              
3115             $rl_first_char = 0;
3116             $lastcommand = $cmd;
3117             *KeyMap = $var_EditingMode; # JP: added
3118              
3119             # In Vi command mode, don't position the cursor beyond the last
3120             # character of the line buffer.
3121             &F_BackwardChar(1) if $Vi_mode and $line ne ''
3122             and &at_end_of_line and $KeyMap{'name'} eq 'vicmd_keymap';
3123              
3124             rl_redisplay();
3125             $LastCommandKilledText = $ThisCommandKilledText;
3126             }
3127              
3128             undef @undo; ## Release the memory.
3129             undef @undoGroupS; ## Release the memory.
3130             &ResetTTY; ## Restore the tty state.
3131             $| = $oldbar;
3132             select $old;
3133             return undef if defined($ReturnEOF);
3134             #print STDOUT "|al=`$AcceptLine'";
3135             $AcceptLine; ## return the line accepted.
3136             }
3137              
3138             sub SetTTY {
3139             return if $dumb_term || $stdin_not_tty;
3140             #return system 'stty raw -echo' if defined &DB::DB;
3141             Term::ReadKey::ReadMode(4, $term_IN);
3142             if ($^O eq 'MSWin32') {
3143             # If we reached this, Perl isn't cygwin; Enter sends \r; thus
3144             # we need binmode XXXX Do we need to undo??? $term_IN is most
3145             # probably private now...
3146             binmode $term_IN;
3147             }
3148             return 1;
3149             }
3150              
3151             sub ResetTTY {
3152             return if $dumb_term || $stdin_not_tty;
3153             return Term::ReadKey::ReadMode(0, $term_IN);
3154             }
3155              
3156             =head3 substr_with_props
3157              
3158             C
3159              
3160             Gives the I of C<$prompt.$string> with embedded face-change
3161             commands.
3162              
3163             =cut
3164              
3165             sub substr_with_props {
3166             my ($p, $s, $from, $len, $ket, $bsel, $esel) = @_;
3167             my $lp = length $p;
3168              
3169             defined $from or $from = 0;
3170             defined $len or $len = length($p) + length($s) - $from;
3171             unless (defined $ket) {
3172             warn 'bug in Term::ReadLine::Perl5, please report to its author';
3173             $ket = '';
3174             }
3175             # We may draw over to put cursor in a correct position:
3176             $ket = '' if $len < length($p) + length($s) - $from; # Not redrawn
3177              
3178             if ($from >= $lp) {
3179             $p = '';
3180             my $start = $from - $lp;
3181             if ($start < length($s)) {
3182             $s = substr $s, $start;
3183             $lp = 0;
3184             } else {
3185             return '';
3186             }
3187             } else {
3188             $p = substr $p, $from;
3189             $lp -= $from;
3190             $from = 0;
3191             }
3192             $s = substr $s, 0, $len - $lp;
3193             $p =~ s/^(\s*)//; my $bs = $1;
3194             $p =~ s/(\s*)$//; my $as = $1;
3195             $p = $rl_term_set->[0] . $p . $rl_term_set->[1] if length $p;
3196             $p = "$bs$p$as";
3197             $ket = chop $s if $ket;
3198             if (defined $bsel and $bsel != $esel) {
3199             $bsel = $len if $bsel > $len;
3200             $esel = $len if $esel > $len;
3201             }
3202             if (defined $bsel and $bsel != $esel) {
3203             get_ornaments_selected;
3204             $bsel -= $lp; $esel -= $lp;
3205             my ($pre, $sel, $post) =
3206             (substr($s, 0, $bsel),
3207             substr($s, $bsel, $esel-$bsel),
3208             substr($s, $esel));
3209             $pre = $rl_term_set->[2] . $pre . $rl_term_set->[3] if length $pre;
3210             $sel = $rl_term_set->[4] . $sel . $rl_term_set->[5] if length $sel;
3211             $post = $rl_term_set->[2] . $post . $rl_term_set->[3] if length $post;
3212             $s = "$pre$sel$post"
3213             } else {
3214             $s = $rl_term_set->[2] . $s . $rl_term_set->[3] if length $s;
3215             }
3216              
3217             if (!$lp) { # Should not happen...
3218             return $s;
3219             } elsif (!length $s) { # Should not happen
3220             return $p;
3221             } else { # Do not underline spaces in the prompt
3222             return "$p$s"
3223             . (length $ket ? ($rl_term_set->[0] . $ket . $rl_term_set->[1]) : '');
3224             }
3225             }
3226              
3227             sub redisplay_high {
3228             get_ornaments_selected();
3229             @$rl_term_set[2,3,4,5] = @$rl_term_set[4,5,2,3];
3230             ## Show the line, default inverted.
3231             rl_redisplay();
3232             @$rl_term_set[2,3,4,5] = @$rl_term_set[4,5,2,3];
3233             $force_redraw = 1;
3234             }
3235              
3236             =head3 rl_redisplay
3237              
3238             B
3239              
3240             Updates the screen to reflect the current value of global C<$line>.
3241              
3242             For the purposes of this routine, we prepend the prompt to a local
3243             copy of C<$line> so that we display the prompt as well. We then
3244             modify it to reflect that some characters have different sizes. That
3245             is, control-C is represented as C<^C>, tabs are expanded, etc.
3246              
3247             This routine is somewhat complicated by two-byte characters.... must
3248             make sure never to try do display just half of one.
3249              
3250             This is some nasty code.
3251              
3252             =cut
3253              
3254             sub rl_redisplay()
3255             {
3256             my ($thislen, $have_bra);
3257             my($dline) = $prompt . $line;
3258             local($D) = $D + length($prompt);
3259             my ($bsel, $esel);
3260             if (defined pos $line) {
3261             $bsel = (pos $line) + length $prompt;
3262             }
3263             my ($have_ket) = '';
3264              
3265             ##
3266             ## If the line contains anything that might require special processing
3267             ## for displaying (such as tabs, control characters, etc.), we will
3268             ## take care of that now....
3269             ##
3270             if ($dline =~ m/[^\x20-\x7e]/)
3271             {
3272             local($new, $Dinc, $c) = ('', 0);
3273              
3274             ## Look at each character of $dline in turn.....
3275             for (my $i = 0; $i < length($dline); $i++) {
3276             $c = substr($dline, $i, 1);
3277              
3278             ## A tab to expand...
3279             if ($c eq "\t") {
3280             $c = ' ' x (8 - (($i-length($prompt)) % 8));
3281              
3282             ## A control character....
3283             } elsif ($c =~ tr/\000-\037//) {
3284             $c = sprintf("^%c", ord($c)+ord('@'));
3285              
3286             ## the delete character....
3287             } elsif (ord($c) == 127) {
3288             $c = '^?';
3289             }
3290             $new .= $c;
3291              
3292             ## Bump over $D if this char is expanded and left of $D.
3293             $Dinc += length($c) - 1 if (length($c) > 1 && $i < $D);
3294             ## Bump over $bsel if this char is expanded and left of $bsel.
3295             $bsel += length($c) - 1 if (defined $bsel && length($c) > 1 && $i < $bsel);
3296             }
3297             $dline = $new;
3298             $D += $Dinc;
3299             }
3300              
3301             ##
3302             ## Now $dline is what we'd like to display (with a prepended prompt)
3303             ## $D is the position of the cursor on it.
3304             ##
3305             ## If it's too long to fit on the line, we must decide what we can fit.
3306             ##
3307             ## If we end up moving the screen index ($si) [index of the leftmost
3308             ## character on the screen], to some place other than the front of the
3309             ## the line, we'll have to make sure that it's not on the first byte of
3310             ## a 2-byte character, 'cause we'll be placing a '<' marker there, and
3311             ## that would screw up the 2-byte character.
3312             ##
3313             ## $si is preserved between several displays (if possible).
3314             ##
3315             ## Similarly, if the line needs chopped off, we make sure that the
3316             ## placement of the tailing '>' won't screw up any 2-byte character in
3317             ## the vicinity.
3318              
3319             # Now $si keeps the value from previous display
3320             if ($D == length($prompt) # If prompts fits exactly, show only if need not show trailing '>'
3321             and length($prompt) < $rl_screen_width - (0 != length $dline)) {
3322             $si = 0; ## prefer displaying the whole prompt
3323             } elsif ($si >= $D) { # point to the left of what was displayed
3324             $si = &max(0, $D - $rl_margin);
3325             $si-- if $si > 0 && $si != length($prompt) && !&OnSecondByte($si);
3326             } elsif ($si + $rl_screen_width <= $D) { # Point to the right of ...
3327             $si = &min(length($dline), ($D - $rl_screen_width) + $rl_margin);
3328             $si-- if $si > 0 && $si != length($prompt) && !&OnSecondByte($si);
3329             } elsif (length($dline) - $si < $rl_screen_width - $rl_margin and $si) {
3330             # Too little of the line shown
3331             $si = &max(0, length($dline) - $rl_screen_width + 3);
3332             $si-- if $si > 0 && $si != length($prompt) && !&OnSecondByte($si);
3333             } else {
3334             ## Fine as-is.... don't need to change $si.
3335             }
3336             $have_bra = 1 if $si != 0; # Need the "chopped-off" marker
3337              
3338             $thislen = &min(length($dline) - $si, $rl_screen_width);
3339             if ($si + $thislen < length($dline)) {
3340             ## need to place a '>'... make sure to place on first byte.
3341             $thislen-- if &OnSecondByte($si+$thislen-1);
3342             substr($dline, $si+$thislen-1,1) = '>';
3343             $have_ket = 1;
3344             }
3345              
3346             ##
3347             ## Now know what to display.
3348             ## Must get substr($dline, $si, $thislen) on the screen,
3349             ## with the cursor at $D-$si characters from the left edge.
3350             ##
3351             $dline = substr($dline, $si, $thislen);
3352             $delta = $D - $si; ## delta is cursor distance from beginning of $dline.
3353             if (defined $bsel) { # Highlight the selected part
3354             $bsel -= $si;
3355             $esel = $delta;
3356             ($bsel, $esel) = ($esel, $bsel) if $bsel > $esel;
3357             $bsel = 0 if $bsel < 0;
3358             if ($have_ket) {
3359             $esel = $thislen - 1 if $esel > $thislen - 1;
3360             } else {
3361             $esel = $thislen if $esel > $thislen;
3362             }
3363             }
3364             if ($si >= length($prompt)) { # Keep $dline for $lastredisplay...
3365             $prompt = ($have_bra ? "<" : "");
3366             $dline = substr $dline, 1 if length($dline); # After prompt
3367             $bsel = 1 if defined $bsel and $bsel == 0;
3368             } else {
3369             $dline = substr($dline, (length $prompt) - $si);
3370             $prompt = substr($prompt,$si);
3371             substr($prompt, 0, 1) = '<' if $si > 0;
3372             }
3373             # Now $dline is the part after the prompt...
3374              
3375             ##
3376             ## Now must output $dline, with cursor $delta spaces from left of TTY
3377             ##
3378              
3379             local ($\, $,) = ('','');
3380              
3381             ##
3382             ## If $force_redraw is not set, we can attempt to optimize the redisplay
3383             ## However, if we don't happen to find an easy way to optimize, we just
3384             ## fall through to the brute-force method of re-drawing the whole line.
3385             ##
3386             if (not $force_redraw and not defined $bsel)
3387             {
3388             ## can try to optimize here a bit.
3389              
3390             ## For when we only need to move the cursor
3391             if ($lastredisplay eq $dline and $lastpromptlen == length $prompt) {
3392             ## If we need to move forward, just overwrite as far as we need.
3393             if ($lastdelta < $delta) {
3394             print $term_OUT
3395             substr_with_props($prompt, $dline,
3396             $lastdelta, $delta-$lastdelta, $have_ket);
3397             ## Need to move back.
3398             } elsif($lastdelta > $delta) {
3399             ## Two ways to move back... use the fastest. One is to just
3400             ## backspace the proper amount. The other is to jump to the
3401             ## the beginning of the line and overwrite from there....
3402             my $out = substr_with_props($prompt, $dline, 0, $delta, $have_ket);
3403             if ($lastdelta - $delta <= length $out) {
3404             print $term_OUT "\b" x ($lastdelta - $delta);
3405             } else {
3406             print $term_OUT "\r", $out;
3407             }
3408             }
3409             ($lastlen, $lastredisplay, $lastdelta, $lastpromptlen)
3410             = ($thislen, $dline, $delta, length $prompt);
3411             # print $term_OUT "\a"; # Debugging
3412             return;
3413             }
3414              
3415             ## for when we've just added stuff to the end
3416             if ($thislen > $lastlen &&
3417             $lastdelta == $lastlen &&
3418             $delta == $thislen &&
3419             $lastpromptlen == length($prompt) &&
3420             substr($dline, 0, $lastlen - $lastpromptlen) eq $lastredisplay)
3421             {
3422             print $term_OUT substr_with_props($prompt, $dline,
3423             $lastdelta, undef, $have_ket);
3424             # print $term_OUT "\a"; # Debugging
3425             ($lastlen, $lastredisplay, $lastdelta, $lastpromptlen)
3426             = ($thislen, $dline, $delta, length $prompt);
3427             return;
3428             }
3429              
3430             ## There is much more opportunity for optimizing.....
3431             ## something to work on later.....
3432             }
3433              
3434             ##
3435             ## Brute force method of redisplaying... redraw the whole thing.
3436             ##
3437              
3438             print $term_OUT "\r", substr_with_props($prompt, $dline, 0, undef, $have_ket, $bsel, $esel);
3439             my $back = length ($dline) + length ($prompt) - $delta;
3440             $back += $lastlen - $thislen,
3441             print $term_OUT ' ' x ($lastlen - $thislen) if $lastlen and $lastlen > $thislen;
3442              
3443             if ($back) {
3444             my $out = substr_with_props($prompt, $dline, 0, $delta, $have_ket, $bsel, $esel);
3445             if ($back <= length $out and not defined $bsel) {
3446             print $term_OUT "\b" x $back;
3447             } else {
3448             print $term_OUT "\r", $out;
3449             }
3450             }
3451              
3452             ($lastlen, $lastredisplay, $lastdelta, $lastpromptlen)
3453             = ($thislen, $dline, $delta, length $prompt);
3454              
3455             $force_redraw = 0;
3456             }
3457              
3458             =head3 redisplay
3459              
3460             B[(I<$prompt>)]
3461              
3462             If an argument I<$prompt> is given, it is used instead of the prompt.
3463             Updates the screen to reflect the current value of global C<$line> via
3464             L.
3465             =cut
3466              
3467             sub redisplay(;$)
3468             {
3469             ## local $line has prompt also; take that into account with $D.
3470             local($prompt) = defined($_[0]) ? $_[0] : $prompt;
3471             $prompt = '' unless defined($prompt);
3472             rl_redisplay();
3473              
3474             }
3475              
3476             sub min($$) { $_[0] < $_[1] ? $_[0] : $_[1]; }
3477              
3478             sub getc_with_pending {
3479              
3480             my $key = @Pending ? shift(@Pending) : &$rl_getc;
3481              
3482             # Save keystrokes for vi '.' command
3483             push(@$Dot_buf, $key) if $Dot_buf;
3484              
3485             $key;
3486             }
3487              
3488             =head3 get_command
3489              
3490             C
3491              
3492             If the C<*keymap>) has an entry for C<$ord_command_char>, it is returned.
3493             Otherwise, the default command in C<$Keymap{'default'}> is returned if that
3494             exists. If C<$Keymap{'default'}> is false, C<'F_Ding'> is returned.
3495              
3496             =cut
3497              
3498             sub get_command
3499             {
3500             local *KeyMap = shift;
3501             my ($key) = @_;
3502             my $cmd = defined($KeyMap[$key]) ? $KeyMap[$key]
3503             : ($KeyMap{'default'} || 'F_Ding');
3504             if (!defined($cmd) || $cmd eq ''){
3505             warn "internal error (key=$key)";
3506             $cmd = 'F_Ding';
3507             }
3508             $cmd
3509             }
3510              
3511             =head3 do_command
3512              
3513             C
3514              
3515             If the C<*keymap> has an entry for C<$key>, it is executed.
3516             Otherwise, the default command for the keymap is executed.
3517              
3518             =cut
3519              
3520             sub do_command
3521             {
3522             my ($keymap, $count, $key) = @_;
3523             my $cmd = get_command($keymap, $key);
3524              
3525             local *KeyMap = $keymap; # &$cmd may expect it...
3526             &$cmd($count, $key);
3527             $lastcommand = $cmd;
3528             }
3529              
3530             =head3 savestate
3531              
3532             C
3533              
3534             Save whatever state we wish to save as an anonymous array. The only
3535             other function that needs to know about its encoding is
3536             getstate/preserve_state.
3537              
3538             =cut
3539              
3540             sub savestate
3541             {
3542             [$D, $si, $LastCommandKilledText, $KillBuffer, $line, @_];
3543             }
3544              
3545             =head3 preserve_state
3546              
3547             C
3548              
3549             =cut
3550              
3551             sub preserve_state {
3552             return if $Vi_mode;
3553             push(@undo, savestate()), return unless @undo;
3554             my $last = $undo[-1];
3555             my @only_movement;
3556             if ( #$last->[1] == $si and $last->[2] eq $LastCommandKilledText
3557             # and $last->[3] eq $KillBuffer and
3558             $last->[4] eq $line ) {
3559             # Only position changed; remove old only-position-changed records
3560             pop @undo if $undo[-1]->[5];
3561             @only_movement = 1;
3562             }
3563             push(@undo, savestate(@only_movement));
3564             }
3565              
3566             sub remove_selection {
3567             if ( $rl_first_char && length $line && $rl_default_selected ) {
3568             $line = '';
3569             $D = 0;
3570             return 1;
3571             }
3572             if ($rl_delete_selection and defined pos $line and $D != pos $line) {
3573             kill_text(pos $line, $D);
3574             return 1;
3575             }
3576             return;
3577             }
3578              
3579             sub max($$) { $_[0] > $_[1] ? $_[0] : $_[1]; }
3580             sub isupper($) { ord($_[0]) >= ord('A') && ord($_[0]) <= ord('Z'); }
3581             sub islower($) { ord($_[0]) >= ord('a') && ord($_[0]) <= ord('z'); }
3582              
3583             =head3 OnSecondByte
3584              
3585             B(I<$index>)
3586              
3587             Returns true if the byte at I<$index> into I<$line> is the second byte
3588             of a two-byte character.
3589              
3590             =cut
3591              
3592             sub OnSecondByte
3593             {
3594             return 0 if !$_rl_japanese_mb || $_[0] == 0 || $_[0] == length($line);
3595              
3596             die 'internal error' if $_[0] > length($line);
3597              
3598             ##
3599             ## must start looking from the beginning of the line .... can
3600             ## have one- and two-byte characters interspersed, so can't tell
3601             ## without starting from some know location.....
3602             ##
3603             for (my $i = 0; $i < $_[0]; $i++) {
3604             next if ord(substr($line, $i, 1)) < 0x80;
3605             ## We have the first byte... must bump up $i to skip past the 2nd.
3606             ## If that one we're skipping past is the index, it should be changed
3607             ## to point to the first byte of the pair (therefore, decremented).
3608             return 1 if ++$i == $_[0];
3609             }
3610             0; ## seemed to be OK.
3611             }
3612              
3613              
3614             =head3 CharSize
3615              
3616             BC(I<$index>)
3617              
3618             Returns the size of the character at the given I<$index> in the
3619             current line. Most characters are just one byte in length. However,
3620             if the byte at the index and the one after both have the high bit set
3621             and I<$_rl_japanese_mb> is set, those two bytes are one character of
3622             size two.
3623              
3624             Assumes that I<$index> points to the first of a 2-byte char if not
3625             pointing to a 1-byte char.
3626              
3627             TODO: handle Unicode
3628              
3629             =cut
3630             sub CharSize
3631             {
3632             my $index = shift;
3633             return 2 if $_rl_japanese_mb &&
3634             ord(substr($line, $index, 1)) >= 0x80 &&
3635             ord(substr($line, $index+1, 1)) >= 0x80;
3636             1;
3637             }
3638              
3639             sub GetTTY
3640             {
3641             $base_termios = $termios; # make it long enough
3642             &ioctl($term_IN,$TCGETS,$base_termios) || die "Can't ioctl TCGETS: $!";
3643             }
3644              
3645             sub XonTTY
3646             {
3647             # I don't know which of these I actually need to do this to, so we'll
3648             # just cover all bases.
3649              
3650             &ioctl($term_IN,$TCXONC,$TCOON); # || die "Can't ioctl TCXONC STDIN: $!";
3651             &ioctl($term_OUT,$TCXONC,$TCOON); # || die "Can't ioctl TCXONC STDOUT: $!";
3652             }
3653              
3654             sub ___SetTTY
3655             {
3656             if ($DEBUG) {
3657             print "before ResetTTY\n\r";
3658             system 'stty -a';
3659             }
3660              
3661             &XonTTY;
3662              
3663             &GetTTY
3664             if !defined($base_termios);
3665              
3666             @termios = unpack($termios_t,$base_termios);
3667             $termios[$TERMIOS_IFLAG] |= $TERMIOS_READLINE_ION;
3668             $termios[$TERMIOS_IFLAG] &= ~$TERMIOS_READLINE_IOFF;
3669             $termios[$TERMIOS_OFLAG] |= $TERMIOS_READLINE_OON;
3670             $termios[$TERMIOS_OFLAG] &= ~$TERMIOS_READLINE_OOFF;
3671             $termios[$TERMIOS_LFLAG] |= $TERMIOS_READLINE_LON;
3672             $termios[$TERMIOS_LFLAG] &= ~$TERMIOS_READLINE_LOFF;
3673             $termios[$TERMIOS_VMIN] = 1;
3674             $termios[$TERMIOS_VTIME] = 0;
3675             $termios = pack($termios_t,@termios);
3676             &ioctl($term_IN,$TCSETS,$termios) || die "Can't ioctl TCSETS: $!";
3677              
3678             if ($DEBUG) {
3679             print "after ResetTTY\n\r";
3680             system 'stty -a';
3681             }
3682             }
3683              
3684             sub normal_tty_mode
3685             {
3686             return if $stdin_not_tty || $dumb_term || !$initialized;
3687             &XonTTY;
3688             &GetTTY if !defined($base_termios);
3689             &ResetTTY;
3690             }
3691              
3692             sub ___ResetTTY
3693             {
3694             if ($DEBUG) {
3695             print "before ResetTTY\n\r";
3696             system 'stty -a';
3697             }
3698              
3699             @termios = unpack($termios_t,$base_termios);
3700             $termios[$TERMIOS_IFLAG] |= $TERMIOS_NORMAL_ION;
3701             $termios[$TERMIOS_IFLAG] &= ~$TERMIOS_NORMAL_IOFF;
3702             $termios[$TERMIOS_OFLAG] |= $TERMIOS_NORMAL_OON;
3703             $termios[$TERMIOS_OFLAG] &= ~$TERMIOS_NORMAL_OOFF;
3704             $termios[$TERMIOS_LFLAG] |= $TERMIOS_NORMAL_LON;
3705             $termios[$TERMIOS_LFLAG] &= ~$TERMIOS_NORMAL_LOFF;
3706             $termios = pack($termios_t,@termios);
3707             &ioctl($term_IN,$TCSETS,$termios) || die "Can't ioctl TCSETS: $!";
3708              
3709             if ($DEBUG) {
3710             print "after ResetTTY\n\r";
3711             system 'stty -a';
3712             }
3713             }
3714              
3715             =head3 WordBreak
3716              
3717             C
3718              
3719             Returns true if the character at I into $line is a basic word
3720             break character, false otherwise.
3721              
3722             =cut
3723              
3724             sub WordBreak
3725             {
3726             index($rl_basic_word_break_characters,
3727             substr($line,$_[0],1)) != -1;
3728             }
3729              
3730             sub getstate
3731             {
3732             ($D, $si, $LastCommandKilledText, $KillBuffer, $line) = @{$_[0]};
3733             $ThisCommandKilledText = $LastCommandKilledText;
3734             }
3735              
3736             =head3 kill_text
3737              
3738             kills from D=$_[0] to $_[1] (to the killbuffer if $_[2] is true)
3739              
3740             =cut
3741              
3742             sub kill_text
3743             {
3744             my($from, $to, $save) = (&min($_[0], $_[1]), &max($_[0], $_[1]), $_[2]);
3745             my $len = $to - $from;
3746             if ($save) {
3747             $KillBuffer = '' if !$LastCommandKilledText;
3748             if ($from < $LastCommandKilledText - 1) {
3749             $KillBuffer = substr($line, $from, $len) . $KillBuffer;
3750             } else {
3751             $KillBuffer .= substr($line, $from, $len);
3752             }
3753             $ThisCommandKilledText = 1 + $from;
3754             }
3755             substr($line, $from, $len) = '';
3756              
3757             ## adjust $D
3758             if ($D > $from) {
3759             $D -= $len;
3760             $D = $from if $D < $from;
3761             }
3762             }
3763              
3764              
3765             =head3 at_end_of_line
3766              
3767             Returns true if $D at the end of the line.
3768              
3769             =cut
3770              
3771             sub at_end_of_line
3772             {
3773             ($D + &CharSize($D)) == (length($line) + 1);
3774             }
3775              
3776             =head3 changecase
3777              
3778             changecase($count, $up_down_caps)
3779              
3780             Translated from GNU's I.
3781              
3782             If I<$up_down_caps> is 'up' to upcase I<$count> words;
3783             'down' to downcase them, or something else to capitalize them.
3784              
3785             If I<$count> is negative, the dot is not moved.
3786              
3787             =cut
3788             sub changecase
3789             {
3790             my $op = $_[1];
3791              
3792             my ($start, $state, $c, $olddot) = ($D, 0);
3793             if ($_[0] < 0)
3794             {
3795             $olddot = $D;
3796             $_[0] = -$_[0];
3797             }
3798              
3799             &F_ForwardWord; ## goes forward $_[0] words.
3800              
3801             while ($start < $D) {
3802             $c = substr($line, $start, 1);
3803              
3804             if ($op eq 'up') {
3805             $c = uc $c;
3806             } elsif ($op eq 'down') {
3807             $c = lc $c;
3808             } else { ## must be 'cap'
3809             if ($state == 1) {
3810             $c = lc $c;
3811             } else {
3812             $c = uc $c;
3813             $state = 1;
3814             }
3815             $state = 0 if $c !~ tr/a-zA-Z//;
3816             }
3817              
3818             substr($line, $start, 1) = $c;
3819             $start++;
3820             }
3821             $D = $olddot if defined($olddot);
3822             }
3823              
3824             =head3 search
3825              
3826             search($position, $string)
3827              
3828             Checks if $string is at position I<$rl_History[$position]> and returns
3829             I<$position> if found or -1 if not found.
3830              
3831             This is intended to be the called first in a potentially repetitive
3832             search, which is why the unusual return value. See also
3833             L.
3834              
3835             =cut
3836              
3837             sub search($$) {
3838             my ($i, $str) = @_;
3839             return -1 if $i < 0 || $i > $#rl_History; ## for safety
3840             while (1) {
3841             return $i if rindex($rl_History[$i], $str) >= 0;
3842             if ($reverse) {
3843             return -1 if $i-- == 0;
3844             } else {
3845             return -1 if $i++ == $#rl_History;
3846             }
3847             }
3848             }
3849              
3850             sub DoSearch
3851             {
3852             local $reverse = shift; # Used in search()
3853             my $oldline = $line;
3854             my $oldD = $D;
3855             my $tmp;
3856              
3857             my $searchstr = ''; ## string we're searching for
3858             my $I = -1; ## which history line
3859              
3860             $si = 0;
3861              
3862             while (1)
3863             {
3864             if ($I != -1) {
3865             $line = $rl_History[$I];
3866             $D += index($rl_History[$I], $searchstr);
3867             }
3868             redisplay( '('.($reverse?'reverse-':'') ."i-search) `$searchstr': ");
3869              
3870             $c = &getc_with_pending;
3871             if (($KeyMap[ord($c)] || 0) eq 'F_ReverseSearchHistory') {
3872             if ($reverse && $I != -1) {
3873             if ($tmp = &search($I-1,$searchstr), $tmp >= 0) {
3874             $I = $tmp;
3875             } else {
3876             &F_Ding;
3877             }
3878             }
3879             $reverse = 1;
3880             } elsif (($KeyMap[ord($c)] || 0) eq 'F_ForwardSearchHistory') {
3881             if (!$reverse && $I != -1) {
3882             if ($tmp = &search($I+1,$searchstr), $tmp >= 0) {
3883             $I = $tmp;
3884             } else {
3885             &F_Ding;
3886             }
3887             }
3888             $reverse = 0;
3889             } elsif ($c eq "\007") { ## abort search... restore line and return
3890             $line = $oldline;
3891             $D = $oldD;
3892             return;
3893             } elsif (ord($c) < 32 || ord($c) > 126) {
3894             push(@Pending, $c) if $c ne "\e";
3895             if ($I < 0) {
3896             ## just restore
3897             $line = $oldline;
3898             $D = $oldD;
3899             } else {
3900             #chose this line
3901             $line = $rl_History[$I];
3902             $D = index($rl_History[$I], $searchstr);
3903             }
3904             rl_redisplay();
3905             last;
3906             } else {
3907             ## Add this character to the end of the search string and
3908             ## see if that'll match anything.
3909             $tmp = &search($I < 0 ? $rl_HistoryIndex-$reverse: $I, $searchstr.$c);
3910             if ($tmp == -1) {
3911             &F_Ding;
3912             } else {
3913             $searchstr .= $c;
3914             $I = $tmp;
3915             }
3916             }
3917             }
3918             }
3919              
3920             =head3 search
3921              
3922             searchStart($position, $reverse, $string)
3923              
3924             I<$reverse> should be either +1, or -1;
3925              
3926             Checks if $string is at position I<$rl_History[$position+$reverse]> and
3927             returns I<$position> if found or -1 if not found.
3928              
3929             This is intended to be the called first in a potentially repetitive
3930             search, which is why the unusual return value. See also L.
3931              
3932             =cut
3933             sub searchStart($$$) {
3934             my ($i, $reverse, $str) = @_;
3935             $i += $reverse ? - 1: +1;
3936             return -1 if $i < 0 || $i > $#rl_History; ## for safety
3937             while (1) {
3938             return $i if index($rl_History[$i], $str) == 0;
3939             if ($reverse) {
3940             return -1 if $i-- == 0;
3941             } else {
3942             return -1 if $i++ == $#rl_History;
3943             }
3944             }
3945             }
3946              
3947             sub DoSearchStart
3948             {
3949             my ($reverse,$what) = @_;
3950             my $i = searchStart($rl_HistoryIndex, $reverse, $what);
3951             return if $i == -1;
3952             $rl_HistoryIndex = $i;
3953             ($D, $line) = (0, $rl_History[$rl_HistoryIndex]);
3954             F_BeginningOfLine();
3955             F_ForwardChar(length($what));
3956              
3957             }
3958              
3959             ###########################################################################
3960             ###########################################################################
3961              
3962             =head3 TextInsert
3963              
3964             C
3965              
3966             =cut
3967              
3968             sub TextInsert {
3969             my $count = shift;
3970             my $text2add = shift(@_) x $count;
3971             if ($InsertMode) {
3972             substr($line,$D,0) .= $text2add;
3973             } else {
3974             substr($line,$D,length($text2add)) = $text2add;
3975             }
3976             $D += length($text2add);
3977             }
3978              
3979             =head3 complete_internal
3980              
3981             The meat of command completion. Patterned closely after GNU's.
3982              
3983             The supposedly partial word at the cursor is "completed" as per the
3984             single argument:
3985             "\t" complete as much of the word as is unambiguous
3986             "?" list possibilities.
3987             "*" replace word with all possibilities. (who would use this?)
3988              
3989             A few notable variables used:
3990             $rl_completer_word_break_characters
3991             -- characters in this string break a word.
3992             $rl_special_prefixes
3993             -- but if in this string as well, remain part of that word.
3994              
3995             Returns true if a completion was done, false otherwise, so vi completion
3996             routines can test it.
3997              
3998             =cut
3999             sub complete_internal
4000              
4001             {
4002             my $what_to_do = shift;
4003             my ($point, $end) = ($D, $D);
4004              
4005             # In vi mode, complete if the cursor is at the *end* of a word, not
4006             # after it.
4007             ($point++, $end++) if $Vi_mode;
4008              
4009             if ($point)
4010             {
4011             ## Not at the beginning of the line; Isolate the word to be completed.
4012             1 while (--$point && (-1 == index($rl_completer_word_break_characters,
4013             substr($line, $point, 1))));
4014              
4015             # Either at beginning of line or at a word break.
4016             # If at a word break (that we don't want to save), skip it.
4017             $point++ if (
4018             (index($rl_completer_word_break_characters,
4019             substr($line, $point, 1)) != -1) &&
4020             (index($rl_special_prefixes, substr($line, $point, 1)) == -1)
4021             );
4022             }
4023              
4024             my $text = substr($line, $point, $end - $point);
4025             $rl_completer_terminator_character = ' ';
4026             my @matches =
4027             &completion_matches($rl_completion_function,$text,$line,$point);
4028              
4029             if (@matches == 0) {
4030             return &F_Ding;
4031             } elsif ($what_to_do eq "\t") {
4032             my $replacement = shift(@matches);
4033             $replacement .= $rl_completer_terminator_character
4034             if @matches == 1 && !$rl_completion_suppress_append;
4035             &F_Ding if @matches != 1;
4036             if ($var_TcshCompleteMode) {
4037             @tcsh_complete_selections = (@matches, $text);
4038             $tcsh_complete_start = $point;
4039             $tcsh_complete_len = length($replacement);
4040             }
4041             if ($replacement ne '') {
4042             substr($line, $point, $end-$point) = $replacement;
4043             $D = $D - ($end - $point) + length($replacement);
4044             }
4045             } elsif ($what_to_do eq '?') {
4046             shift(@matches); ## remove prepended common prefix
4047             local $\ = '';
4048             print $term_OUT "\n\r";
4049             # print "@matches\n\r";
4050             &pretty_print_list (@matches);
4051             $force_redraw = 1;
4052             } elsif ($what_to_do eq '*') {
4053             shift(@matches); ## remove common prefix.
4054             local $" = $rl_completer_terminator_character;
4055             my $replacement = "@matches$rl_completer_terminator_character";
4056             substr($line, $point, $end-$point) = $replacement; ## insert all.
4057             $D = $D - ($end - $point) + length($replacement);
4058             } else {
4059             warn "\r\n[Internal error]";
4060             return &F_Ding;
4061             }
4062              
4063             1;
4064             }
4065              
4066             =head3 use_basic_commands
4067              
4068             use_basic_commands($text, $line, $start);
4069              
4070             Used as a completion function by I<&rl_basic_commands>. Return items
4071             from I<@rl_basic_commands> that start with the pattern in I<$text>.
4072              
4073             I<$start> should be 0, signifying matching from the beginning of the
4074             line, for this to work. Otherwise we return the empty list. I<$line>
4075             is ignored, but needs to be there in to match the completion-function
4076             API.
4077              
4078             =cut
4079              
4080             sub use_basic_commands($$$) {
4081             my ($text, $line, $start) = @_;
4082             return () if $start != 0;
4083             grep(/^$text/, @rl_basic_commands);
4084             }
4085              
4086             =head3 completion_matches
4087              
4088             completion_matches(func, text, line, start)
4089              
4090             I is a function to call as
4091              
4092             func($text, $line, $start)
4093              
4094             where I<$text> is the item to be completed,
4095             I<$line> is the whole command line, and
4096             I<$start> is the starting index of I<$text> in I<$line>.
4097             The function I<$func> should return a list of items that might match.
4098              
4099             completion_matches will return that list, with the longest common
4100             prefix prepended as the first item of the list. Therefore, the list
4101             will either be of zero length (meaning no matches) or of 2 or more.....
4102              
4103             =cut
4104             sub completion_matches
4105             {
4106             my ($func, $text, $line, $start) = @_;
4107              
4108             ## get the raw list
4109             my @matches;
4110              
4111             #print qq/\r\neval("\@matches = &$func(\$text, \$line, \$start)\n\r/;#DEBUG
4112             #eval("\@matches = &$func(\$text, \$line, \$start);1") || warn "$@ ";
4113              
4114             @matches = &$func($text, $line, $start);
4115              
4116             ## if anything returned , find the common prefix among them
4117             if (@matches) {
4118             my $prefix = $matches[0];
4119             my $len = length($prefix);
4120             for (my $i = 1; $i < @matches; $i++) {
4121             next if substr($matches[$i], 0, $len) eq $prefix;
4122             $prefix = substr($prefix, 0, --$len);
4123             last if $len == 0;
4124             $i--; ## retry this one to see if the shorter one matches.
4125             }
4126             unshift(@matches, $prefix); ## make common prefix the first thing.
4127             }
4128             @matches;
4129             }
4130              
4131             $have_getpwent = eval{
4132             my @fields = getpwent(); setpwent(); 1;
4133             };
4134              
4135             sub rl_tilde_expand($) {
4136             my $prefix = shift;
4137             my @matches = ();
4138             setpwent();
4139             while (my @fields = (getpwent)[0]) {
4140             push @matches, $fields[0]
4141             if ( $prefix eq ''
4142             || $prefix eq substr($fields[0], 0, length($prefix)) );
4143             }
4144             setpwent();
4145             @matches;
4146             }
4147              
4148             sub tilde_complete($) {
4149             my $prefix = shift;
4150             return $prefix unless $have_getpwent;
4151             my @names = rl_tilde_expand($prefix);
4152             if (scalar @names == 1) {
4153             (getpwnam($names[0]))[7];
4154             } else {
4155             map {'~' . $_} @names;
4156             }
4157             }
4158              
4159             =head3 pretty_print_list
4160              
4161             Print an array in columns like ls -C. Originally based on stuff
4162             (lsC2.pl) by utashiro@sran230.sra.co.jp (Kazumasa Utashiro).
4163              
4164             See L for a more flexible and more general routine.
4165              
4166             =cut
4167              
4168             sub pretty_print_list
4169             {
4170             my @list = @_;
4171             return unless @list;
4172             my ($lines, $columns, $mark, $index);
4173              
4174             ## find width of widest entry
4175             my $maxwidth = 0;
4176             grep(length > $maxwidth && ($maxwidth = length), @list);
4177             $maxwidth++;
4178              
4179             $columns = $maxwidth >= $rl_screen_width
4180             ? 1 : int($rl_screen_width / $maxwidth);
4181              
4182             ## if there's enough margin to interspurse among the columns, do so.
4183             $maxwidth += int(($rl_screen_width % $maxwidth) / $columns);
4184              
4185             $lines = int((@list + $columns - 1) / $columns);
4186             $columns-- while ((($lines * $columns) - @list + 1) > $lines);
4187              
4188             $mark = $#list - $lines;
4189             local $\ = '';
4190             for ($l = 0; $l < $lines; $l++) {
4191             for ($index = $l; $index <= $mark; $index += $lines) {
4192             printf("%-$ {maxwidth}s", $list[$index]);
4193             }
4194             print $term_OUT $list[$index] if $index <= $#list;
4195             print $term_OUT "\n\r";
4196             }
4197             }
4198              
4199             sub start_dot_buf {
4200             my($count, $ord) = @_;
4201             $Dot_buf = [pack('c', $ord)];
4202             unshift(@$Dot_buf, split(//, $count)) if $count > 1;
4203             $Dot_state = savestate();
4204             }
4205              
4206             sub end_dot_buf {
4207             # We've recognized an editing command
4208              
4209             # Save the command keystrokes for use by '.'
4210             $Last_vi_command = $Dot_buf;
4211             undef $Dot_buf;
4212              
4213             # Save the pre-command state for use by 'u' and 'U';
4214             $Vi_undo_state = $Dot_state;
4215             $Vi_undo_all_state = $Dot_state if !$Vi_undo_all_state;
4216              
4217             # Make sure the current line is treated as new line for history purposes.
4218             $rl_HistoryIndex = $#rl_History + 1;
4219             }
4220              
4221             sub save_dot_buf {
4222             &start_dot_buf(@_);
4223             &end_dot_buf;
4224             }
4225              
4226             sub do_delete {
4227              
4228             my($count, $ord, $poshash) = @_;
4229              
4230             my $other_end = &get_position($count, undef, $ord, $poshash);
4231             return &F_Ding if !defined $other_end;
4232              
4233             if ($other_end < 0) {
4234             # dd - delete entire line
4235             &kill_text(0, length($line), 1);
4236             }
4237             else {
4238             &kill_text($D, $other_end, 1);
4239             }
4240              
4241             1; # True return value
4242             }
4243              
4244             =head3 get_position
4245              
4246             get_position($count, $ord, $fulline_ord, $poshash)
4247              
4248             Interpret vi positioning commands
4249             =cut
4250              
4251             sub get_position {
4252             my ($count, $ord, $fullline_ord, $poshash) = @_;
4253              
4254             # Manipulate a copy of the cursor, not the real thing
4255             local $D = $D;
4256              
4257             # $ord (first character of positioning command) is an optional argument.
4258             $ord = ord(&getc_with_pending) if !defined $ord;
4259              
4260             # Detect double character (for full-line operation, e.g. dd)
4261             return -1 if defined $fullline_ord and $ord == $fullline_ord;
4262              
4263             my $re = $poshash->{$ord};
4264              
4265             if ($re) {
4266             my $c = pack('c', $ord);
4267             if (lc($c) eq 'b') {
4268             &backward_scan($count, $re);
4269             }
4270             else {
4271             &forward_scan($count, $re);
4272             }
4273             }
4274             else {
4275             # Move the local copy of the cursor
4276             &do_command($var_EditingMode{'vipos'}, $count, $ord);
4277             }
4278              
4279             # Return the new cursor (undef if illegal command)
4280             $D;
4281             }
4282              
4283             sub forward_scan {
4284             my($count, $re) = @_;
4285             while ($count--) {
4286             last unless substr($line, $D) =~ m{^($re)};
4287             $D += length($1);
4288             }
4289             }
4290              
4291             sub backward_scan {
4292             my($count, $re) = @_;
4293             while ($count--) {
4294             last unless substr($line, 0, $D) =~ m{($re)$};
4295             $D -= length($1);
4296             }
4297             }
4298              
4299             sub get_line_from_history($) {
4300             my($n) = @_;
4301             return &F_Ding if $n < 0 or $n > @rl_History;
4302             return if $n == $rl_HistoryIndex;
4303              
4304             # If we're moving from the currently-edited line, save it for later.
4305             $line_for_revert = $line if $rl_HistoryIndex == @rl_History;
4306              
4307             # Get line from history buffer (or from saved edit line).
4308             $line = ($n == @rl_History) ? $line_for_revert : $rl_History[$n];
4309             $D = $Vi_mode ? 0 : length $line;
4310              
4311             # Subsequent 'U' will bring us back to this point.
4312             $Vi_undo_all_state = savestate() if $Vi_mode;
4313              
4314             $rl_HistoryIndex = $n;
4315             }
4316              
4317             # Redisplay the line, without attempting any optimization
4318             sub rl_forced_update_display() {
4319             local $force_redraw = 1;
4320             redisplay(@_);
4321             }
4322              
4323             ## returns a new $i or -1 if not found.
4324             sub vi_search {
4325             my ($i) = @_;
4326             return -1 if $i < 0 || $i > $#rl_History; ## for safety
4327             while (1) {
4328             return $i if $rl_History[$i] =~ /$Vi_search_re/;
4329             if ($reverse) {
4330             return -1 if $i-- == 0;
4331             } else {
4332             return -1 if $i++ == $#rl_History;
4333             }
4334             }
4335             }
4336              
4337             sub do_vi_search {
4338             my $incr = $reverse ? -1 : 1;
4339              
4340             my $i = &vi_search($rl_HistoryIndex + $incr);
4341             return &F_Ding if $i < 0; # Not found.
4342              
4343             $rl_HistoryIndex = $i;
4344             ($D, $line) = (0, $rl_History[$rl_HistoryIndex]);
4345             }
4346              
4347             # Using local $line, $D, and $prompt, get and return the string to
4348             # search for.
4349             sub get_vi_search_str($) {
4350             my($c) = @_;
4351              
4352             local $prompt = $prompt . $c;
4353             local ($line, $D) = ('', 0);
4354             rl_redisplay();
4355              
4356             # Gather a search string in our local $line.
4357             while ($lastcommand ne 'F_ViEndSearch') {
4358             &do_command($var_EditingMode{'visearch'}, 1, ord(&getc_with_pending));
4359             rl_redisplay();
4360              
4361             # We've backspaced past beginning of line
4362             return undef if !defined $line;
4363             }
4364             $line;
4365             }
4366              
4367             sub vi_input_mode()
4368             {
4369             $InsertMode = 1;
4370             $var_EditingMode = $var_EditingMode{'vi'};
4371             $Vi_mode = 1;
4372             }
4373              
4374             sub clipboard_set($) {
4375             my $in = shift;
4376             if ($^O eq 'os2') {
4377             eval {
4378             require OS2::Process;
4379             OS2::Process::ClipbrdText_set($in); # Do not disable \r\n-conversion
4380             1
4381             } and return;
4382             } elsif ($^O eq 'MSWin32') {
4383             eval {
4384             require Win32::Clipboard;
4385             Win32::Clipboard::Set($in);
4386             1
4387             } and return;
4388             }
4389             my $mess;
4390             if ($ENV{RL_CLCOPY_CMD}) {
4391             $mess = "Writing to pipe `$ENV{RL_CLCOPY_CMD}'";
4392             open COPY, "| $ENV{RL_CLCOPY_CMD}" or warn("$mess: $!"), return;
4393             } elsif (defined $HOME) {
4394             my $cutpastefile = File::Spec($HOME, '.rl_cutandpaste');
4395             $mess = "Writing to file `$cutpastefile'";
4396             open COPY, "> $cutpastefile" or warn("$mess: $!"), return;
4397             } else {
4398             return;
4399             }
4400             print COPY $in;
4401             close COPY or warn("$mess: closing $!");
4402             }
4403              
4404             =head3 read_an_init_file
4405              
4406             B(I, [I])
4407              
4408             Reads and executes I which does things like Sets input
4409             key bindings in key maps.
4410              
4411             If there was a problem return 0. Otherwise return 1;
4412              
4413             =cut
4414              
4415             sub read_an_init_file($;$)
4416             {
4417             my $file = shift;
4418             my $include_depth = shift or 0;
4419             my $rc;
4420              
4421             $file = File::Spec->catfile($HOME, $file) unless -f $file;
4422             return 0 unless open $rc, "< $file";
4423             local (@action) = ('exec'); ## exec, skip, ignore (until appropriate endnif)
4424             local (@level) = (); ## if, else
4425              
4426             local $/ = "\n";
4427             while (my $line = <$rc>) {
4428             parse_and_bind($line, $file, $include_depth);
4429             }
4430             close($rc);
4431             return 1;
4432             }
4433              
4434             =head1 SEE ALSO
4435              
4436             L
4437              
4438             =cut
4439             1;