package App::Codeowners::Formatter::String; # ABSTRACT: Format codeowners output using printf-like strings =head1 DESCRIPTION This is a L that formats output using a printf-like string. See L. =cut use warnings; use strict; our $VERSION = '9999.999'; # VERSION use parent 'App::Codeowners::Formatter'; use App::Codeowners::Util qw(stringf zip); use Color::ANSI::Util 0.03 qw(ansifg); use Encode qw(encode); sub stream { my $self = shift; my $result = shift; $result = {zip @{$self->columns}, @$result}; my %info = ( F => $self->_create_filterer->($result->{File}, undef), O => $self->_create_filterer->($result->{Owner}, $self->_owner_colorgen), P => $self->_create_filterer->($result->{Project}, undef), T => $self->_create_filterer->($result->{Pattern}, undef), ); my $text = stringf($self->format, %info); print { $self->handle } encode('UTF-8', $text), "\n"; } sub _expand_filter_args { my $arg = shift || ''; my @filters = split(/,/, $arg); my $color_override; for (my $i = 0; $i < @filters; ++$i) { my $filter = $filters[$i] or next; if ($filter =~ /^(?:nocolor|color:([0-9a-fA-F]{3,6}))$/) { $color_override = $1 || ''; splice(@filters, $i, 1); redo; } } return (\@filters, $color_override); } sub _ansi_reset { "\033[0m" } sub _colored { my $text = shift; my $rgb = shift or return $text; return $text if $ENV{NO_COLOR}; $rgb =~ s/^(.)(.)(.)$/$1$1$2$2$3$3/; if ($rgb !~ m/^[0-9a-fA-F]{6}$/) { warn "Color value must be in 'ffffff' or 'fff' form.\n"; return $text; } my ($begin, $end) = (ansifg($rgb), _ansi_reset); return "${begin}${text}${end}"; } sub _create_filterer { my $self = shift; my %filter = ( quote => sub { local $_ = $_[0]; s/"/\"/s; "\"$_\"" }, ); return sub { my $value = shift || ''; my $color = shift || ''; my $gencolor = ref($color) eq 'CODE' ? $color : sub { $color }; return sub { my $arg = shift; my ($filters, $color) = _expand_filter_args($arg); if (ref($value) eq 'ARRAY') { $value = join(',', map { _colored($_, $color // $gencolor->($_)) } @$value); } else { $value = _colored($value, $color // $gencolor->($value)); } for my $key (@$filters) { if (my $filter = $filter{$key}) { $value = $filter->($value); } else { warn "Unknown filter: $key\n" } } $value || ''; }; }; } sub _owner_colorgen { my $self = shift; # https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/ my @contrasting_colors = qw( e6194b 3cb44b ffe119 4363d8 f58231 911eb4 42d4f4 f032e6 bfef45 fabebe 469990 e6beff 9a6324 fffac8 800000 aaffc3 808000 ffd8b1 000075 a9a9a9 ); # assign a color to each owner, on demand my %owner_colors; my $num = -1; $self->{owner_color} ||= sub { my $owner = shift or return; $owner_colors{$owner} ||= do { $num = ($num + 1) % scalar @contrasting_colors; $contrasting_colors[$num]; }; }; } 1;