summaryrefslogtreecommitdiff
path: root/support/latexindent/LatexIndent/Lines.pm
diff options
context:
space:
mode:
Diffstat (limited to 'support/latexindent/LatexIndent/Lines.pm')
-rw-r--r--support/latexindent/LatexIndent/Lines.pm266
1 files changed, 266 insertions, 0 deletions
diff --git a/support/latexindent/LatexIndent/Lines.pm b/support/latexindent/LatexIndent/Lines.pm
new file mode 100644
index 0000000000..edfe811564
--- /dev/null
+++ b/support/latexindent/LatexIndent/Lines.pm
@@ -0,0 +1,266 @@
+package LatexIndent::Lines;
+# 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.
+#
+# See http://www.gnu.org/licenses/.
+#
+# Chris Hughes, 2017
+#
+# For all communication, please visit: https://github.com/cmhughes/latexindent.pl
+use strict;
+use warnings;
+use Exporter qw/import/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::Switches qw/%switches/;
+use LatexIndent::Verbatim qw/%verbatimStorage/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/lines_body_selected_lines lines_verbatim_create_line_block/;
+
+sub lines_body_selected_lines {
+ my $self = shift;
+ my @lines = @{$_[0]};
+
+ # strip all space from lines switch
+ $switches{lines} =~ s/\h//sg;
+
+ $logger->info("*-n,--lines switch is active, operating on lines $switches{lines}");
+ $logger->info("number of lines in file: ".($#lines+1));
+ $logger->info("*interpretting $switches{lines}");
+
+ my @lineRanges = split(/,/,$switches{lines});
+ my @indentLineRange;
+ my @NOTindentLineRange;
+
+ my %minMaxStorage;
+ my %negationMinMaxStorage;
+
+ # loop through line ranges, which are separated by commas
+ #
+ # --lines 3-15,17-19
+ #
+ foreach(@lineRanges){
+ my $minLine = 0;
+ my $maxLine = 0;
+ my $negationMode = 0;
+
+ #
+ # --lines !3-15
+ #
+ if($_ =~ m/!/s){
+ $negationMode = 1;
+ $_ =~ s/!//s;
+ $logger->info("negation mode active as $_");
+ }
+
+ # --lines min-max
+ if($_ =~ m/-/s){
+ ($minLine,$maxLine) = split(/-/,$_);
+ } else {
+ $minLine = $_;
+ $maxLine = $_;
+ }
+
+ # both minLine and maxLine need to be INTEGERS
+ if ($minLine !~ m/^\d+$/ or $maxLine !~ m/^\d+$/){
+ $logger->warn("*$_ not a valid line specification; I'm ignoring this entry");
+ next;
+ }
+
+ # swap minLine and maxLine if necessary
+ if($minLine > $maxLine){
+ ($minLine,$maxLine) = ($maxLine, $minLine);
+ }
+
+ # minline > number of lines needs addressing
+ if ($minLine-1 > $#lines){
+ $logger->warn("*--lines specified with min line $minLine which is *greater than* the number of lines in file: ".($#lines+1));
+ $logger->warn("adjusting this value to be ".($#lines+1));
+ $minLine = $#lines+1;
+ }
+
+ # maxline > number of lines needs addressing
+ if ($maxLine-1 > $#lines){
+ $logger->warn("*--lines specified with max line $maxLine which is *greater than* the number of lines in file: ".($#lines+1));
+ $logger->warn("adjusting this value to be ".($#lines+1));
+ $maxLine = $#lines+1;
+ }
+
+ # either store the negation, or not
+ if($negationMode){
+ $negationMinMaxStorage{$minLine} = $maxLine;
+ } else {
+ $minMaxStorage{$minLine} = $maxLine;
+ }
+ $logger->info("min line: $minLine, max line: $maxLine");
+ }
+
+ # only proceed if we have a valid line range
+ if ( (keys %minMaxStorage) < 1 and (keys %negationMinMaxStorage) < 1){
+ $logger->warn("*--lines not specified with valid range: $switches{lines}");
+ $logger->warn("entire body will be indented, and ignoring $switches{lines}");
+ $switches{lines} = 0;
+ ${$self}{body} = join("",@lines);
+ return;
+ }
+
+ # we need to perform the token check here
+ ${$self}{body} = join("",@lines);
+ $self->token_check;
+ ${$self}{body} = q();
+
+ # negated line ranges
+ if (keys %negationMinMaxStorage >= 1){
+ @NOTindentLineRange = &lines_sort_and_combine_line_range(\%negationMinMaxStorage);
+
+ $logger->info("*negation line range summary: ");
+ $logger->info("the number of NEGATION line ranges: ".(($#NOTindentLineRange+1)/2));
+ $logger->info("the *sorted* NEGATION line ranges are in the form MIN-MAX: ");
+ for (my $index=0; $index<(($#NOTindentLineRange+1)/2); $index++){
+ $logger->info(join("-",@NOTindentLineRange[2*$index..2*$index+1]));
+
+ if($index==0 and $NOTindentLineRange[2*$index]>1){
+ $minMaxStorage{1} = $NOTindentLineRange[2*$index]-1;
+ } elsif($index>0){
+ $minMaxStorage{$NOTindentLineRange[2*$index-1]+1} = $NOTindentLineRange[2*$index]-1;
+ }
+ }
+
+ # final range
+ if($NOTindentLineRange[-1]<$#lines){
+ $minMaxStorage{$NOTindentLineRange[-1]+1} = $#lines+1;
+ }
+ }
+
+ @indentLineRange = &lines_sort_and_combine_line_range(\%minMaxStorage) if (keys %minMaxStorage >= 1) ;
+
+ $logger->info("*line range summary: ");
+ $logger->info("the number of indent line ranges: ".(($#indentLineRange+1)/2));
+ $logger->info("the *sorted* line ranges are in the form MIN-MAX: ");
+ for (my $index=0; $index<(($#indentLineRange+1)/2); $index++){
+ $logger->info(join("-",@indentLineRange[2*$index..2*$index+1]));
+ }
+
+ my $startLine = 0;
+
+ # now that we have the line range, we can sort arrange the body
+ while ($#indentLineRange>0){
+ my $minLine = shift(@indentLineRange);
+ my $maxLine = shift(@indentLineRange);
+
+ # perl arrays start at 0
+ $minLine--;
+ $maxLine--;
+
+ $self->lines_verbatim_create_line_block(\@lines,$startLine,$minLine-1) unless ($minLine == 0);
+
+ ${$self}{body} .= join("",@lines[$minLine..$maxLine]);
+
+ $startLine = $maxLine+1;
+ }
+
+ # final line range
+ $self->lines_verbatim_create_line_block(\@lines,$startLine,$#lines) if($startLine<=$#lines);
+ return;
+}
+
+sub lines_sort_and_combine_line_range{
+
+ my %minMaxStorage = %{$_[0]};
+ #
+ # --lines 8-10,4-5,1-2
+ #
+ # needs to be interpretted as
+ #
+ # --lines 1-2,4-5,8-10,
+ #
+ # sort the line ranges by the *minimum* value, the associated
+ # maximum values will be arranged after this
+ my @indentLineRange = sort { $a <=> $b } keys(%minMaxStorage);
+
+ my @justMinimumValues = @indentLineRange;
+ for (my $index=0;$index<=$#justMinimumValues;$index++){
+ splice(@indentLineRange,2*$index+1,0,$minMaxStorage{$justMinimumValues[$index]});
+ }
+
+ for (my $index=1;$index<(($#indentLineRange+1)/2);$index++){
+ my $currentMin = $indentLineRange[2*$index];
+ my $currentMax = $indentLineRange[2*$index+1];
+ my $previousMax = $indentLineRange[2*$index-1];
+ my $previousMin = $indentLineRange[2*$index-2];
+
+ if ( ($currentMin - 1) <= $previousMax and ( $currentMax > $previousMax ) ){
+ # overlapping line ranges, for example
+ #
+ # --lines 3-5,4-10
+ #
+ # needs to be interpretted as
+ #
+ # --lines 3-10
+ #
+ $logger->info("overlapping line range found");
+ $logger->info("line ranges (before): ".join(", ",@indentLineRange));
+ splice(@indentLineRange,2*$index-1,2);
+ $logger->info("line ranges (after): ".join(", ",@indentLineRange));
+
+ # reset index so that loop starts again
+ $index = 0;
+ } elsif ( ($currentMin - 1) <= $previousMax and ( $currentMax <= $previousMax ) ){
+ # overlapping line ranges, for example
+ #
+ # --lines 3-7,4-6
+ #
+ # needs to be interpretted as
+ #
+ # --lines 3-7
+ #
+ $logger->info("overlapping line range found");
+ $logger->info("line ranges (before): ".join(", ",@indentLineRange));
+ splice(@indentLineRange,2*$index,2);
+ $logger->info("line ranges (after): ".join(", ",@indentLineRange));
+
+ # reset index so that loop starts again
+ $index = 0;
+ }
+ }
+
+ return @indentLineRange;
+}
+
+sub lines_verbatim_create_line_block{
+ my $self = shift;
+ my @lines = @{$_[0]};
+ my $startLine = $_[1];
+ my $finishLine = $_[2];
+
+ my $verbBody = join("",@lines[$startLine..$finishLine]);
+ $verbBody =~ s/\R?$//s;
+
+ # create a new Verbatim object
+ my $noIndentBlockObj = LatexIndent::Verbatim->new( begin=>q(),
+ body=>$verbBody,
+ end=>q(),
+ name=>"line-switch-verbatim-protection",
+ type=>"linesprotect",
+ modifyLineBreaksYamlName=>"lines-not-to-be-indented",
+ );
+
+ # give unique id
+ $noIndentBlockObj->create_unique_id;
+
+ # verbatim children go in special hash
+ $verbatimStorage{${$noIndentBlockObj}{id}}=$noIndentBlockObj;
+
+ # remove the environment block, and replace with unique ID
+ ${$self}{body} .= ${$noIndentBlockObj}{id}."\n";
+
+ return;
+}
+
+1;