#! /bin/false # Copyright (C) 2016-2018 Guido Flohr <guido.flohr@cantanea.com>, # all rights reserved. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. package Qgoda::Splitter; $Qgoda::Splitter::VERSION = 'v0.9.3'; use strict; use Locale::TextDomain qw('qgoda'); use Scalar::Util qw(reftype); use Qgoda::Util qw(empty front_matter read_body safe_yaml_load); sub new { my ($class, $path) = @_; my $front_matter = front_matter $path; if (!defined $front_matter) { my $error = $! ? $! : __"no front matter"; die __x("error reading front matter from '{filename}': {error}\n", filename => $path. error => $error); } my $meta = safe_yaml_load $front_matter; my %front_lines; my $lineno = 1; foreach my $line (split /\n/, $front_matter) { ++$lineno; my $data = eval { safe_yaml_load $line }; if (!$@ && $data && ref $data && 'HASH' eq reftype $data) { my @keys = keys %$data; foreach my $key (keys %$data) { $front_lines{$key} = $lineno if exists $meta->{$key}; } } } my $body = read_body $path, ''; if (!defined $body) { my $error = $! ? $! : __"no body found"; die __x("error reading body from '{filename}': {error}\n", filename => $path. error => $error); } my @first = grep { !empty } split / ( <!--qgoda-xgettext-->(?:.*?)<!--\/qgoda-xgettext--> | <!--qgoda-no-xgettext-->(?:.*?)<!--\/qgoda-no-xgettext--> | [ \011-\015]* \n [ \011-\015]* \n [ \011-\015]* ) /sx, $body; my @chunks; foreach my $chunk (@first) { if ($chunk =~ /^[ \011-\015]+$/) { push @chunks, $chunk; } else { my $head = $chunk =~ s/^([ \011-\015]+)// ? $1 : undef; my $tail = $chunk =~ s/([ \011-\015]+)$// ? $1 : undef; push @chunks, $head if !empty $head; push @chunks, $chunk if !empty $chunk; push @chunks, $tail if !empty $tail; } } my $lineno = 3 + $front_matter =~ y/\n/\n/; my @entries; foreach my $chunk (@chunks) { if ($chunk =~ /[^ \011-\015]+$/) { if ($chunk =~ /^<!--qgoda-xgettext-->(.*?)<!--\/qgoda-xgettext-->$/s) { push @entries, { text => $1, lineno => $lineno, type => 'block', } } elsif ($chunk =~ /^<!--qgoda-no-xgettext-->(.*?)<!--\/qgoda-no-xgettext-->$/s) { push @entries, { text => $1, lineno => $lineno, type => 'exclude', } } else { push @entries, { text => $chunk, lineno => $lineno, type => 'paragraph', } } } else { push @entries, { text => $chunk, lineno => $lineno, type => 'whitespace', } } $lineno += $chunk =~ y/\n/\n/; } # Parse HTML comments. Maybe this should be optional. foreach my $entry (@entries) { if ($entry->{text} =~ s{^[ \011-\015]*<!--(.*?)-->[ \011-\015]*}{}s) { # We only extract message context hints as they are non-standard. my $comment = $1; if ($comment =~ s{xgettext:msgctxt=(.*)}{}) { my $msgctxt = $1; $msgctxt =~ s{^[ \011-\015]*}{}; $msgctxt =~ s{[ \011-\015]*$}{}; $entry->{msgctxt} = $msgctxt if !empty $msgctxt; } $comment =~ s{^[ \011-\015]*}{}; $comment =~ s{[ \011-\015]*$}{}; $entry->{comment} = $comment if !empty $comment; # Change to whitespace, if nothing left. $entry->{type} = 'whitespace' if empty $entry->{text}; } } bless { __meta => $meta, __body => $body, __entries => \@entries, __front_lines => \%front_lines }, $class; } sub meta { shift->{__meta}; } sub metaLineNumber { my ($self, $key) = @_; return $self->{__front_lines}->{$key} if exists $self->{__front_lines}->{$key}; return; } sub entries { my ($self) = @_; grep { 'whitespace' ne $_->{type} } grep { 'exclude' ne $_->{type} } @{$self->{__entries}}; } sub reassemble { my ($self, $callback) = @_; my $output = ''; foreach my $entry (@{$self->{__entries}}) { if ('whitespace' eq $entry->{type}) { $output .= $entry->{text}; } elsif ('block' eq $entry->{type}) { $output .= "<!--qgoda-xgettext-->" . $callback->($entry->{text}) . "<!--/qgoda-xgettext-->"; } elsif ('exclude' eq $entry->{type}) { $output .= "<!--qgoda-no-xgettext-->" . $callback->($entry->{text}) . "<!--/qgoda-no-xgettext-->"; } else { $output .= $callback->($entry->{text}); } } return $output; } 1;