App-Greple-md
view release on metacpan or search on metacpan
lib/App/Greple/md.pm view on Meta::CPAN
return $_[1] unless $config->{osc8};
my($url, $text) = @_;
my $escaped = uri_escape_utf8($url, "^\\x20-\\x7e");
"${OS}${escaped}${OE}${text}${OS}${OE}";
}
#
# Link text inner pattern: backtick spans, backslash escapes, normal chars
#
my $LT = qr/(?:`[^`\n]*+`|\\.|[^`\\\n\]]++)+/;
#
# colorize() - the main function
#
# Receives entire file content in $_ (--begin with -G --filter).
# Processes all patterns with multiline regexes.
#
#
# Pipeline steps as code refs
#
my %colorize = (
code_blocks => sub {
s{^( {0,3})(`{3,}|~{3,})(.*)\n((?s:.*?))^( {0,3})\2(\h*)$}{
my($oi, $fence, $lang, $body, $ci, $trail) = ($1, $2, $3, $4, $5, $6);
my $result = md_color('code_mark', "$oi$fence");
$result .= md_color('code_info', $lang) if length($lang);
$result .= "\n";
if (length($body)) {
$result .= join '', map { md_color('code_block', $_) }
split /(?<=\n)/, $body;
}
$result .= md_color('code_mark', "$ci$fence") . $trail;
protect($result)
}mge;
},
comments => sub {
s/(^<!--(?![->])(?s:.*?)-->)/protect(md_color('comment', $1))/mge;
},
image_links => sub {
s{\[!\[($LT)\]\(([^)\n]+)\)\]\(<?([^>)\s\n]+)>?\)}{
protect(
osc8($2, md_color('image_link', "!"))
. osc8($3, md_color('image_link', "[$1]"))
)
}ge;
},
images => sub {
s{!\[($LT)\]\(<?([^>)\s\n]+)>?\)}{
protect(osc8($2, md_color('image', "![$1]")))
}ge;
},
links => sub {
s{(?<![!\e])\[($LT)\]\(<?([^>)\s\n]+)>?\)}{
protect(osc8($2, md_color('link', "[$1]")))
}ge;
},
inline_code => sub {
s/(?<bt>`++)(((?!\g{bt}).)+)(\g{bt})/
protect(md_color('code_tick', $+{bt}) . md_color('code_inline', $2) . md_color('code_tick', $4))
/ge;
},
headings => sub {
my $hashed = $config->{hashed};
for my $n (reverse 1..6) {
next unless active("h$n");
my $hdr = '#' x $n;
s{^($hdr\h+.*)$}{
my $line = $1;
$line .= " $hdr"
if $hashed->{"h$n"} && $line !~ /\#$/;
protect(md_color("h$n", restore($line)));
}mge;
}
},
horizontal_rules => sub {
s/^([ ]{0,3}(?:[-*_][ ]*){3,})$/protect(md_color('horizontal_rule', $1))/mge;
},
bold => sub {
s/(?<![\\`])\*\*.*?(?<!\\)\*\*/md_color('bold', $&)/ge;
s/(?<![\\`\w])__.*?(?<!\\)__(?!\w)/md_color('bold', $&)/ge;
},
italic => sub {
s/(?<![\\`\w])_(?:(?!_).)+(?<!\\)_(?!\w)/md_color('italic', $&)/ge;
s/(?<![\\`\*])\*(?:(?!\*).)+(?<!\\)\*(?!\*)/md_color('italic', $&)/ge;
},
strike => sub {
s/(?<![\\`])~~.+?(?<!\\)~~/md_color('strike', $&)/ge;
},
blockquotes => sub {
s/^(>+\h?)(.*)$/md_color('blockquote', $1) . $2/mge;
},
);
#
# Pipeline configuration
#
# Always before headings (protection + links)
my @protect_steps = qw(code_blocks comments image_links images links);
# Inline steps controlled by heading_markup
my @inline_steps = qw(inline_code horizontal_rules bold italic strike);
# Always last
my @final_steps = qw(blockquotes);
# Step-to-label mapping for active() check (unmapped = always active)
my %step_label = (
headings => 'header',
horizontal_rules => 'horizontal_rule',
bold => 'bold',
italic => 'italic',
strike => 'strike',
blockquotes => 'blockquote',
);
sub build_pipeline {
my $hm = $config->{heading_markup};
lib/App/Greple/md.pm view on Meta::CPAN
for my $step (build_pipeline()) {
my $label = $step_label{$step};
next if $label && !active($label);
$colorize{$step}->();
}
$_ = restore($_);
$_;
}
#
# Table formatting
#
sub begin {
colorize() if $config->{colorize};
format_table() if $config->{table};
}
sub format_table {
my $sep = $config->{rule} ? "\x{2502}" : '|'; # â or |
s{(^ {0,3}\|.+\|\n){3,}}{
my $block = $&;
my $formatted = call_ansicolumn($block,
'-s', '|', '-o', $sep, '-t', '--cu=1');
fix_separator($formatted, $sep);
}mge;
}
sub call_ansicolumn {
my ($text, @args) = @_;
require Command::Run;
require App::ansicolumn;
Command::Run->new
->command(\&App::ansicolumn::ansicolumn, @args)
->with(stdin => $text)
->update
->data // '';
}
sub fix_separator {
my ($text, $sep) = @_;
my $sep_re = $sep eq "\x{2502}" ? "\x{2502}" : '\\|';
$text =~ s{^$sep_re((?:\h* -+ \h* $sep_re)*\h* -+ \h*)$sep_re$}{
$sep eq "\x{2502}"
? "\x{251C}" . ($1 =~ tr[\x{2502} -][\x{253C}\x{2500}\x{2500}]r) . "\x{2524}"
: "|" . ($1 =~ tr[ ][-]r) . "|"
}xmeg;
$text;
}
1;
__DATA__
option default \
-G --filter --filestyle=once --color=always \
--begin &__PACKAGE__::begin
define {CODE_BLOCK} ^ {0,3}(?<bt>`{3,}+|~{3,}+)(.*)\n((?s:.*?))^ {0,3}(\g{bt})
define {COMMENT} ^<!--(?![->])(?s:.+?)-->
define {TABLE} ^ {0,3}([â|â].+[â|â¤]\n){3,}
define {LIST_ITEM} ^\h*(?:[*-]|(?:\d+|#)[.)])\h+.*\n
define {DEFINITION} (?:\A|\G\n|\n\n).+\n\n?(:\h+.*\n)
option --fold-by \
-Mtee "&ansifold" --crmode \
--autoindent='^\h*(?:[*-]|(?:\d+|#)[.)]|:)\h+|^\h+' \
--smart --width=$<shift> \
-- \
--exclude {CODE_BLOCK} \
--exclude {COMMENT} \
--exclude {TABLE} \
--cm N -E {LIST_ITEM} \
--cm N -E {DEFINITION} \
--crmode
( run in 1.713 second using v1.01-cache-2.11-cpan-97f6503c9c8 )