* J.A.J. Pater <[email protected]> [03/07/09 07:27]:
> 
> Moshe Kamensky schreef:
> > No, there is no way to do it, I miss this as well... If you only want to 
> > view text, I have a plugin for urxvt that does this.
> >
> > Moshe
> Would this plugin not work while editing text?
> I'd like to have it.
> 

It won't work for editing, because it only works when applying the bidi 
algorithm once for each line. I attach the plugin. You should put it in 
the same directory as the other urxvt perl plugins (possibly 
/usr/lib/urxvt/perl), and add bidi to URxvt.perl-ext-common, or use the  
-pe switch (see the man pages for urxvt and urxvtperl for details).
You will need Text::Bidi installed (from CPAN) which, in turn, needs 
libfribidi.

There is a resource URxvt.bidiFieldSeparator that can be set to a 
sequence of characters, each of which serves as a separator for the bidi 
algorithm. This is useful for example to preserve the columns when using 
a mail client within urxvt.

Best,
Moshe


> 
> --~--~---------~--~----~------------~-------~--~----~
> You received this message from the "vim_use" maillist.
> For more information, visit http://www.vim.org/maillist.php
> -~----------~----~----~----~------~----~------~--~---
> 
#! perl

use Text::Bidi qw(:all);

sub on_start {
    my ($self) = @_;
    $self->{'dir'} = $Text::Bidi::Type::ON;
    my $reset = $self->x_resource('bidiFieldSeparator');
    set_reset($reset) if $reset;
    ()
}

sub byte2rend {
    ($_[0] & 0xf, ($_[0] >> 4) & 0xf)
}

sub rend2byte {
    $_[0] + ($_[1] << 4)
}

sub map2rend {
    return () unless @_;
    my $start = $_[0];
    my @res;
    my $dir;
    if ( $#_ ) {
        $dir = $_[1] - $start;
        $dir = $dir / abs($dir);
    }
    for my $i (1..$#_) {
        next if $_[$i] - $_[$i-1] == $dir;
        push @res, byte2rend($start), byte2rend($_[$i-1]);
        $start = $_[$i];
        last if $i == $#_;
        $dir = $_[$i+1] - $start;
        $dir = $dir / abs($dir);
    }
    push @res, byte2rend($start), byte2rend($_[-1]);
    $res[-1] |= 0x10;
    $res[0] |= 0x10;
    @res;
}

sub rend2map {
    my @res;
    my $f = urxvt::GET_CUSTOM($_[0]->[0]) & 0xf;
    my $i = 1;
    while ( 1 ) {
        my $s = urxvt::GET_CUSTOM($_[0]->[$i]);
        $i++;
        my $b = rend2byte($f, $s);
        $f = urxvt::GET_CUSTOM($_[0]->[$i]);
        $i++;
        $s = urxvt::GET_CUSTOM($_[0]->[$i]);
        $i++;
        my $e = rend2byte($f, $s & 0xf);
        push @res, $b < $e ? ($b..$e) : reverse $e..$b;
        last if $s & 0x10 or $i > $#{$_[0]};
        $f = urxvt::GET_CUSTOM($_[0]->[$i]);
        $i++;
    }
    @res
}

sub on_line_update {
   my ($self, $row) = @_;

   my $line = $self->line($row);
   my $text = $line->t;
   my $rend = $line->r;
   unless ( $text =~ /\p{BidiClass:R}/ ) {
       urxvt::SET_CUSTOM($rend->[0], 0);
       $line->r($rend);
       return()
   }
   my $w = $self->ncol();
   if ( urxvt::GET_CUSTOM($rend->[0])) {
       # assume that the character near the cursor was just added
       # and remove it to get a correct translation
       my $off = $line->offset_of($self->screen_cur()) - 1;
       my $cur = substr($text, $off, 1, '');
       #print STDERR "removed '$cur' from $off in '$text'\n";
       # translate back to logical
       my @text = split //, $text;
       my @v2l = rend2map($rend);
       #print STDERR join(';', @v2l), "\n";
       $text = join('', @te...@v2l]);
       # put back the character
       #print STDERR "Putting back '$cur' at $off in '$text'\n";
       substr($text, $off, 0, $cur);
   }
   # pad the text with spaces so that justification is correct
   my $pad = ($w - length($text) % $w);
   $text .= ' ' x $pad;
   my ($new, $dir, undef, $v2l) = 
       log2vis( 
           $self->special_decode($text),
           #$text,
           $self->{'dir'}, $w);
   $new = $self->special_encode($new);
   # if the base direction is left-to-right, remove the padding so that 
   # rendition works correctly
   if ( $dir == $Text::Bidi::Type::LTR ) {
       $new =~ s/( {0,$pad})$//;
       $pad = length($1);
       splice @$v2l, -$pad, $pad;
   }
   $line->t($new);

   # I don't know how to determine the rendition for the rest of the line
   push @$rend, (urxvt::DEFAULT_RSTYLE) x (length($new) - @$rend);
   my @nrend = @$re...@$v2l];
   # store the v2l map for further changes
   my @custom = map2rend(@$v2l);
   for my $i ( 0..$#custom ) {
       $nrend[$i] = urxvt::SET_CUSTOM($nrend[$i], $custom[$i]);
   }
   $line->r(\...@nrend);
   ();
}

my %cmd2type = (
    LTR => $Text::Bidi::Type::LTR,
    RTL => $Text::Bidi::Type::RTL,
    Auto => $Text::Bidi::Type::ON,
);
sub on_user_command {
    my ($self, $cmd) = @_;
    my $dir = $cmd2type{$cmd} if $cmd =~ s/^bidi:pardir//;
    if ( defined $dir ) {
        $self->{'dir'} = $dir;
        # this does not actually help, still need to press ^L
        $self->want_refresh;
    } else {
        warn "Unknown direction $cmd";
    }
    ()
}

Attachment: pgpH4VnMCYZIc.pgp
Description: PGP signature

Reply via email to