* 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";
}
()
}
pgpH4VnMCYZIc.pgp
Description: PGP signature
