use
5.010;
String::Tagged->VERSION(
'0.11'
);
our
$VERSION
=
'0.03'
;
sub
_parse_colour_mirc
{
shift
;
my
(
$colcode
) =
@_
;
$colcode
=~ m/^
return
Convert::Color::RGB8->new( $1 );
$colcode
=~ m/^
return
Convert::Color::RGB8->new(
"$1$1$2$2$3$3"
);
$colcode
=~ m/^(\d\d?)/ and $1 < 16 and
return
Convert::Color::mIRC->new( $1 );
return
undef
;
}
my
@termcolours
=
map
{
chomp
; Convert::Color::RGB8->new(
$_
) } <DATA>;
close
DATA;
sub
_parse_colour_ansiterm
{
shift
;
my
(
$idx
) =
@_
;
$idx
>= 0 and
$idx
<
@termcolours
and
return
$termcolours
[
$idx
];
return
undef
;
}
sub
parse_irc
{
my
$class
=
shift
;
my
(
$text
,
%opts
) =
@_
;
my
$self
=
$class
->new(
""
);
my
%format
;
while
(
length
$text
) {
if
(
$text
=~ s/^([\x00-\x1f])// ) {
my
$ctrl
=
chr
(
ord
($1)+0x40);
if
(
$ctrl
eq
"B"
) {
$format
{bold} ?
delete
$format
{bold} : (
$format
{bold} = 1 );
}
elsif
(
$ctrl
eq
"U"
or
$ctrl
eq
"_"
) {
$format
{under} ?
delete
$format
{under} : (
$format
{under} = 1 );
}
elsif
(
$ctrl
eq
"R"
or
$ctrl
eq
"]"
) {
$format
{italic} ?
delete
$format
{italic} : (
$format
{italic} = 1 );
}
elsif
(
$ctrl
eq
"V"
) {
$format
{
reverse
} ?
delete
$format
{
reverse
} : (
$format
{
reverse
} = 1 );
}
elsif
(
$ctrl
eq
"O"
) {
undef
%format
;
}
elsif
(
$ctrl
eq
"C"
) {
my
$colourre
=
qr/#[0-9a-f]{6}|#[0-9a-f]{3}|\d\d?/
i;
if
(
$text
=~ s/^(
$colourre
),(
$colourre
)// ) {
$format
{fg} =
$self
->_parse_colour_mirc( $1 );
$format
{bg} =
$self
->_parse_colour_mirc( $2 );
}
elsif
(
$text
=~ s/^(
$colourre
)// ) {
$format
{fg} =
$self
->_parse_colour_mirc( $1 );
}
else
{
delete
$format
{fg};
delete
$format
{bg};
}
}
elsif
(
$ctrl
eq
"D"
) {
if
(
$text
=~ s/^b// ) {
$format
{under} ?
delete
$format
{under} : (
$format
{under} = 1 );
}
elsif
(
$text
=~ s/^c// ) {
$format
{bold} ?
delete
$format
{bold} : (
$format
{bold} = 1 );
}
elsif
(
$text
=~ s/^d// ) {
$format
{italic} ?
delete
$format
{italic} : (
$format
{italic} = 1 );
}
elsif
(
$text
=~ s/^g// ) {
undef
%format
}
else
{
$text
=~ s/^(.)(.)//;
my
(
$fg
,
$bg
) =
map
{
ord
(
$_
) -
ord
(
'0'
) } ( $1, $2 );
if
(
$fg
> 0 ) {
$format
{fg} =
$self
->_parse_colour_ansiterm(
$fg
);
}
if
(
$bg
> 0 ) {
$format
{bg} =
$self
->_parse_colour_ansiterm(
$bg
);
}
}
}
}
else
{
$text
=~ s/^([^\x00-\x1f]+)//;
my
$piece
= $1;
while
(
length
$piece
and
$opts
{parse_plain_formatting} ) {
$piece
=~ s/^(.*?)(?<!\w)(([\
*_
\/])\w+\3)(?!\w)// or
last
;
my
(
$pre
,
$inner
,
$flag
) = ( $1, $2, $3 );
$self
->append_tagged(
$pre
,
%format
)
if
length
$pre
;
my
%innerformat
=
%format
;
$innerformat
{
{
'*'
=>
"bold"
,
'_'
=>
"under"
,
'/'
=>
"italic"
}->{
$flag
}
} = 1;
$self
->append_tagged(
$inner
,
%innerformat
);
}
$self
->append_tagged(
$piece
,
%format
)
if
length
$piece
;
}
}
return
$self
;
}
sub
build_irc
{
my
$self
=
shift
;
my
%opts
=
@_
;
my
$default_fg
=
$opts
{default_fg} // 0;
my
$ret
=
""
;
my
%formats
;
$self
->iter_extents_nooverlap(
sub
{
my
(
$extent
,
%tags
) =
@_
;
$ret
.=
"\cB"
if
!
$formats
{bold} != !
$tags
{bold};
$ret
.=
"\c_"
if
!
$formats
{under} != !
$tags
{under};
$ret
.=
"\c]"
if
!
$formats
{italic} != !
$tags
{italic};
$ret
.=
"\cV"
if
!
$formats
{
reverse
} != !
$tags
{
reverse
};
$formats
{
$_
} =
$tags
{
$_
}
for
qw( bold under italic reverse )
;
my
$fg
=
$tags
{fg} ?
$tags
{fg}->as_mirc->
index
:
undef
;
my
$bg
=
$tags
{bg} ?
$tags
{bg}->as_mirc->
index
:
undef
;
if
( (
$fg
//
''
) ne (
$formats
{fg}//
''
) or (
$bg
//
''
) ne (
$formats
{bg}//
''
) ) {
if
(
defined
$bg
) {
$fg
//=
$default_fg
;
$ret
.=
sprintf
"\cC%02d,%02d"
,
$fg
,
$bg
;
}
elsif
(
defined
$fg
) {
$ret
.=
sprintf
"\cC%02d"
,
$fg
;
}
else
{
$ret
.=
"\cC"
;
}
}
$formats
{fg} =
$fg
;
$formats
{bg} =
$bg
;
$ret
.=
$extent
->plain_substr;
});
$ret
.=
"\cC"
if
defined
$formats
{fg} or
defined
$formats
{bg};
return
$ret
;
}
sub
new_from_formatted
{
my
$class
=
shift
;
my
(
$orig
) =
@_
;
return
$class
->clone(
$orig
,
only_tags
=> [
qw( bold under italic reverse fg bg )
]
);
}
sub
as_formatted
{
my
$self
=
shift
;
return
$self
;
}
0x55AA;