home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 December (Special) / PCWorld_2005-12_Special_cd.bin / Bezpecnost / lsti / lsti.exe / framework-2.5.exe / Zoid.pm < prev    next >
Text File  |  2005-04-27  |  35KB  |  1,291 lines

  1. package Term::ReadLine::Zoid;
  2.  
  3. use strict;
  4. use vars '$AUTOLOAD';
  5. use Term::ReadLine::Zoid::Base;
  6. #use encoding 'utf8';
  7. no warnings; # undef == '' down here
  8.  
  9. our @ISA = qw/Term::ReadLine::Zoid::Base Term::ReadLine::Stub/; # explicitly not use'ing T:RL::Stub
  10. our $VERSION = '0.07';
  11.  
  12. sub import { # terrible hack - Term::ReadLine in perl 5.6.x is defective
  13.     return unless (caller())[0] eq 'Term::ReadLine' and $] < 5.008 ;
  14.     *Term::ReadLine::Stub::new = sub {
  15.         shift;
  16.         my $self = bless {}, 'Term::ReadLine::Zoid';
  17.         return $self->_init(@_);
  18.     };
  19. }
  20.  
  21. sub new {
  22.     my $self = bless {}, shift(@_);
  23.     return $self->_init(@_);
  24. }
  25.  
  26. our $_current;
  27. our %_config  = (
  28.     minline        => 0,
  29.     autohistory    => 1,
  30.     autoenv        => 1,
  31.     autolist    => 1,
  32.     automultiline    => 1,
  33.     PS2        => '> ',
  34.     comment_begin    => '#',
  35.     maxcomplete    => 'pager',
  36.     default_mode    => 'insert',
  37. );
  38. our %_keymaps = (
  39.     insert => {
  40.         return    => 'accept_line',
  41.         ctrl_O    => 'operate_and_get_next',
  42.         ctrl_D    => 'delete_char_or_eof',
  43.         ctrl_C    => 'return_empty_string',
  44.         escape    => 'switch_mode_command',
  45.         ctrl_R    => 'switch_mode_isearch',
  46.         ctrl__    => 'switch_mode_fbrowse',
  47.         right    => 'forward_char',
  48.         ctrl_F    => 'forward_char',
  49.         left    => 'backward_char',
  50.         ctrl_B    => 'backward_char',
  51.         home    => 'beginning_of_line',
  52.         ctrl_A    => 'beginning_of_line',
  53.         end    => 'end_of_line',
  54.         ctrl_E    => 'end_of_line',
  55.         up    => 'previous_history',
  56.         page_up    => 'previous_history',
  57.         ctrl_P    => 'previous_history',
  58.         down    => 'next_history',
  59.         page_down => 'next_history',
  60.         ctrl_N    => 'next_history',
  61.         delete    => 'delete_char',
  62.         backspace => 'backward_delete_char',
  63.         ctrl_U    => 'unix_line_discard',
  64.         ctrl_K    => 'kill_line',
  65.         ctrl_W    => 'unix_word_rubout',
  66.         tab    => 'complete',
  67.         ctrl_V    => 'quoted_insert',
  68.         insert    => 'overwrite_mode',
  69.         ctrl_L    => 'clear_screen',
  70.         _default => 'self_insert',
  71.     },
  72.     multiline => {
  73.         return    => 'insert_line',
  74.         up    => 'backward_line',
  75.         down    => 'forward_line',
  76.         page_up => 'page_up',
  77.         page_down => 'page_down',
  78.         _isa    => 'insert',
  79.     },
  80.     command => { _use => 'Term::ReadLine::Zoid::ViCommand'  },
  81.     emacs   => { _use => 'Term::ReadLine::Zoid::Emacs'      },
  82.     emacs_multiline => { _use => 'Term::ReadLine::Zoid::Emacs' },
  83.     fbrowse => { _use => 'Term::ReadLine::Zoid::FileBrowse' },
  84.     isearch => { _use => 'Term::ReadLine::Zoid::ISearch'    },
  85. );
  86.  
  87. sub _init {
  88.     my ($self, $name, $in, $out) = @_;
  89.  
  90.     %$self = (
  91.         appname   => $name,
  92.         IN        => $in  || *STDIN{IO},
  93.         OUT       => $out || *STDOUT{IO},
  94.         history   => [],
  95.         hist_cnt  => 1,
  96.         class     => ref($self), # we might be overloaded
  97.         undostack => [],
  98.     %$self );
  99.  
  100.     $$self{config}{$_}  ||= $_config{$_}  for keys %_config ;
  101.     $$self{keymaps}{$_} ||= $_keymaps{$_} for keys %_keymaps;
  102.     eval "sub switch_mode_$_;" for keys %{$$self{keymaps}}; # if we declare, we can()
  103.  
  104.     # rcfiles
  105.     my ($rcfile) = grep {-e $_ && -r _} 
  106.         "$ENV{HOME}/.perl_rl_zoid_rc",
  107.         "$ENV{HOME}/.zoid/perl_rl_zoid_rc",
  108.         "/etc/perl_rl_zoid_rc";
  109.     if ($rcfile) {
  110.         local $_current = $self;
  111.         do $rcfile;
  112.     }
  113.  
  114.     # PERL_RL
  115.     if (exists $ENV{PERL_RL}) {
  116.         my ($which, @config) = split /\s+/, $ENV{PERL_RL};
  117.         if (UNIVERSAL::isa($self, "Term::ReadLine::$which")) {
  118.             for (@config) {
  119.                 /(\w+)=(.*)/ or next;
  120.                 $$self{config}{$1} = $2;
  121.             }
  122.         }
  123.     }
  124.  
  125.     $self->switch_mode();
  126.     return $self;
  127. }
  128.  
  129. sub AUTOLOAD {
  130.     $AUTOLOAD =~ s/.*:://;
  131.     return if $AUTOLOAD eq 'DESTROY';
  132.     my $self = shift;
  133.     if ($AUTOLOAD =~ /^switch_mode_(.*)/) {
  134.         $self->switch_mode($1, @_);
  135.     }
  136.     elsif ($$self{class} ne __PACKAGE__) {
  137.         my $sub = $$self{class}.'::'.$AUTOLOAD;
  138.         $self->$sub(@_);
  139.     }
  140.     else {
  141.         my (undef, $f, $l) = caller;
  142.         die "$AUTOLOAD: no such method at $f line $l\n"
  143.     }
  144. }
  145.  
  146. # ############ #
  147. # ReadLine api #
  148. # ############ #
  149.  
  150. sub ReadLine { return 'Term::ReadLine::Zoid' }
  151.  
  152. sub readline {
  153.     my ($self, $prompt, $preput) = @_;
  154.     $self->reset();
  155.     $self->switch_mode();
  156.     $$self{prompt} = defined($prompt) ? $prompt : $$self{appname}.' !> ';
  157.     $$self{lines}  = [ split /\n/, $preput ] if defined $preput;
  158.     my $title = $$self{config}{title} || $$self{appname};
  159.     $self->title($title);
  160.     $self->new_line();
  161.     if ($$self{prev_hist_p}) {
  162.         $self->set_history( delete $$self{prev_hist_p} );
  163.     }
  164.     $self->loop();
  165.     return $self->_return();
  166. }
  167.  
  168. sub _return { # also used by continue
  169.     my $self = shift;
  170.     bless $self, $$self{class}; # rebless default class
  171.     print { $$self{OUT} } "\n";
  172.     return undef unless defined $$self{_loop}; # exit application
  173.     return '' unless length $$self{_loop}; # return empty string
  174.     my $string = join("\n", @{$$self{lines}}) || '';
  175.     $self->AddHistory($string) if $$self{config}{autohistory};
  176.     return '' if $$self{config}{comment_begin}
  177.         and ! grep {$_ !~ /^\s*\Q$$self{config}{comment_begin}\E/} @{$$self{lines}};
  178.     $string =~ s/\\\n//ge if $$self{config}{automultiline};
  179.     #print STDERR "string: $string\n";
  180.     return $string;
  181. }
  182.  
  183. sub addhistory {
  184.     my ($self, $line) = @_;
  185.     return unless defined $$self{config}{minline};
  186.     return unless length $line and length($line) > $$self{config}{minline};
  187.     unshift @{$$self{history}}, $line;
  188.     $$self{hist_cnt}++;
  189. }
  190. *AddHistory = \&addhistory; # T:RL:Gnu compat
  191.  
  192. sub IN { $_[0]{IN} }
  193.  
  194. sub OUT { $_[0]{OUT} }
  195.  
  196. sub MinLine {
  197.     my ($self, $minl) = @_;
  198.     my $old_minl = $$self{config}{minline};
  199.     $$self{config}{minline} = $minl;
  200.     return $old_minl;
  201. }
  202.  
  203. sub Attribs { $_[0]{config} }
  204.  
  205. sub Features { {
  206.     ( map {($_ => 1)} qw/appname minline attribs 
  207.         addhistory addHistory getHistory getHistory TermSize/ ),
  208.     ( map {($_ => $_[0]{config}{$_})}
  209.         qw/autohistory autoenv automultiline/ ),
  210. } }
  211.  
  212. # ############ #
  213. # Extended api #
  214. # ############ #
  215.  
  216. sub GetHistory {
  217.     return wantarray 
  218.         ? ( reverse @{$_[0]{history}} )
  219.         : [ reverse @{$_[0]{history}} ] ;
  220. }
  221.  
  222. sub SetHistory {
  223.     my $self = shift;
  224.     $self->{history} = ref($_[0])
  225.         ? [ reverse @{$_[0]} ]
  226.         : [ reverse @_       ] ;
  227. }
  228.  
  229. # TermSize in Base
  230.  
  231. sub continue { # user typed \n but app says we ain't done
  232.     my $self = shift;
  233.     shift @{$$self{history}} if $$self{history}[0] eq join "\n", @{$$self{lines}};
  234.     $$self{_buffer}++; # previous _return printed a \n
  235.     $self->switch_mode( $$self{mode} ); # switch into last mode
  236.     $self->insert_line();
  237.     $self->loop();
  238.     return $self->_return();
  239. }
  240.  
  241. sub current {
  242.     return $_current if $_current;
  243.     my (undef, $f, $l) = caller;
  244.     die "No current Term::ReadLine::Zoid object at $f line $l";
  245. }
  246.  
  247. sub bindkey {
  248.     my ($self, $key, $sub, $mode) = @_;
  249.     $mode ||= $$self{config}{default_mode};
  250.     $$self{keymaps}{$mode} ||= {};
  251.     $key = 'meta_'.uc($1) if $key =~ /^[mM]-(.)$/;
  252.     $key = 'ctrl_'.uc($1) if $key =~ /^(?:\^|[cC]-)(.)$/;
  253.     $sub =~ tr/-/_/ unless ref $sub;
  254.     $$self{keymaps}{$mode}{$key} = $sub;
  255. }
  256.  
  257. # ######### #
  258. # Render Fu #
  259. # ######### #
  260.  
  261. sub draw {
  262.     my $self  = shift;
  263.     my @pos   = @{$$self{pos}};   # force copy
  264.     my @lines = @{$$self{lines}}; # idem
  265. #    use Data::Dumper; print STDERR Dumper \@lines, \@pos;
  266.  
  267.     $pos[0] = length $lines[ $pos[1] ]
  268.         if $pos[0] > length $lines[ $pos[1] ];
  269.  
  270.     # replace the non printables
  271.     for (0 .. $#lines) {
  272.         if ($_ == $pos[1]) {
  273.             my $start = substr $lines[$_], 0, $pos[0], '';
  274.             my $n = ( $start =~ s{([^[:print:]])}{
  275.                 my $ord = ord $1;
  276.                 ($ord < 32) ? '^'.(chr $ord + 64) : '^?'
  277.             }ge );
  278.             $pos[0] += $n;
  279.             $lines[$_] = $start . $lines[$_];
  280.         }
  281.         $lines[$_] =~ s{([^[:print:]\e])}{
  282.             my $ord = ord $1;
  283.             ($ord < 32) ? '^'.(chr $ord + 64) : '^?'
  284.         }ge;
  285.     }
  286.  
  287.     # format PS1
  288.     my $prompt = ref($$self{prompt}) ? ${$$self{prompt}} : $$self{prompt};
  289.     $prompt =~ s/(!!)|!/$1?'!':$$self{hist_cnt}/eg;
  290.  
  291.     # format PS2 ... thank carl0s if you like to set nu
  292.     my $len = length scalar @lines;
  293.     my $nu_form = (defined $ENV{CLICOLOR} and ! $ENV{CLICOLOR})
  294.         ? "  %${len}u " : "  \e[33m%${len}u\e[0m " ;
  295.     if (@lines > 1) {
  296.         my $ps2 = ref($$self{config}{PS2}) ? ${$$self{config}{PS2}} : $$self{config}{PS2};
  297.         if ($$self{config}{nu}) { # line numbering
  298.             $lines[$_] = sprintf($nu_form, $_ + 1) . $ps2 . $lines[$_]
  299.                 for 1 .. $#lines;
  300.             $pos[0] += $self->print_length($ps2) + $len + 3 if $pos[1];
  301.         }
  302.         else {
  303.             $lines[$_] = $ps2 . $lines[$_] for 1 .. $#lines;
  304.             $pos[0] += $self->print_length($ps2) if $pos[1];
  305.         }
  306.     }
  307.  
  308.     # include PS1
  309.     my @prompt = split /\n/, $prompt, -1;
  310.     if (@prompt) {
  311.         $prompt[-1] = sprintf($nu_form, 1) . $prompt[-1] if $$self{config}{nu};
  312.         $pos[0] += $self->print_length($prompt[-1]) unless $pos[1];
  313.         $pos[1] += $#prompt;
  314.         $lines[0] = pop(@prompt) . $lines[0];
  315.         unshift @lines, @prompt if @prompt;
  316.     }
  317.  
  318.     # format RPS1
  319.     if (my $rprompt = $$self{config}{RPS1}) {
  320.         $rprompt = $$rprompt if ref $rprompt;
  321.         my $l = $self->print_length($lines[0]);
  322.         if ($rprompt and $l < $$self{term_size}[0]) {
  323.             $rprompt = substr $rprompt, - $$self{term_size}[0] + $l - 1;
  324.             my $w = $$self{term_size}[0] - $l - $self->print_length($rprompt) - 1;
  325.             $lines[0] .= (' 'x$w) . $rprompt;
  326.         }
  327.     }
  328.  
  329.     $self->print(\@lines, \@pos);
  330. }
  331.  
  332. *redraw_current_line = \&draw;
  333.  
  334. # ############ #
  335. # Internal api #
  336. # ############ #
  337.  
  338. sub switch_mode { 
  339.     my ($self, $mode, @args) = @_;
  340.     $mode ||= $$self{config}{default_mode};
  341.     unless ($$self{keymaps}{$mode}) {
  342.         warn "$mode: no such keymap\n\n";
  343.         $mode = 'insert'; # hardcoded fallback
  344.     }
  345.     $$self{mode} = $mode;
  346.     if (my $class = delete $$self{keymaps}{$mode}{_use}) { # bootstrap
  347.         eval "use $class";
  348.         if ($@) {
  349.             $$self{keymaps}{$mode}{_use} = $class; # put it back
  350.             die $@;
  351.         }
  352.         bless $self, $class;
  353.         $$self{keymaps}{$mode} = {
  354.             %{ $$self{keymaps}{$mode} },
  355.             %{ $self->keymap($mode)   }
  356.         } if UNIVERSAL::can($class, 'keymap');
  357.         $$self{keymaps}{$mode}{_class} ||= $class;
  358.     }
  359.     else {
  360.         my $class = $$self{keymaps}{$mode}{_class} || $$self{class};
  361.         #print STDERR "class: $class\n";
  362.         bless $self, $class;
  363.     }
  364.  
  365.     if (exists $$self{keymaps}{$mode}{_on_switch}) {
  366.         my $sub = $$self{keymaps}{$mode}{_on_switch};
  367.         return ref($sub) ? $sub->($self, @args) : $self->$sub(@args) ;
  368.     }
  369. }
  370.  
  371. sub reset { # should this go in Base ?
  372.     my $self = shift;
  373.     $$self{lines} = [''];
  374.     $$self{pos}  = [0, 0];
  375.     $$self{_buffer} = 0;
  376.     $$self{replace} = 0;
  377.     $$self{hist_p} = undef;
  378.     $$self{undostack} = [];
  379.     $$self{scroll_pos} = 0;
  380. }
  381.  
  382. sub save {
  383.     my $self = shift;
  384.     my %save = (
  385.         pos    => [ @{$$self{pos}}   ],
  386.         lines  => [ @{$$self{lines}} ],
  387.         prompt => $$self{prompt},
  388.     );
  389.     return \%save;
  390. }
  391.  
  392. sub restore {
  393.     my ($self, $save) = @_;
  394.     $$self{pos}    = [ @{$$save{pos}} ];
  395.     $$self{lines}  = [ @{$$save{lines}} ];
  396.     $$self{prompt} = $$save{prompt};
  397. }
  398.  
  399. sub substring { # buffer is undef is copy, end is undef is insert
  400.     my ($self, $buffer, $start, $end) = @_;
  401.  
  402.     ($start, $end) = sort {$$a[1] <=> $$b[1] or $$a[0] <=> $$b[0]} ($start, $end) if $end;
  403.     my ($pre, $post) = _split($start || $$self{pos}, [ @{$$self{lines}} ]); # force copy of lines
  404.     my $re = [''];
  405.     if ($end) {
  406.         $$end[0] = $$end[0] - $$start[0] if $$end[1] == $$start[1];
  407.         $$end[1] = $$end[1] - $$start[1];
  408.         ($re, $post) = _split($end, $post);
  409.     }
  410.     return join "\n", @$re unless defined $buffer;
  411.  
  412.     $buffer = [split /\n/, $buffer, -1] if ! ref $buffer;
  413.     $buffer = [''] unless @$buffer;
  414.     $$pre[-1] .= shift @$buffer;
  415.     push @$pre, @$buffer;
  416.     $$self{pos} = [ length($$pre[-1]), $#$pre ];
  417.     $$pre[-1] .= shift @$post;
  418.     $$self{lines} = [ @$pre, @$post ];
  419.  
  420.     return join "\n", @$re;
  421. }
  422.  
  423. sub _split {
  424.     my ($pos, $buf, $nbuf) = (@_, []);
  425.     push @$nbuf, splice @$buf, 0, $$pos[1] if $$pos[1];
  426.     push @$nbuf, substr($$buf[0], 0, $$pos[0], '') || '';
  427.     return ($nbuf, $buf);
  428. }
  429.  
  430. # ############ #
  431. # Key routines #
  432. # ############ #
  433.  
  434. sub previous_history {
  435.     my $self = shift;
  436.     if (not defined $$self{hist_p}) {
  437.         return $self->bell unless scalar @{$$self{history}};
  438.         $$self{_hist_save} = $self->save();
  439.         $self->set_history(0);
  440.     }
  441.     elsif ($$self{hist_p} < $#{$$self{history}}) {
  442.         $self->set_history( ++$$self{hist_p} );
  443.     }
  444.     else { return $self->bell }
  445.     return 1;
  446. }
  447.  
  448. sub next_history {
  449.     my $self = shift;
  450.     return $self->bell unless defined $$self{hist_p};
  451.     if ($$self{hist_p} == 0) {
  452.         $$self{hist_p} = undef;
  453.         $self->restore($$self{_hist_save});
  454.     }
  455.     else { $self->set_history( --$$self{hist_p} ) }
  456.     return 1;
  457. }
  458.  
  459. sub set_history {
  460.     my $self = shift;
  461.     my $hist_p = shift;
  462.     return $self->bell if $hist_p < 0 or $$self{hist_p} > $#{$$self{history}};
  463.     $$self{hist_p} = $hist_p;
  464.     $$self{lines} = [ split /\n/, $$self{history}[$hist_p] ];
  465.     $$self{pos} = [ length($$self{lines}[-1]), $#{$$self{lines}} ];
  466.     # posix says {pos} should be [0, 0], i disagree
  467. }
  468.  
  469. sub self_insert {
  470.     my ($self, $chr) = (@_);
  471.  
  472.     # force pos on end of line
  473.     $$self{pos}[0] = length $$self{lines}[ $$self{pos}[1] ]
  474.         if $$self{pos}[0] > length $$self{lines}[ $$self{pos}[1] ];
  475.  
  476.     substr $$self{lines}[ $$self{pos}[1] ], $$self{pos}[0], $$self{replace}, $chr;
  477.     $$self{pos}[0] += length $chr;
  478. }
  479.  
  480. sub accept_line {
  481.     my $self = shift;
  482.     if ( 
  483.         $$self{config}{automultiline} and scalar @{$$self{lines}}
  484.         and ! grep /\\\\$|(?<!\\)$/, @{$$self{lines}}
  485.     ) {  #print STDERR "funky auto multiline :)\n";
  486.         push @{$$self{lines}}, '';
  487.         $$self{pos} = [0, $#{$$self{lines}}];
  488.     }
  489.     else { $$self{_loop} = 0 }
  490. }
  491.  
  492. *return = \&accept_line;
  493.  
  494. sub operate_and_get_next {
  495.     my $self = shift;
  496.     $$self{prev_hist_p} = $$self{hist_p};
  497.     $$self{_loop} = 0;
  498. }
  499.  
  500. sub return_eof_maybe {
  501.     length( join "\n", @{$_[0]{lines}} )
  502.         ? ( $_[0]->bell )
  503.         : ( $_[0]{_loop} = undef ) ;
  504. }
  505.  
  506. sub return_eof { $_[0]{_loop} = undef }
  507.  
  508. sub return_empty_string { $_[0]{_loop} = '' }
  509.  
  510. sub delete_char {
  511.     my $self = shift;
  512.  
  513.     if ($$self{pos}[0] >= length $$self{lines}[ $$self{pos}[1] ]) {
  514.         $$self{pos}[0] = length $$self{lines}[ $$self{pos}[1] ]; # force pos on end of line
  515.         return $self->bell unless $$self{pos}[1] < @{$$self{lines}};
  516.         $$self{lines}[ $$self{pos}[1] ] .= $$self{lines}[ $$self{pos}[1] + 1 ]; # append next line
  517.         splice @{$$self{lines}}, $$self{pos}[1] + 1, 1; # kill next line
  518.     }
  519.     else { substr $$self{lines}[ $$self{pos}[1] ], $$self{pos}[0], 1, '' }
  520.     return 1;
  521. }
  522.  
  523. sub delete_char_or_eof {
  524.     my $self = shift;
  525.     if (
  526.         $$self{pos}[1] == $#{$$self{lines}}
  527.         and ! length $$self{lines}[-1]
  528.     ) { $$self{_loop} = $$self{pos}[1] ? 0 : undef }
  529.     else { $self->delete_char() }
  530. }
  531.  
  532. sub backward_delete_char {
  533.     $_[0]->backward_char();
  534.     $_[0]->delete_char() unless $_[0]{replace};
  535. }
  536.  
  537. sub unix_line_discard {
  538.     $_[0]{killbuf} = join "\n", @{$_[0]{lines}};
  539.     @{$_[0]}{'lines', 'pos'} = ([''], [0, 0])
  540. }
  541.  
  542. sub possible_completions {
  543.     my $self = shift;
  544.     $self->complete(undef, 'PREVIEW');
  545. }
  546.  
  547. sub complete {
  548.     my ($self, undef, $preview) = @_;
  549.  
  550.     # check !autolist stuff
  551.     if ($$self{completions} && @{$$self{completions}}) {
  552.         $self->output( @{$$self{completions}} );
  553.         delete $$self{completions};
  554.         return;
  555.     }
  556.  
  557.     # get the right function
  558.     my $func = exists($$self{config}{completion_function}) 
  559.         ? $$self{config}{completion_function}
  560.         : $readline::rl_completion_function ;
  561.     return unless $func;
  562.     unless (ref $func) {
  563.         no strict;
  564.         $func = *{$func}{CODE};
  565.         return unless ref $func; # how does this work ?
  566.     }
  567.  
  568.     # generate the arguments
  569.     my $buffer = join "\n", @{$$self{lines}};
  570.     my $end = $self->pos2off($$self{pos});
  571.     my $word = substr $buffer, 0, $end;
  572.     $word =~ s/^.*\s//s; # only leave /\S*$/
  573.     my $lw = length $word;
  574.  
  575.     # get the completions and output
  576.     my @compl = $func->($word, $buffer, $end - $lw); # word, line, start
  577.     my $meta = ref($compl[0]) ? shift(@compl) : {} ; # hash constitutes an undocumented feature
  578.     $self->output( $$meta{message} ) if $$meta{message};
  579.  
  580.     return $self->bell unless @compl;
  581.     if ($compl[0] eq $compl[-1]) { @compl = ($compl[0]) } # 1 item or list with only duplicates
  582.     else { @compl = $self->longest_match(@compl) } # returns $compl, @compl
  583.  
  584.     # format completion
  585.     my $compl = shift @compl;
  586.     $compl = $$meta{prefix} . $compl;
  587.     $compl .= $$meta{postfix} unless @compl;
  588.     unless ($$meta{quoted}) {
  589.         if ($$meta{quote}) {
  590.             if (ref $$meta{quote}) { $compl = $$meta{quote}->($compl) } # should be code ref
  591.             else { # plain quote
  592.                 $compl =~ s#\\\\|(?<=[^\\])($$meta{quote})#$1?"\\$1":'\\\\'#ge if $$meta{quote};
  593.                 $compl .= $$meta{quote} if !@compl and $compl =~ /\w$/; # arbitrary cruft
  594.             }
  595.         }
  596.         else { $compl =~ s#\\\\|(?<!\\)(\s)#$1?"\\$1":'\\\\'#eg } # escape whitespaces
  597.         $compl .= ' ' if !@compl and $compl =~ /\w$/; # arbitrary cruft
  598.     }
  599.  
  600.     # display completions
  601.     if (@compl) {
  602.         if ($$self{config}{autolist} || $preview) {
  603.             $self->output( @compl );
  604.             return if $preview;
  605.         }
  606.         else { $$self{completions} = \@compl }
  607.     }
  608.  
  609.     # update buffer
  610.     push @{$$self{undostack}}, $self->save() if length $compl;
  611. #    print STDERR ">>$buffer<< end $end off: ".($end - $lw)." l: $lw c: $compl\n";
  612.     my $start = $$meta{start} || $end - $lw;
  613.     substr $buffer,  $start, $end - $start, $compl;
  614.     $$self{lines} = [ split /\n/, $buffer ];
  615.     $$self{pos}[0] -= $lw - length($compl); # for the moment completions can't contains \n
  616. }
  617.  
  618. sub longest_match { # cut doubles and find longest match
  619.     my ($self, @compl) = @_;
  620.  
  621.     @compl = sort @compl;
  622.     my $match = $compl[0];
  623.     while (length $match and $compl[-1] !~ /^\Q$match\E/) { chop $match } # due to sort only one diff
  624.  
  625.     my $prev = '';
  626.     return ($match, grep {
  627.         if ($_ eq $prev) { 0 }
  628.         else { $prev = $_; 1 }
  629.     } @compl);
  630. }
  631.  
  632. sub overwrite_mode {
  633.     my $b = $_[0]{replace};
  634.     $_[0]->switch_mode(); # for command mode
  635.     $_[0]{replace} = $b ? 0 : 1;
  636. }
  637.  
  638. sub forward_char { # including cnt for vi mode
  639.     my ($self, undef, $cnt) = @_;
  640.     for (1 .. $cnt||1) {
  641.         if ($$self{pos}[0] >= length $$self{lines}[ $$self{pos}[1] ]) {
  642.             return $self->bell unless $$self{pos}[1] < $#{$$self{lines}};
  643.             $$self{pos} = [0, ++$$self{pos}[1]];
  644.         }
  645.         else { $$self{pos}[0]++ }
  646.     }
  647.     return 1;
  648. }
  649.  
  650. sub backward_char { # including cnt for vi mode
  651.     my ($self, undef, $cnt) = @_;
  652. #    print STDERR "going $cnt left, pos $$self{pos}[0]\n";
  653.     for (1 .. $cnt||1) {
  654.         if ($$self{pos}[0] == 0) {
  655.             return $self->bell if $$self{pos}[1] == 0;
  656.             $$self{pos}[1]--;
  657.             $$self{pos}[0] = length $$self{lines}[ $$self{pos}[1] ];
  658.         }
  659.         elsif ($$self{pos}[0] >= length $$self{lines}[ $$self{pos}[1] ]) {
  660.             $$self{pos}[0] = length($$self{lines}[ $$self{pos}[1] ]) - 1;
  661.         }
  662.         else { $$self{pos}[0]-- }
  663.     }
  664.     return 1;
  665. }
  666.  
  667. sub beginning_of_line { $_[0]{pos}[0] = 0; return 1 }
  668.  
  669. sub end_of_line { $_[0]{pos}[0] = length $_[0]{lines}[ $_[0]{pos}[1] ]; return 1 }
  670.  
  671. sub quoted_insert {
  672.     my $self = shift;
  673.     $self->self_insert($self->read_key);
  674. }
  675.  
  676. sub unix_word_rubout {
  677.     my $self = shift;
  678.     $$self{pos}[0] = length $$self{lines}[ $$self{pos}[1] ]
  679.         if $$self{pos}[0] > length $$self{lines}[ $$self{pos}[1] ];
  680.     my $pre = substr $$self{lines}[ $$self{pos}[1] ], 0, $$self{pos}[0], '';
  681.     $pre =~ s/\S*\s*$//;
  682.     $$self{pos}[0] = length $pre;
  683.     $$self{lines}[ $$self{pos}[1] ] = $pre . $$self{lines}[ $$self{pos}[1] ];
  684. }
  685.  
  686. sub kill_line {
  687.     my $self = shift;
  688.     $$self{lines}[ $$self{pos}[1] ] = substr $$self{lines}[ $$self{pos}[1] ], 0, $$self{pos}[0];
  689. }
  690.  
  691. sub insert_line {
  692.     my $self = shift;
  693.     my $l = length $$self{lines}[ $$self{pos}[1] ];
  694.     my $end = substr $$self{lines}[ $$self{pos}[1] ], $$self{pos}[0], $l, '';
  695.     $$self{pos} = [0, $$self{pos}[1] + 1];
  696.     splice @{$$self{lines}}, $$self{pos}[1], 0, $end || '';
  697. }
  698.  
  699. sub backward_line {
  700.     my $self = shift;
  701.     return 0 unless $$self{pos}[1] > 0;
  702.     $$self{pos}[1]--;
  703.     return 1;
  704. }
  705.  
  706. sub forward_line {
  707.     my $self = shift;
  708.     return 0 unless $$self{pos}[1] < $#{$$self{lines}};
  709.     $$self{pos}[1]++;
  710.     return 1;
  711. }
  712.  
  713. sub page_up {
  714.     my $self = shift;
  715.     my (undef, $higth) = $self->TermSize();
  716.     $$self{pos}[1] -= $higth;
  717.     $$self{pos}[1] = 0 if $$self{pos}[1] < 0;
  718. }
  719.  
  720.  
  721. sub page_down {
  722.     my $self = shift;
  723.     my (undef, $higth) = $self->TermSize();
  724.     $$self{pos}[1] += $higth;
  725.     $$self{pos}[1] = $#{$$self{lines}} if $$self{pos}[1] > $#{$$self{lines}};
  726. }
  727.  
  728. 1;
  729.  
  730. __END__
  731.  
  732. =head1 NAME
  733.  
  734. Term::ReadLine::Zoid - another ReadLine package
  735.  
  736. =head1 SYNOPSIS
  737.  
  738.     # In your app:
  739.     use Term::ReadLine;
  740.     my $term = Term::ReadLine->new("my app");
  741.     
  742.     my $prompt = "eval: ";
  743.     my $OUT = $term->OUT || \*STDOUT;
  744.     while ( defined ($_ = $term->readline($prompt)) ) {
  745.         # Think while (<STDIN>) {}
  746.         my $res = eval($_);
  747.         warn $@ if $@;
  748.         print $OUT $res, "\n" unless $@;
  749.     }
  750.     
  751.     # In some rc file
  752.     export PERL_RL=Zoid
  753.  
  754. =head1 DESCRIPTION
  755.  
  756. This package provides a set of modules that form an interactive input buffer
  757. written in plain perl with minimal dependencies. It features almost all
  758. key-bindings described in the posix spec for the sh(1) utility with some extensions like
  759. multiline editing; this includes a vi-command mode with a save-buffer
  760. (for copy-pasting) and an undo-stack.
  761.  
  762. Historically this code was part of the Zoidberg shell, but this implementation
  763. is complete independent from zoid and uses the  L<Term::ReadLine> interface, so it
  764. can be used with other perl programs.
  765.  
  766. ( The documentation sometimes referes to 'the application', this is the program
  767. using the ReadLine module for input. )
  768.  
  769. =head1 ENVIRONMENT
  770.  
  771. The L<Term::ReadLine> interface module uses the C<PERL_RL> variable
  772. to decide which module to load; so if you want to use this module for all
  773. your perl applications, try something like:
  774.  
  775.     export PERL_RL=Zoid
  776.  
  777. =head1 KEY MAPPING
  778.  
  779. The function name is given between parenthesis, these can be used for
  780. privat key maps.
  781.  
  782. =head2 Default keymap
  783.  
  784. The default key mapping is as follows:
  785.  
  786. =over 4
  787.  
  788. =item escape, ^[  (I<switch_mode_command>)
  789.  
  790. Place the line editor in command mode, see L<Term::ReadLine::Zoid::ViCommand>.
  791.  
  792. =item ^C  (I<return_empty_string>)
  793.  
  794. End editing and return an empty string.
  795.  
  796. =item ^D  (I<delete_char_or_eof>)
  797.  
  798. For a single line buffer ends editing and returns C<undef>
  799. if the line is empty, else it deletes a char.
  800. For a multiline buffer, ends editing and returns the lines
  801. to the application if the cursor is on the last line and this line
  802. is empty, else it deletes a char.
  803.  
  804. Note that the I<delete_char_or_eof> function does what I<delete_char>
  805. should do to be compatible with GNU readline lib.
  806.  
  807. =item delete  (I<delete_char>)
  808.  
  809. =item backspace, ^H, ^?  (I<backward_delete_char>)
  810.  
  811. Delete and backspace kill the current or previous character.
  812. The key '^?' is by default considered a backspace because most modern
  813. keyboards use this key for the "backspace" key and an escape sequence
  814. for the "delete" key.
  815. Of course '^H' is also considered a backspace.
  816.  
  817. =item tab, ^I  (I<complete>)
  818.  
  819. Try to complete the bigword on left of the cursor.
  820.  
  821. There is no default completion included in this package, so unless you define a custom
  822. expansion it doesn't do anything. See the L</completion_function> option.
  823.  
  824. Uses the PAGER environment variable to find a suitable pager when there are
  825. more completions to be shown then would fit on the screen.
  826.  
  827. See also the L</autolist> and L</maxcomplete> options.
  828.  
  829. =item return, ^J  (I<accept_line>)
  830.  
  831. End editing and return the edit line to the application unless the newline is escaped.
  832.  
  833. If _all_ lines in the buffer end with a single '\', the newline is considered escaped
  834. you can continue typing on the next line. This behaviour can be a bit unexpected
  835. because this module has multiline support which historic readline implementations
  836. have not, historically the escaping of a newline is done by the application not by the library.
  837. The surpress this behaviour, and let the application do it's thing, disable the "automultiline"
  838. option.
  839.  
  840. To enter the real multiline editing mode, press 'escape m',
  841. see L<Term::ReadLine::Zoid::MultiLine>.
  842.  
  843. =item ^O  (I<operate_and_get_next>)
  844.  
  845. Return the current buffer to the application but remember where we are in history.
  846. This can be used to quickly (re-)execute series of commands from history.
  847.  
  848. =item ^K  (I<kill_line>)
  849.  
  850. Delete from cursor to the end of the line.
  851.  
  852. =item ^L  (I<clear_screen>)
  853.  
  854. Clear entire screen. In contrast with other readline libraries, the prompt
  855. will remain at the bottom of the screen.
  856.  
  857. =item ^R  (I<switch_mode_isearch>)
  858.  
  859. Enter incremental search mode, see L<Term::ReadLine::Zoid::ISearch>.
  860.  
  861. =item ^U  (I<unix_line_discard>)
  862.  
  863. This is also known as the "kill" char. It deletes all characters on the edit line
  864. and puts them in the save buffer. You can paste them back in later with 'escape-p'.
  865.  
  866. =item ^V  (I<quoted_insert>)
  867.  
  868. Insert next key literally, ignoring any key-bindings.
  869.  
  870. WARNING: control or escape chars in the editline can cause unexpected results
  871.  
  872. =item ^W  (I<unix_word_rubout>)
  873.  
  874. Delete the word before the cursor.
  875.  
  876. =item insert  (I<overwrite_mode>)
  877.  
  878. Toggle replace bit.
  879.  
  880. =item home, ^A  (I<beginning_of_line>)
  881.  
  882. Move cursor to the begin of the edit line.
  883.  
  884. =item end, ^E  (I<end_of_line>)
  885.  
  886. Move cursor to the end of the edit line.
  887.  
  888. =item left, ^B  (I<backward_char>)
  889.  
  890. =item right, ^F  (I<forward_char>)
  891.  
  892. These keys can be used to move the cursor in the edit line.
  893.  
  894. =item up, page_up, ^P  (I<previous_history>)
  895.  
  896. =item down, page_down, ^N  (I<next_history>)
  897.  
  898. These keys are used to rotate the history.
  899.  
  900. =back
  901.  
  902. =head2 Multi-line keymap
  903.  
  904. The following keys are different in mutline mode, the others
  905. fall back to the default behaviour.
  906.  
  907. =over 4
  908.  
  909. =item return (I<insert_line>)
  910.  
  911. Insert a newline at the current cursor position.
  912.  
  913. =item up (I<backward_line>)
  914.  
  915. Move the cursor one line up.
  916.  
  917. =item down (I<forward_line>)
  918.  
  919. Move the cursor one line down.
  920.  
  921. =item page_up (I<page_up>)
  922.  
  923. Move the cursor one screen down, or to the bottom of the buffer.
  924.  
  925. =item page_down (I<page_down>)
  926.  
  927. Move the cursor one screen up, or to the top of the buffer.
  928.  
  929. =back
  930.  
  931. =head2 Unmapped functions
  932.  
  933. =over 4
  934.  
  935. =item I<return_eof>
  936.  
  937. End editing and return C<undef>.
  938.  
  939. =item I<return_eof_maybe>
  940.  
  941. End editing and return C<undef> if the buffer is completely empty.
  942.  
  943. =item I<possible_completions>
  944.  
  945. Like I<complete> but only shows the completions without
  946. actually doing them.
  947.  
  948. =item I<redraw_current_line>
  949.  
  950. Redraw the current line. This is done all the time automaticly 
  951. so you'll almost never need to call this one explicitly.
  952.  
  953. =back
  954.  
  955. =head1 ATTRIBS
  956.  
  957. The hash with options can be accessed with the L</Attribs> method.
  958. These can be modified from the rc-file (see L</FILES>) or can be set
  959. from the C<PERL_RL> environment variable. For example to disable the
  960. L</autolist> feature you can set C<PERL_RL='Zoid autolist=0'> before
  961. you start the application.
  962.  
  963. ( Also they can be altered interactively using the mini-buffer of 
  964. the command mode, see L<Term::ReadLine::Zoid::ViCommand>. )
  965.  
  966. =over 4
  967.  
  968. =item autohistory
  969.  
  970. If enabled lines are added to the history automaticly,
  971. subject to L</MinLine>. By default enabled.
  972.  
  973. =item autoenv
  974.  
  975. If enabled the environment variables C<COLUMNS> and C<LINES>
  976. are kept up to date. By default enabled.
  977.  
  978. =item autolist
  979.  
  980. If set completions are listed directly when a completion fails,
  981. if not set you need to press "tab" twice to see a list of possible completions.
  982. By default enabled.
  983.  
  984. =item automultiline
  985.  
  986. See L</return> for a description. By default enabled.
  987.  
  988. =item beat
  989.  
  990. This option can contain a CODE reference.
  991. It is called on the heartbeat event.
  992.  
  993. =item bell
  994.  
  995. This option can contain a CODE reference.
  996. The default is C<print "\cG">, which makes the terminal ring a bell.
  997.  
  998. =item comment_begin
  999.  
  1000. This option can be set to a string, if the edit line starts with this string the line
  1001. is regarded to be a comment and is not returned to the application, but it will appear
  1002. in the history if 'autohistory' is also set. Defaults to "#".
  1003.  
  1004. When there are multiple lines in the buffer they all need to start with the comment
  1005. string for the buffer to be regarded as a comment.
  1006.  
  1007. =item completion_function
  1008.  
  1009. This option can contain either a code ref or the name of a function to perform
  1010. completion. For compatibility with Term::ReadLine::Perl the global scalar
  1011. C<$readline::rl_completion_function> will be checked if this option
  1012. isn't defined.
  1013.  
  1014. The function will get the following arguments: C<$word>, C<$buffer>, C<$start>.
  1015. Where C<$word> is the word before the cursor, while C<$buffer> is the complete text
  1016. on the command line; C<$start> is the offset of C<$word> in C<$buffer>. 
  1017.  
  1018. The function should return a list of possible completions of C<$word>.
  1019. The completion list is checked for double entries.
  1020.  
  1021. There is B<no> default.
  1022.  
  1023. FIXME tell about the meta fields for advanced completion
  1024.  
  1025. =item default_mode
  1026.  
  1027. Specifies the mode the buffer starts in when you do a C<readline()>, also other
  1028. modes return to this mode if you exit them.
  1029. The default is 'insert' which is the single-line insert mode.
  1030. If you always want to edit in multiline mode set this option to 'multiline'.
  1031.  
  1032. =item maxcomplete
  1033.  
  1034. Maximum number of completions to be displayed, when the number of completions
  1035. is bigger the user is asked before displaying them. If set to zero completions
  1036. are always displayed.
  1037.  
  1038. If this option is set to the string 'pager' the user is asked when the number of
  1039. completions is to big to fit on screen and a pager would be used.
  1040.  
  1041. =item minline
  1042.  
  1043. This option controls which lines are included in the history, lines
  1044. shorter then this number are ignored. When set to "0" all lines are included in the
  1045. history, when set to C<undef> all lines are ignored.
  1046. Defaults to "0".
  1047.  
  1048. =item PS2
  1049.  
  1050. This option can contain the prompt to be used for extra buffer lines.
  1051. It defaults to C<< "> " >>.
  1052.  
  1053. Although the "PS1" prompt (as specified as an argument to the C<readline()> method)
  1054. can contain newlines, the PS2 prompt can't.
  1055.  
  1056. =item RPS1
  1057.  
  1058. This option can contain a string that will be shown on the right side of the screen.
  1059. This is known as the "right prompt" and the idea is stolen from zsh(1).
  1060.  
  1061. =item title
  1062.  
  1063. Used to set the terminal title, defaults to the appname.
  1064.  
  1065. =item low_latency
  1066.  
  1067. Changes the escape sequences are read from input.
  1068. If true delays evalution of the escape key till the next char is known.
  1069. By default disabled.
  1070.  
  1071. =back
  1072.  
  1073. =head1 FILES
  1074.  
  1075. This module reads a rc-file on intialisation, either F<$HOME/.perl_rl_zoid_rc>,
  1076. F<$HOME/.zoid/perl_rl_zoid_rc> or F</etc/perl_rl_zoid_rc>.
  1077. The rc-file is a perl script with access to the Term::ReadLine::Zoid object through
  1078. the method C<current()>.
  1079. If you want to have different behaviour for different applications,
  1080. try to check for C<< $rl->{appname} >>.
  1081.  
  1082.     # in for example ~/.perl_rl_zoid_rc
  1083.     my $rl = Term::ReadLine::Zoid->current();
  1084.     
  1085.     # set low latency
  1086.     $rl->Attribs()->{low_latency} = 1;
  1087.     
  1088.     # alias control-space to escape
  1089.     $rl->bindchr( chr(0), 'escape' );
  1090.     
  1091.     # create an ad hoc macro
  1092.     $rl->bindkey('^P', sub { $rl->press('mplayer -vo sdl ') } );
  1093.  
  1094. =head1 METHODS
  1095.  
  1096. =head2 ReadLine api
  1097.  
  1098. Functions specified by the L<Term::ReadLine> documentation.
  1099.  
  1100. =over 4
  1101.  
  1102. =item C<new($appname, $IN, $OUT)>
  1103.  
  1104. Simple constructor. Arguments are the application name (used for default prompt
  1105. and title string) and optional filehandles for input and output.
  1106.  
  1107. =item C<ReadLine()>
  1108.  
  1109. Returns the name of the current ReadLine module actually used.
  1110.  
  1111. =item C<readline($prompt, $preput)>
  1112.  
  1113. Returns a string entered by the user. 
  1114. The final newline is stripped, though the string might contain newlines elsewhere.
  1115.  
  1116. The prompt only supports the escape "!" for the history number
  1117. of the current line, use "!!" for a literal "!".
  1118. All other escapes you need to parse yourself, before supplying
  1119. the prompt.
  1120. The prompt defaults to C<< "$appname !> " >>.
  1121.  
  1122. If you want to do more with your prompt see L<Env::PS1>.
  1123.  
  1124. C<$preput> can be used to set some text on the edit line allready.
  1125.  
  1126. =item C<addhistory($line)>
  1127.  
  1128. =item C<AddHistory($line)>
  1129.  
  1130. Add a command to the history (subject to the L</minline> option).
  1131.  
  1132. If L</autohistory> is set this method will be called automaticly by L</readline>.
  1133.  
  1134. =item C<IN()>
  1135.  
  1136. Returns the filehandle used for input.
  1137.  
  1138. =item C<OUT()>
  1139.  
  1140. Returns the filehandle used for output.
  1141.  
  1142. =item C<MinLine($value)>
  1143.  
  1144. Sets L</minline> option to C<$value> and returns old value.
  1145.  
  1146. =item C<findConsole()>
  1147.  
  1148. TODO - what uses does this have ?
  1149.  
  1150. =item C<Attribs()>
  1151.  
  1152. Returns a reference to the options hash.
  1153.  
  1154. =item C<Features()>
  1155.  
  1156. Returns a reference to a hash with names of implemented features.
  1157.  
  1158. Be aware that the naming scheme is quite arbitrary, this module
  1159. uses the same names as Term::ReadLine::Gnu for common features.
  1160.  
  1161. =back
  1162.  
  1163. =head2 Extended api
  1164.  
  1165. =over 4
  1166.  
  1167. =item C<SetHistory(@hist)>
  1168.  
  1169. =item C<GetHistory()>
  1170.  
  1171. Simple acces to the history arry, the "set" function supports both a list
  1172. and a reference, the "get" function uses "wantarray".
  1173. Not sure which behaviour is compatible with T:RL::Gnu.
  1174.  
  1175. =item C<TermSize()>
  1176.  
  1177. Returns number of columns and lines on the terminal.
  1178.  
  1179. =item C<continue()>
  1180.  
  1181. This method can be called to continue the previous C<readline()> call.
  1182. Can be used to build a custom auto-mulitline feature.
  1183.  
  1184. =item C<current()>
  1185.  
  1186. Returns the current T:RL::Zoid object, for use in rc files, see L</FILES>.
  1187.  
  1188. =item C<bindkey($key, $sub, $map)>
  1189.  
  1190. Bind a CODE reference to a key, the function gets called when the key is typed with
  1191. the key name as an argument. The C<$map> argument is optional and can be either
  1192. "default", "command", "isearch" or "multiline".
  1193.  
  1194. If C<$sub> is not a reference it is considered an alias;
  1195. these aliases are not recursive.
  1196.  
  1197. For alphanumeric characters the name is the character itself, special characters have
  1198. long speaking names and control characters are prefixed with a '^'.
  1199.  
  1200. Binding combination with the meta- or alt-key is not supported (see L</NOTES>).
  1201.  
  1202. =back
  1203.  
  1204. =head2 Private api
  1205.  
  1206. Methods for use in overload classes.
  1207.  
  1208. I<Avoid using these methods from the application.>
  1209.  
  1210. =over 4
  1211.  
  1212. =item C<switch_mode($mode)>
  1213.  
  1214. Switch to input mode C<$mode>; changes the key map and
  1215. reblesses the object if the C<_on_switch> key returns a class name.
  1216.  
  1217. =item C<reset()>
  1218.  
  1219. Reset all temporary attributes.
  1220.  
  1221. =item C<save()>
  1222.  
  1223. Returns a ref with a copy of some temporary attributes.
  1224. Can be used to switch between multiple edit lines in combination with L</restore>.
  1225.  
  1226. =item C<restore($save)>
  1227.  
  1228. Restores saved attributes.
  1229.  
  1230. =item C<set_history($int)>
  1231.  
  1232. Sets history entry C<$int> in the buffer.
  1233.  
  1234. =item C<longest_match(@completion)>
  1235.  
  1236. Returns the longest match among the completions followed by the completions
  1237. itself. Used for completion functions.
  1238.  
  1239. =back
  1240.  
  1241. =head1 DEVELOPMENT
  1242.  
  1243. FIXME minimum subroutines new mode-class
  1244.  
  1245. FIXME how to set up a keymap
  1246.  
  1247. FIXME how to add a keymap/mode
  1248.  
  1249. =head1 NOTES
  1250.  
  1251. With most modern keymappings the combination of the meta key (alt) with a letter
  1252. is identical with an escape character followed by that letter.
  1253.  
  1254. Some functioality may in time be moved to the ::Base package.
  1255.  
  1256. =head1 TODO
  1257.  
  1258. UTF8 support, or general charset support, would be nice but at the moment
  1259. I lack the means to test these things. If anyone has ideas or suggestions about this
  1260. please contact me.
  1261.  
  1262. =head1 BUGS
  1263.  
  1264. Line wrap doesn't always displays the last character on the line right, no functional bug though.
  1265.  
  1266. If the buffer size exceeds the screen size some bugs appear in the rendering.
  1267.  
  1268. Please mail the author if you find any other bugs.
  1269.  
  1270. =head1 AUTHOR
  1271.  
  1272. Jaap Karssenberg || Pardus [Larus] E<lt>pardus@cpan.orgE<gt>
  1273.  
  1274. Copyright (c) 2004 Jaap G Karssenberg. All rights reserved.
  1275. This program is free software; you can redistribute it and/or
  1276. modify it under the same terms as Perl itself.
  1277.  
  1278. =head1 SEE ALSO
  1279.  
  1280. L<Term::ReadLine::Zoid::ViCommand>,
  1281. L<Term::ReadLine::Zoid::MultiLine>,
  1282. L<Term::ReadLine::Zoid::ISearch>,
  1283. L<Term::ReadLine::Zoid::FileBrowse>,
  1284. L<Term::ReadLine::Zoid::Base>,
  1285. L<Term::ReadLine>,
  1286. L<Env::PS1>,
  1287. L<Zoidberg>
  1288.  
  1289. =cut
  1290.  
  1291.