summaryrefslogtreecommitdiff
path: root/support/latexindent
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/latexindent
Initial commit
Diffstat (limited to 'support/latexindent')
-rw-r--r--support/latexindent/LatexIndent/AlignmentAtAmpersand.pm525
-rw-r--r--support/latexindent/LatexIndent/Arguments.pm409
-rw-r--r--support/latexindent/LatexIndent/BackUpFileProcedure.pm136
-rw-r--r--support/latexindent/LatexIndent/BlankLines.pm126
-rw-r--r--support/latexindent/LatexIndent/Braces.pm189
-rw-r--r--support/latexindent/LatexIndent/Command.pm215
-rw-r--r--support/latexindent/LatexIndent/Document.pm406
-rw-r--r--support/latexindent/LatexIndent/DoubleBackSlash.pm45
-rw-r--r--support/latexindent/LatexIndent/Else.pm134
-rw-r--r--support/latexindent/LatexIndent/Environment.pm139
-rw-r--r--support/latexindent/LatexIndent/FileContents.pm265
-rw-r--r--support/latexindent/LatexIndent/FileExtension.pm154
-rw-r--r--support/latexindent/LatexIndent/GetYamlSettings.pm929
-rw-r--r--support/latexindent/LatexIndent/Heading.pm245
-rw-r--r--support/latexindent/LatexIndent/HiddenChildren.pm205
-rw-r--r--support/latexindent/LatexIndent/HorizontalWhiteSpace.pm79
-rw-r--r--support/latexindent/LatexIndent/IfElseFi.pm211
-rw-r--r--support/latexindent/LatexIndent/Indent.pm425
-rw-r--r--support/latexindent/LatexIndent/Item.pm148
-rw-r--r--support/latexindent/LatexIndent/KeyEqualsValuesBraces.pm121
-rw-r--r--support/latexindent/LatexIndent/LogFile.pm251
-rw-r--r--support/latexindent/LatexIndent/MandatoryArgument.pm135
-rw-r--r--support/latexindent/LatexIndent/ModifyLineBreaks.pm394
-rw-r--r--support/latexindent/LatexIndent/NamedGroupingBracesBrackets.pm77
-rw-r--r--support/latexindent/LatexIndent/OptionalArgument.pm120
-rw-r--r--support/latexindent/LatexIndent/Preamble.pm90
-rw-r--r--support/latexindent/LatexIndent/Replacement.pm89
-rw-r--r--support/latexindent/LatexIndent/RoundBrackets.pm100
-rw-r--r--support/latexindent/LatexIndent/Sentence.pm362
-rw-r--r--support/latexindent/LatexIndent/Special.pm272
-rw-r--r--support/latexindent/LatexIndent/Switches.pm44
-rw-r--r--support/latexindent/LatexIndent/Tokens.pm74
-rw-r--r--support/latexindent/LatexIndent/TrailingComments.pm132
-rw-r--r--support/latexindent/LatexIndent/UnNamedGroupingBracesBrackets.pm138
-rw-r--r--support/latexindent/LatexIndent/Verbatim.pm435
-rw-r--r--support/latexindent/LatexIndent/Version.pm24
-rw-r--r--support/latexindent/README57
-rw-r--r--support/latexindent/defaultSettings.yaml603
-rw-r--r--support/latexindent/documentation/appendices.tex247
-rw-r--r--support/latexindent/documentation/cmhlistings.tex28
-rw-r--r--support/latexindent/documentation/figure-schematic.tex33
-rw-r--r--support/latexindent/documentation/latexindent.pdfbin0 -> 855773 bytes
-rw-r--r--support/latexindent/documentation/latexindent.tex777
-rw-r--r--support/latexindent/documentation/logo.tex33
-rw-r--r--support/latexindent/documentation/references.tex4
-rw-r--r--support/latexindent/documentation/sec-conclusions-know-limitations.tex38
-rw-r--r--support/latexindent/documentation/sec-default-user-local.tex737
-rw-r--r--support/latexindent/documentation/sec-demonstration.tex40
-rw-r--r--support/latexindent/documentation/sec-fine-tuning.tex109
-rw-r--r--support/latexindent/documentation/sec-how-to-use.tex391
-rw-r--r--support/latexindent/documentation/sec-indent-config-and-settings.tex179
-rw-r--r--support/latexindent/documentation/sec-introduction.tex130
-rw-r--r--support/latexindent/documentation/sec-replacements.tex372
-rw-r--r--support/latexindent/documentation/sec-the-m-switch.tex1746
-rw-r--r--support/latexindent/documentation/subsec-commands-and-their-options.tex245
-rw-r--r--support/latexindent/documentation/subsec-conflicting-poly-switches.tex160
-rw-r--r--support/latexindent/documentation/subsec-noAdditionalIndent-indentRules.tex27
-rw-r--r--support/latexindent/documentation/subsec-partnering-poly-switches.tex51
-rw-r--r--support/latexindent/documentation/subsubsec-commands-with-arguments.tex104
-rw-r--r--support/latexindent/documentation/subsubsec-environments-and-their-arguments.tex283
-rw-r--r--support/latexindent/documentation/subsubsec-environments-with-items.tex61
-rw-r--r--support/latexindent/documentation/subsubsec-headings.tex85
-rw-r--r--support/latexindent/documentation/subsubsec-ifelsefi.tex84
-rw-r--r--support/latexindent/documentation/subsubsec-no-add-remaining-code-blocks.tex135
-rw-r--r--support/latexindent/documentation/subsubsec-special.tex63
-rw-r--r--support/latexindent/documentation/title.tex27
-rwxr-xr-xsupport/latexindent/latexindent-module-installer.pl49
-rwxr-xr-xsupport/latexindent/latexindent.pl81
68 files changed, 14822 insertions, 0 deletions
diff --git a/support/latexindent/LatexIndent/AlignmentAtAmpersand.pm b/support/latexindent/LatexIndent/AlignmentAtAmpersand.pm
new file mode 100644
index 0000000000..8b8e387d09
--- /dev/null
+++ b/support/latexindent/LatexIndent/AlignmentAtAmpersand.pm
@@ -0,0 +1,525 @@
+package LatexIndent::AlignmentAtAmpersand;
+# 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 utf8;
+use Unicode::GCString;
+use Data::Dumper;
+use Exporter qw/import/;
+use List::Util qw(max);
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::LogFile qw/$logger/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/align_at_ampersand find_aligned_block double_back_slash_else/;
+our $alignmentBlockCounter;
+
+sub find_aligned_block{
+ my $self = shift;
+
+ return unless (${$self}{body} =~ m/(?!<\\)%\*\h*\\begin\{/s);
+
+ # aligned block
+ # %* \begin{tabular}
+ # 1 & 2 & 3 & 4 \\
+ # 5 & & 6 & \\
+ # %* \end{tabular}
+ $logger->trace('*Searching for ALIGNED blocks marked by comments')if($is_t_switch_active);
+ $logger->trace(Dumper(\%{$masterSettings{lookForAlignDelims}})) if($is_tt_switch_active);
+ while( my ($alignmentBlock,$yesno)= each %{$masterSettings{lookForAlignDelims}}){
+ if(ref $yesno eq "HASH"){
+ $yesno = (defined ${$yesno}{delims} ) ? ${$yesno}{delims} : 1;
+ }
+ if($yesno){
+ $logger->trace("looking for %*\\begin\{$alignmentBlock\} environments");
+
+ my $alignmentRegExp = qr/
+ (
+ (?!<\\)
+ %
+ \*
+ \h* # possible horizontal spaces
+ \\begin\{
+ $alignmentBlock # environment name captured into $2
+ \} # %* \begin{alignmentBlock} statement
+ )
+ (
+ .*?
+ )
+ \R
+ \h*
+ (
+ (?!<\\)
+ %\* # %
+ \h* # possible horizontal spaces
+ \\end\{$alignmentBlock\} # \end{alignmentBlock}
+ ) # %* \end{<something>} statement
+ #\R
+ /sx;
+
+ while( ${$self}{body} =~ m/$alignmentRegExp/sx){
+
+ ${$self}{body} =~ s/
+ $alignmentRegExp
+ /
+ # create a new Environment object
+ my $alignmentBlockObj = LatexIndent::AlignmentAtAmpersand->new( begin=>$1,
+ body=>$2,
+ end=>$3,
+ name=>$alignmentBlock,
+ modifyLineBreaksYamlName=>"environments",
+ linebreaksAtEnd=>{
+ begin=>1,
+ body=>1,
+ end=>0,
+ },
+ );
+
+ # log file output
+ $logger->trace("*Alignment block found: %*\\begin\{$alignmentBlock\}") if $is_t_switch_active;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($alignmentBlockObj);
+
+ ${@{${$self}{children}}[-1]}{replacementText};
+ /xseg;
+ }
+ } else {
+ $logger->trace("*not* looking for $alignmentBlock as $alignmentBlock:$yesno");
+ }
+ }
+ return;
+}
+
+sub yaml_modify_line_breaks_settings{
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ return;
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $alignmentBlockCounter++;
+ ${$self}{id} = "$tokens{alignmentBlock}$alignmentBlockCounter";
+ return;
+}
+
+sub align_at_ampersand{
+ my $self = shift;
+ return if(${$self}{bodyLineBreaks}==0);
+
+ # calculate the maximum number of ampersands in a row in the body
+ my $maximumNumberOfAmpersands = 0;
+ foreach(split("\n",${$self}{body})){
+ my $numberOfAmpersands = () = $_ =~ /(?<!\\)&/g;
+ $maximumNumberOfAmpersands = $numberOfAmpersands if($numberOfAmpersands>$maximumNumberOfAmpersands);
+ }
+
+ # create an array of zeros
+ my @maximumColumnWidth = (0) x ($maximumNumberOfAmpersands+1);
+ my @maximumColumnWidthMC = (0) x ($maximumNumberOfAmpersands+1);
+
+ # array for the new body
+ my @formattedBody;
+
+ # now loop back through the body, and store the maximum column size
+ foreach(split("\n",${$self}{body})){
+ # remove \\ and anything following it
+ my $endPiece;
+ if($_ =~ m/(\\\\.*)/){
+ $_ =~ s/(\\\\.*)//;
+ $endPiece = $1;
+ }
+
+ # remove any trailing comments
+ my $trailingComments;
+ if($_ =~ m/$trailingCommentRegExp/ ){
+ $_ =~ s/($trailingCommentRegExp)//;
+ $trailingComments = $1;
+ }
+
+ # count the number of ampersands in the current row
+ my $numberOfAmpersands = () = $_ =~ /(?<!\\)&/g;
+
+ # switch for multiColumGrouping
+ my $multiColumnGrouping = ($_ =~ m/\\multicolumn/ and ${$self}{multiColumnGrouping});
+ my $alignRowsWithoutMaxDelims = ${$self}{alignRowsWithoutMaxDelims};
+
+ # by default, the stripped row is simply the current row
+ my $strippedRow = $_;
+
+ # loop through the columns
+ my $columnCount = 0;
+
+ # format switch off by default
+ my $formatRow = 0;
+
+ # store the column sizes for measuring and comparison purposes
+ my @columnSizes = ();
+
+ # we will store the columns in each row
+ my @columns;
+
+ # need to have at least one ampersand, or contain a \multicolumn command
+ if( ($_ =~ m/(?<!\\)&/ and ( ($numberOfAmpersands == $maximumNumberOfAmpersands)||$multiColumnGrouping||$alignRowsWithoutMaxDelims ) )
+ or
+ ($multiColumnGrouping and $alignRowsWithoutMaxDelims) ){
+ # remove space at the beginning of a row, surrounding &, and at the end of the row
+ $_ =~ s/(?<!\\)\h*(?<!\\)&\h*/&/g;
+ $_ =~ s/^\h*//g;
+ $_ =~ s/\h*$//g;
+
+ # if the line finishes with an &, then add an empty space,
+ # otherwise the column count is off
+ $_ .= ($_ =~ m/(?<!\\)&$/ ? " ":q());
+
+ # store the columns, which are either split by &
+ # or otherwise simply the current line, if for example, the current line simply
+ # contains \multicolumn{8}... \\ (see test-cases/texexchange/366841-zarko.tex, for example)
+ @columns = ($_ =~ m/(?<!\\)&/ ? split(/(?<!\\)&/,$_) : $_);
+
+ # empty the white-space-stripped row
+ $strippedRow = '';
+ foreach my $column (@columns){
+ # if a column has finished with a \ then we need to add a trailing space,
+ # otherwise the \ can be put next to &. See test-cases/texexchange/112343-gonzalo for example
+ $column .= ($column =~ m/\\$/ ? " ": q());
+
+ # store the column size
+ # reference: http://www.perl.com/pub/2012/05/perlunicook-unicode-column-width-for-printing.html
+ my $gcs = Unicode::GCString->new($column);
+ my $columnWidth = $gcs->columns();
+
+ # multicolumn cells need a bit of special care
+ if($multiColumnGrouping and $column =~ m/\\multicolumn\{(\d+)\}/ and $1>1){
+ $maximumColumnWidthMC[$columnCount] = $columnWidth if( defined $maximumColumnWidthMC[$columnCount] and ($columnWidth > $maximumColumnWidthMC[$columnCount]) );
+ $columnWidth = 1 if($multiColumnGrouping and ($column =~ m/\\multicolumn\{(\d+)\}/));
+ }
+
+ # store the maximum column width
+ $maximumColumnWidth[$columnCount] = $columnWidth if( defined $maximumColumnWidth[$columnCount] and ($columnWidth > $maximumColumnWidth[$columnCount]) );
+
+ # put the row back together, using " " if the column is empty
+ $strippedRow .= ($columnCount>0 ? "&" : q() ).($columnWidth > 0 ? $column: " ");
+
+ # store the column width
+ $columnSizes[$columnCount] = $columnWidth;
+
+ # move on to the next column
+ if($multiColumnGrouping and ($column =~ m/\\multicolumn\{(\d+)\}/)){
+ # columns that are within the multiCol statement receive a width of -1
+ for my $i (($columnCount+1)..($columnCount+$1)){
+ $columnSizes[$i] = -1;
+ }
+ # update the columnCount to account for the multiColSpan
+ $columnCount += $1;
+ } else {
+ $columnCount++;
+ }
+ }
+
+ # toggle the formatting switch
+ $formatRow = 1;
+ } elsif($endPiece and ${$self}{alignDoubleBackSlash}){
+ # otherwise a row could contain no ampersands, but would still desire
+ # the \\ to be aligned, see test-cases/alignment/multicol-no-ampersands.tex
+ @columns = $_;
+ $formatRow = 1;
+ }
+
+ # store the information
+ push(@formattedBody,{
+ row=>$strippedRow,
+ format=>$formatRow,
+ multiColumnGrouping=>$multiColumnGrouping,
+ columnSizes=>\@columnSizes,
+ columns=>\@columns,
+ endPiece=>($endPiece ? $endPiece :q() ),
+ trailingComment=>($trailingComments ? $trailingComments :q() )});
+ }
+
+ # output some of the info so far to the log file
+ $logger->trace("*Alignment at ampersand routine for ${$self}{name} (see lookForAlignDelims)") if $is_t_switch_active;
+ $logger->trace("Maximum column sizes of horizontally stripped formatted block (${$self}{name}): @maximumColumnWidth") if $is_t_switch_active;
+ $logger->trace("align at ampersand: ${$self}{lookForAlignDelims}") if $is_t_switch_active;
+ $logger->trace("align at \\\\: ${$self}{alignDoubleBackSlash}") if $is_t_switch_active;
+ $logger->trace("spaces before \\\\: ${$self}{spacesBeforeDoubleBackSlash}") if $is_t_switch_active;
+ $logger->trace("multi column grouping: ${$self}{multiColumnGrouping}") if $is_t_switch_active;
+ $logger->trace("align rows without maximum delimeters: ${$self}{alignRowsWithoutMaxDelims}") if $is_t_switch_active;
+ $logger->trace("spaces before ampersand: ${$self}{spacesBeforeAmpersand}") if $is_t_switch_active;
+ $logger->trace("spaces after ampersand: ${$self}{spacesAfterAmpersand}") if $is_t_switch_active;
+ $logger->trace("justification: ${$self}{justification}") if $is_t_switch_active;
+
+ # acount for multicolumn grouping, if the appropriate switch is set
+ if(${$self}{multiColumnGrouping}){
+ foreach(@formattedBody){
+ if(${$_}{format} and ${$_}{row} !~ m/^\h*$/){
+
+ # set a columnCount, which will vary depending on multiColumnGrouping settings or not
+ my $columnCount=0;
+
+ # loop through the columns
+ foreach my $column (@{${$_}{columns}}){
+ # calculate the width of the current column
+ my $gcs = Unicode::GCString->new($column);
+ my $columnWidth = $gcs->columns();
+
+ # check for multiColumnGrouping
+ if(${$_}{multiColumnGrouping} and $column =~ m/\\multicolumn\{(\d+)\}/ and $1>1){
+ my $multiColSpan = $1;
+
+ # for example, \multicolumn{3}{c}{<stuff>} spans 3 columns, so
+ # the maximum column needs to account for this (subtract 1 because of 0 index in perl arrays)
+ my $columnMax = $columnCount+$multiColSpan-1;
+
+ # groupingWidth contains the total width of column sizes grouped
+ # underneath the \multicolumn{} statement
+ my $groupingWidth = 0;
+ my $maxGroupingWidth = 0;
+ foreach (@formattedBody){
+ $groupingWidth = 0;
+
+ # loop through the columns covered by the multicolumn statement
+ foreach my $j ($columnCount..$columnMax){
+ if( defined @{${$_}{columnSizes}}[$j]
+ and
+ @{${$_}{columnSizes}}[$j] >= 0
+ and
+ ${$_}{format}
+ ){
+ $groupingWidth += (defined $maximumColumnWidth[$j] ? $maximumColumnWidth[$j] : 0);
+ } else {
+ $groupingWidth = 0;
+ }
+ }
+
+ # update the maximum grouping width
+ $maxGroupingWidth = $groupingWidth if($groupingWidth > $maxGroupingWidth);
+
+ # the cells that receive multicolumn grouping need extra padding; in particular
+ # if the justification is *left*:
+ # the *last* cell of the multicol group receives the padding
+ # if the justification is *right*:
+ # the *first* cell of the multicol group receives the padding
+ #
+ # this motivates the introduction of $columnOffset, which is
+ # 0 if justification is left
+ # $multiColSpan if justification is right
+ my $columnOffset = (${$self}{justification} eq "left") ? $columnMax : $columnCount;
+ if(defined @{${$_}{columnSizes}}[$columnMax] and ($columnWidth > ($groupingWidth+(${$self}{spacesBeforeAmpersand}+1+${$self}{spacesAfterAmpersand})*($multiColSpan-1)) ) and @{${$_}{columnSizes}}[$columnMax] >= 0){
+ my $multiColPadding = $columnWidth-$groupingWidth-(${$self}{spacesBeforeAmpersand}+1+${$self}{spacesAfterAmpersand})*($multiColSpan-1);
+
+ # it's possible that multiColPadding might already be assigned; in which case,
+ # we need to check that the current value of $multiColPadding is greater than the existing one
+ if(defined @{${$_}{multiColPadding}}[$columnOffset]){
+ @{${$_}{multiColPadding}}[$columnOffset] = max($multiColPadding,@{${$_}{multiColPadding}}[$columnOffset]);
+ } else {
+ @{${$_}{multiColPadding}}[$columnOffset] = $multiColPadding;
+ }
+
+ # also need to account for maximum column width *including* other multicolumn statements
+ if($maximumColumnWidthMC[$columnCount]>$columnWidth and $column !~ m/\\multicolumn\{(\d+)\}/){
+ @{${$_}{multiColPadding}}[$columnOffset] += ($maximumColumnWidthMC[$columnCount]-$columnWidth);
+ }
+ }
+ }
+ # update it to account for the ampersands and the spacing either side of ampersands
+ $maxGroupingWidth += ($multiColSpan-1)*(${$self}{spacesBeforeAmpersand}+1+${$self}{spacesAfterAmpersand});
+
+ # store the maxGroupingWidth for use in the next loop
+ @{${$_}{maxGroupingWidth}}[$columnCount] = $maxGroupingWidth;
+
+ # update the columnCount to account for the multiColSpan
+ $columnCount += $multiColSpan - 1;
+ }
+
+ # increase the column count
+ $columnCount++;
+ }
+ }
+ }
+ }
+
+ # the maximum row width will be used in aligning (or not) the \\
+ my $maximumRowWidth = 0;
+
+ # now that the multicolumn widths have been accounted for, loop through the body
+ foreach(@formattedBody){
+ if(${$_}{format} and ${$_}{row} !~ m/^\h*$/){
+
+ # set a columnCount, which will vary depending on multiColumnGrouping settings or not
+ my $columnCount=0;
+ my $tmpRow = q();
+
+ # loop through the columns
+ foreach my $column (@{${$_}{columns}}){
+ # calculate the width of the current column
+ my $gcs = Unicode::GCString->new($column);
+ my $columnWidth = $gcs->columns();
+
+ # reset the column padding
+ my $padding = q();
+
+ # check for multiColumnGrouping
+ if(${$_}{multiColumnGrouping} and $column =~ m/\\multicolumn\{(\d+)\}/ and $1>1){
+ my $multiColSpan = $1;
+
+ # groupingWidth contains the total width of column sizes grouped
+ # underneath the \multicolumn{} statement
+ my $maxGroupingWidth = ${${$_}{maxGroupingWidth}}[$columnCount];
+
+ # it's possible to have situations such as
+ #
+ # \multicolumn{3}{l}{one} & \multicolumn{3}{l}{two} & \\
+ # \multicolumn{6}{l}{one} & \\
+ #
+ # in which case we need to loop through the @maximumColumnWidthMC
+ my $groupingWidthMC = 0;
+ my $multicolsEncountered =0;
+ for ($columnCount..($columnCount + ($multiColSpan-1))){
+ if(defined $maximumColumnWidthMC[$_]){
+ $groupingWidthMC += $maximumColumnWidthMC[$_];
+ $multicolsEncountered++ if $maximumColumnWidthMC[$_]>0;
+ }
+ }
+
+ # need to account for (spacesBeforeAmpersands) + length of ampersands (which is 1) + (spacesAfterAmpersands)
+ $groupingWidthMC += ($multicolsEncountered-1)*(${$self}{spacesBeforeAmpersand}+1+${$self}{spacesAfterAmpersand});
+
+ # set the padding; we need
+ # maximum( $maxGroupingWidth, $maximumColumnWidthMC[$columnCount] )
+ my $maxValueToUse = 0;
+ if(defined $maximumColumnWidthMC[$columnCount]){
+ $maxValueToUse = max($maxGroupingWidth,$maximumColumnWidthMC[$columnCount],$groupingWidthMC);
+ } else {
+ $maxValueToUse = $maxGroupingWidth;
+ }
+
+ # calculate the padding
+ $padding = " " x ( $maxValueToUse >= $columnWidth ? $maxValueToUse - $columnWidth : 0 );
+
+ # to the log file
+ if($is_tt_switch_active){
+ $logger->trace("*---------column-------------");
+ $logger->trace($column);
+ $logger->trace("multiColSpan: $multiColSpan");
+ $logger->trace("groupingWidthMC: $groupingWidthMC");
+ $logger->trace("padding length: ",$maxValueToUse - $columnWidth);
+ $logger->trace("multicolsEncountered: $multicolsEncountered");
+ $logger->trace("maxValueToUse: $maxValueToUse");
+ $logger->trace("maximumColumnWidth: ",join(",",@maximumColumnWidth));
+ $logger->trace("maximumColumnWidthMC: ",join(",",@maximumColumnWidthMC));
+ }
+
+ # update the columnCount to account for the multiColSpan
+ $columnCount += $multiColSpan - 1;
+ } else {
+ # compare the *current* column width with the *maximum* column width
+ $padding = " " x (defined $maximumColumnWidth[$columnCount] and $maximumColumnWidth[$columnCount] >= $columnWidth ? $maximumColumnWidth[$columnCount] - $columnWidth : 0);
+ }
+
+ # either way, the row is formed of "COLUMN + PADDING"
+ if(${$self}{justification} eq "left"){
+ $tmpRow .= $column.$padding.(defined @{${$_}{multiColPadding}}[$columnCount] ? " " x @{${$_}{multiColPadding}}[$columnCount]: q()).(" " x ${$self}{spacesBeforeAmpersand})."&".(" " x ${$self}{spacesAfterAmpersand});
+ } else {
+ $tmpRow .= $padding.(defined @{${$_}{multiColPadding}}[$columnCount] ? " " x @{${$_}{multiColPadding}}[$columnCount]: q()).$column.(" " x ${$self}{spacesBeforeAmpersand})."&".(" " x ${$self}{spacesAfterAmpersand});
+ }
+ $columnCount++;
+ }
+
+ # remove the final &
+ $tmpRow =~ s/\h*&\h*$/ /;
+ my $finalSpacing = q();
+ $finalSpacing = " " x (${$self}{spacesBeforeDoubleBackSlash}) if ${$self}{spacesBeforeDoubleBackSlash}>=1;
+ $tmpRow =~ s/\h*$/$finalSpacing/;
+
+ # replace the row with the formatted row
+ ${$_}{row} = $tmpRow;
+
+ # update the maximum row width
+ my $gcs = Unicode::GCString->new($tmpRow);
+ ${$_}{rowWidth} = $gcs->columns();
+ $maximumRowWidth = ${$_}{rowWidth} if(${$_}{rowWidth} > $maximumRowWidth);
+ }
+ }
+
+ # final loop through to get \\ aligned
+ foreach (@formattedBody){
+ # reset the padding
+ my $padding = q();
+
+ # possibly adjust the padding
+ if(${$_}{format} and ${$_}{row} !~ m/^\h*$/){
+ # remove trailing horizontal space if ${$self}{alignDoubleBackSlash} is set to 0
+ ${$_}{row} =~ s/\h*$// if (!${$self}{alignDoubleBackSlash});
+
+ # format spacing infront of \\
+ if(defined ${$self}{spacesBeforeDoubleBackSlash} and ${$self}{spacesBeforeDoubleBackSlash}<0 and !${$self}{alignDoubleBackSlash}){
+ # zero spaces (possibly resulting in un-aligned \\)
+ $padding = q();
+ } elsif(defined ${$self}{spacesBeforeDoubleBackSlash} and ${$self}{spacesBeforeDoubleBackSlash}>=0 and !${$self}{alignDoubleBackSlash}){
+ # specified number of spaces (possibly resulting in un-aligned \\)
+ $padding = " " x (${$self}{spacesBeforeDoubleBackSlash});
+ } else {
+ # aligned \\
+ $padding = " " x ($maximumRowWidth - ${$_}{rowWidth});
+ }
+ }
+
+ # format the row, and put the trailing \\ and trailing comments back into the row
+ ${$_}{row} .= $padding.(${$_}{endPiece} ? ${$_}{endPiece} :q() ).(${$_}{trailingComment}? ${$_}{trailingComment} : q() );
+ }
+
+ # to the log file
+ if($is_tt_switch_active){
+ $logger->trace(${$_}{row}) for @formattedBody;
+ }
+
+ # delete the original body
+ ${$self}{body} = q();
+
+ # update the body
+ ${$self}{body} .= ${$_}{row}."\n" for @formattedBody;
+
+ # if the \end{} statement didn't originally have a line break before it, we need to remove the final
+ # line break added by the above
+ ${$self}{body} =~ s/\h*\R$//s if !${$self}{linebreaksAtEnd}{body};
+}
+
+sub double_back_slash_else{
+ my $self = shift;
+
+ # check for existence of \\ statement, and associated line break information
+ $self->check_for_else_statement(
+ # else name regexp
+ elseNameRegExp=>qr/${${$masterSettings{fineTuning}}{modifyLineBreaks}}{doubleBackSlash}/,
+ # else statements name: note that DBS stands for 'Double Back Slash'
+ ElseStartsOnOwnLine=>"DBSStartsOnOwnLine",
+ # end statements
+ ElseFinishesWithLineBreak=>"DBSFinishesWithLineBreak",
+ # for the YAML settings storage
+ storageNameAppend=>"DBS",
+ # logfile information
+ logName=>"double-back-slash-block (for align at ampersand, see lookForAlignDelims)",
+ );
+}
+1;
diff --git a/support/latexindent/LatexIndent/Arguments.pm b/support/latexindent/LatexIndent/Arguments.pm
new file mode 100644
index 0000000000..96450fdaaf
--- /dev/null
+++ b/support/latexindent/LatexIndent/Arguments.pm
@@ -0,0 +1,409 @@
+package LatexIndent::Arguments;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::LogFile qw/$logger/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/get_arguments_regexp find_opt_mand_arguments construct_arguments_regexp $optAndMandRegExp comma_else/;
+our $ArgumentCounter;
+our $optAndMandRegExp;
+our $optAndMandRegExpWithLineBreaks;
+
+sub construct_arguments_regexp{
+ my $self = shift;
+
+ $optAndMandRegExp = $self->get_arguments_regexp;
+
+ $optAndMandRegExpWithLineBreaks = $self->get_arguments_regexp(mode=>"lineBreaksAtEnd");
+}
+
+sub indent{
+ my $self = shift;
+ ${$self}{body} =~ s/\R$//s if ($is_m_switch_active and ${$self}{IDFollowedImmediatelyByLineBreak});
+ $logger->trace("*Arguments object doesn't receive any direct indentation, but its children will...") if $is_t_switch_active;
+ return;
+}
+
+sub find_opt_mand_arguments{
+ my $self = shift;
+
+ $logger->trace("*Searching ${$self}{name} for optional and mandatory arguments") if $is_t_switch_active;
+
+ # blank line token
+ my $blankLineToken = $tokens{blanklines};
+
+ # the command object allows ()
+ my $objectDependentOptAndMandRegExp = (defined ${$self}{optAndMandArgsRegExp} ? ${$self}{optAndMandArgsRegExp} : $optAndMandRegExpWithLineBreaks);
+
+ if(${$self}{body} =~ m/^$objectDependentOptAndMandRegExp\h*($trailingCommentRegExp)?/){
+ $logger->trace("Optional/Mandatory arguments".(${$masterSettings{commandCodeBlocks}}{roundParenthesesAllowed}?" (possibly round Parentheses)":q())." found in ${$self}{name}: $1") if $is_t_switch_active;
+
+ # create a new Arguments object
+ # The arguments object is a little different to most
+ # other objects, as it is created purely for its children,
+ # so some of the properties common to other objects, such
+ # as environment, ifelsefi, etc do not exist for Arguments;
+ # they will, however, exist for its children: OptionalArgument, MandatoryArgument
+ my $arguments = LatexIndent::Arguments->new(begin=>"",
+ name=>${$self}{name}.":arguments",
+ parent=>${$self}{name},
+ body=>$1,
+ linebreaksAtEnd=>{
+ end=>$2?1:0,
+ },
+ end=>"",
+ regexp=>$objectDependentOptAndMandRegExp,
+ endImmediatelyFollowedByComment=>$2?0:($3?1:0),
+ );
+
+ # give unique id
+ $arguments->create_unique_id;
+
+ # text wrapping can make the ID split across lines
+ ${$arguments}{idRegExp} = ${$arguments}{id};
+
+ if($is_m_switch_active){
+ my $IDwithLineBreaks = join("\\R?\\h*",split(//,${$arguments}{id}));
+ ${$arguments}{idRegExp} = qr/$IDwithLineBreaks/s;
+ }
+
+ # determine which comes first, optional or mandatory
+ if(${$arguments}{body} =~ m/.*?((?<!\\)\{|\[)/s){
+
+ if($1 eq "\["){
+ $logger->trace("Searching for optional arguments, and then mandatory (optional found first)") if $is_t_switch_active;
+ # look for optional arguments
+ $arguments->find_optional_arguments;
+
+ # look for mandatory arguments
+ $arguments->find_mandatory_arguments;
+ } else {
+ $logger->trace("Searching for mandatory arguments, and then optional (mandatory found first)") if $is_t_switch_active;
+ # look for mandatory arguments
+ $arguments->find_mandatory_arguments;
+
+ # look for optional arguments
+ $arguments->find_optional_arguments;
+ }
+
+ # it's possible not to have any mandatory or optional arguments, see
+ # https://github.com/cmhughes/latexindent.pl/issues/123
+ if( !(defined ${$arguments}{children}) ){
+ $logger->trace("No optional or mandatory arguments found; searching for matching round parenthesis") if $is_t_switch_active;
+ $arguments->find_round_brackets;
+ }
+ } else {
+ $logger->trace("Searching for round brackets ONLY") if $is_t_switch_active;
+ # look for round brackets
+ $arguments->find_round_brackets;
+ }
+
+ # examine *first* child
+ # situation: parent BodyStartsOnOwnLine >= 1, but first child has BeginStartsOnOwnLine == 0 || BeginStartsOnOwnLine == undef
+ # problem: the *body* of parent actually starts after the arguments
+ # solution: remove the linebreak at the end of the begin statement of the parent
+ if(defined ${$self}{BodyStartsOnOwnLine} and ${$self}{BodyStartsOnOwnLine}>=1){
+ if( !(defined ${${${$arguments}{children}}[0]}{BeginStartsOnOwnLine} and ${${${$arguments}{children}}[0]}{BeginStartsOnOwnLine}>=1)
+ and ${$self}{body} !~ m/^$blankLineToken/){
+ my $BodyStringLogFile = ${$self}{aliases}{BodyStartsOnOwnLine}||"BodyStartsOnOwnLine";
+ my $BeginStringLogFile = ${${${$arguments}{children}}[0]}{aliases}{BeginStartsOnOwnLine}||"BeginStartsOnOwnLine";
+ $logger->trace("$BodyStringLogFile = 1 (in ${$self}{name}), but first argument should not begin on its own line (see $BeginStringLogFile)") if $is_t_switch_active;
+ $logger->trace("Removing line breaks at the end of ${$self}{begin}") if $is_t_switch_active;
+ ${$self}{begin} =~ s/\R*$//s;
+ ${$self}{linebreaksAtEnd}{begin} = 0;
+ }
+ }
+
+ # situation: preserveBlankLines is active, so the body may well begin with a blank line token
+ # which means that ${$self}{linebreaksAtEnd}{begin} *should be* 1
+ if(${${${$arguments}{children}}[0]}{body} =~ m/^($blankLineToken)/){
+ $logger->trace("Updating {linebreaksAtEnd}{begin} for ${$self}{name} as $blankLineToken or blank line found at beginning of argument child") if $is_t_switch_active;
+ ${$self}{linebreaksAtEnd}{begin} = 1
+ }
+
+ # examine *first* child
+ # situation: parent BodyStartsOnOwnLine == -1, but first child has BeginStartsOnOwnLine == 1
+ # problem: the *body* of parent actually starts after the arguments
+ # solution: add a linebreak at the end of the begin statement of the parent so that
+ # the child settings are obeyed.
+ # BodyStartsOnOwnLine == 0 will actually be controlled by the last arguments'
+ # settings of EndFinishesWithLineBreak
+ if( ${$self}{linebreaksAtEnd}{begin} == 0
+ and ((defined ${$self}{BodyStartsOnOwnLine} and ${$self}{BodyStartsOnOwnLine}==-1)
+ or !(defined ${$self}{BodyStartsOnOwnLine}))
+ ){
+ if(defined ${${${$arguments}{children}}[0]}{BeginStartsOnOwnLine} and ${${${$arguments}{children}}[0]}{BeginStartsOnOwnLine}>=1){
+ my $BodyStringLogFile = ${$self}{aliases}{BodyStartsOnOwnLine}||"BodyStartsOnOwnLine";
+ my $BeginStringLogFile = ${${${$arguments}{children}}[0]}{aliases}{BeginStartsOnOwnLine}||"BeginStartsOnOwnLine";
+ my $BodyValue = (defined ${$self}{BodyStartsOnOwnLine}) ? ${$self}{BodyStartsOnOwnLine} : "0";
+ $logger->trace("$BodyStringLogFile = $BodyValue (in ${$self}{name}), but first argument *should* begin on its own line (see $BeginStringLogFile)") if $is_t_switch_active;
+
+ # possibly add a comment or a blank line, depending on if BeginStartsOnOwnLine == 2 or 3 respectively
+ # at the end of the begin statement
+ my $trailingCharacterToken = q();
+ if(${${${$arguments}{children}}[0]}{BeginStartsOnOwnLine}==1){
+ $logger->trace("Adding line breaks at the end of ${$self}{begin} (first argument, see $BeginStringLogFile == ${${${$arguments}{children}}[0]}{BeginStartsOnOwnLine})") if $is_t_switch_active;
+ } elsif(${${${$arguments}{children}}[0]}{BeginStartsOnOwnLine}==2){
+ $logger->trace("Adding a % at the end of begin, ${$self}{begin} followed by a linebreak ($BeginStringLogFile == 2)") if $is_t_switch_active;
+ $trailingCharacterToken = "%".$self->add_comment_symbol;
+ $logger->trace("Removing trailing space on ${$self}{begin}") if $is_t_switch_active;
+ ${$self}{begin} =~ s/\h*$//s;
+ } elsif (${${${$arguments}{children}}[0]}{BeginStartsOnOwnLine}==3) {
+ $logger->trace("Adding a blank line immediately ${$self}{begin} ($BeginStringLogFile==3)") if $is_t_switch_active;
+ $trailingCharacterToken = "\n".(${$masterSettings{modifyLineBreaks}}{preserveBlankLines}?$tokens{blanklines}:q());
+ }
+
+ # modification
+ ${$self}{begin} .= "$trailingCharacterToken\n";
+ ${$self}{linebreaksAtEnd}{begin} = 1;
+ }
+ }
+
+ # the replacement text can be just the ID, but the ID might have a line break at the end of it
+ ${$arguments}{replacementText} = ${$arguments}{id};
+
+ # children need to receive ancestor information, see test-cases/commands/commands-triple-nested.tex
+ foreach (@{${$arguments}{children}}){
+ $logger->trace("Updating argument child of ${$self}{name} to include ${$self}{id} in ancestors") if $is_t_switch_active;
+ push(@{${$_}{ancestors}},{ancestorID=>${$self}{id},ancestorIndentation=>${$self}{indentation},type=>"natural"});
+ }
+
+ # the argument object only needs a trailing line break if the *last* child
+ # did not add one at the end, and if BodyStartsOnOwnLine >= 1
+ if( (defined ${${${$arguments}{children}}[-1]}{EndFinishesWithLineBreak} and ${${${$arguments}{children}}[-1]}{EndFinishesWithLineBreak}<1)
+ and (defined ${$self}{BodyStartsOnOwnLine} and ${$self}{BodyStartsOnOwnLine}>=1) ){
+ $logger->trace("Updating replacementtext to include a linebreak for arguments in ${$self}{name}") if $is_t_switch_active;
+ ${$arguments}{replacementText} .= "\n" if(${$arguments}{linebreaksAtEnd}{end});
+ }
+
+ # store children in special hash
+ push(@{${$self}{children}},$arguments);
+
+ # remove the environment block, and replace with unique ID
+ ${$self}{body} =~ s/${$arguments}{regexp}/${$arguments}{replacementText}/;
+
+ # delete the regexp, as there's no need for it
+ delete ${${${$self}{children}}[-1]}{regexp};
+
+ $logger->trace(Dumper(\%{$arguments})) if($is_tt_switch_active);
+ $logger->trace("replaced with ID: ${$arguments}{id}") if $is_tt_switch_active;
+ } else {
+ $logger->trace("... no arguments found") if $is_t_switch_active;
+ }
+
+}
+
+
+sub create_unique_id{
+ my $self = shift;
+
+ $ArgumentCounter++;
+ ${$self}{id} = "$tokens{arguments}$ArgumentCounter$tokens{endOfToken}";
+ return;
+}
+
+sub get_arguments_regexp{
+
+ my $self = shift;
+ my %input = @_;
+
+ # blank line token
+ my $blankLineToken = $tokens{blanklines};
+
+ # some calls to this routine need to account for the linebreaks at the end, some do not
+ my $lineBreaksAtEnd = (defined ${input}{mode} and ${input}{mode} eq 'lineBreaksAtEnd')?'\R*':q();
+
+ # arguments Before, by default, includes beamer special and numbered arguments, for example #1 #2, etc
+ my $argumentsBefore = qr/${${$masterSettings{fineTuning}}{arguments}}{before}/;
+ my $argumentsBetween = qr/${${$masterSettings{fineTuning}}{arguments}}{between}/;
+
+ # commands are allowed strings between arguments, e.g node, decoration, etc, specified in stringsAllowedBetweenArguments
+ my $stringsBetweenArguments = q();
+
+ if(defined ${input}{stringBetweenArguments} and ${input}{stringBetweenArguments}==1
+ and ref(${$masterSettings{commandCodeBlocks}}{stringsAllowedBetweenArguments}) eq "ARRAY"){
+ # grab the strings allowed between arguments
+ my @stringsAllowedBetweenArguments = @{${$masterSettings{commandCodeBlocks}}{stringsAllowedBetweenArguments}};
+
+ $logger->trace("*Looping through array for commandCodeBlocks->stringsAllowedBetweenArguments") if $is_t_switch_active ;
+
+ # note that the zero'th element in this array contains the amalgamate switch, which we don't want!
+ foreach (@stringsAllowedBetweenArguments[1 .. $#stringsAllowedBetweenArguments]) {
+ $logger->trace("$_") if $is_t_switch_active ;
+ $stringsBetweenArguments .= ($stringsBetweenArguments eq ""?q():"|").$_;
+ }
+
+ $stringsBetweenArguments = qr/$stringsBetweenArguments/;
+ # report to log file
+ $logger->trace("*Strings allowed between arguments: $stringsBetweenArguments (see stringsAllowedBetweenArguments)") if $is_t_switch_active;
+ }
+
+ if(defined ${input}{roundBrackets} and ${input}{roundBrackets}==1){
+ # arguments regexp
+ return qr/
+ ( # capture into $1
+ (?:
+ (?:\h|\R|$blankLineToken|$trailingCommentRegExp|$argumentsBefore|$argumentsBetween|$stringsBetweenArguments)*
+ (?:
+ (?:
+ \h* # 0 or more spaces
+ (?<!\\) # not immediately pre-ceeded by \
+ \[
+ (?:
+ (?!
+ (?:(?<!\\)\[|(?<!\\)\{)
+ ).
+ )*? # not including [, but \[ ok
+ (?<!\\) # not immediately pre-ceeded by \
+ \] # [optional arguments]
+ )
+ | # OR
+ (?:
+ \h* # 0 or more spaces
+ (?<!\\) # not immediately pre-ceeded by \
+ \{
+ (?:
+ (?!
+ (?:(?<!\\)\{|(?<!\\)\[)
+ ).
+ )*? # not including {, but \{ ok
+ (?<!\\) # not immediately pre-ceeded by \
+ \} # {mandatory arguments}
+ )
+ | # OR
+ (?:
+ \h* # 0 or more spaces
+ (?<!\\) # not immediately pre-ceeded by \
+ \(\$
+ (?:
+ (?!
+ (?:(?<!\\)\$)
+ ).
+ )*? # not including $
+ \$
+ (?<!\\) # not immediately pre-ceeded by \
+ \) # {mandatory arguments}
+ )
+ | # OR
+ (?:
+ \h* # 0 or more spaces
+ (?<!\\) # not immediately pre-ceeded by \
+ \(
+ (?:
+ (?!
+ (?:(?<!\\)\()
+ ).
+ )*? # not including {, but \{ ok
+ (?<!\\) # not immediately pre-ceeded by \
+ \) # {mandatory arguments}
+ )
+ )
+ )
+ + # at least one of the above
+ # NOT followed by
+ (?!
+ (?:
+ (?:\h|\R|$blankLineToken|$trailingCommentRegExp|$argumentsBefore|$stringsBetweenArguments)* # 0 or more h-space, blanklines, trailing comments
+ (?:
+ (?:(?<!\\)\[)
+ |
+ (?:(?<!\\)\{)
+ |
+ (?:(?<!\\)\()
+ )
+ )
+ )
+ \h*
+ ($lineBreaksAtEnd)
+ )
+ /sx;
+ } else {
+ return qr/
+ ( # capture into $1
+ (?:
+ (?:\h|\R|$blankLineToken|$trailingCommentRegExp|$argumentsBefore|$argumentsBetween|$stringsBetweenArguments)*
+ (?:
+ (?:
+ \h* # 0 or more spaces
+ (?<!\\) # not immediately pre-ceeded by \
+ \[
+ (?:
+ (?!
+ (?:(?<!\\)\[|(?<!\\)\{)
+ ).
+ )*? # not including [, but \[ ok
+ (?<!\\) # not immediately pre-ceeded by \
+ \] # [optional arguments]
+ )
+ | # OR
+ (?:
+ \h* # 0 or more spaces
+ (?<!\\) # not immediately pre-ceeded by \
+ \{
+ (?:
+ (?!
+ (?:(?<!\\)\{|(?<!\\)\[)
+ ).
+ )*? # not including {, but \{ ok
+ (?<!\\) # not immediately pre-ceeded by \
+ \} # {mandatory arguments}
+ )
+ )
+ )
+ + # at least one of the above
+ # NOT followed by
+ (?!
+ (?:
+ (?:\h|\R|$blankLineToken|$trailingCommentRegExp|$argumentsBefore)* # 0 or more h-space, blanklines, trailing comments
+ (?:
+ (?:(?<!\\)\[)
+ |
+ (?:(?<!\\)\{)
+ )
+ )
+ )
+ \h*
+ ($lineBreaksAtEnd)
+ )
+ /sx;
+ }
+}
+
+sub comma_else{
+ my $self = shift;
+
+ # check for existence of \\ statement, and associated line break information
+ $self->check_for_else_statement(
+ # else name regexp
+ elseNameRegExp=>qr/${${$masterSettings{fineTuning}}{modifyLineBreaks}}{comma}/,
+ # else statements name
+ ElseStartsOnOwnLine=>"CommaStartsOnOwnLine",
+ # end statements
+ ElseFinishesWithLineBreak=>"CommaFinishesWithLineBreak",
+ # for the YAML settings storage
+ storageNameAppend=>"comma",
+ # logfile information
+ logName=>"comma block, see CommaStartsOnOwnLine and CommaFinishesWithLineBreak",
+ );
+}
+1;
diff --git a/support/latexindent/LatexIndent/BackUpFileProcedure.pm b/support/latexindent/LatexIndent/BackUpFileProcedure.pm
new file mode 100644
index 0000000000..a0374552b4
--- /dev/null
+++ b/support/latexindent/LatexIndent/BackUpFileProcedure.pm
@@ -0,0 +1,136 @@
+package LatexIndent::BackUpFileProcedure;
+# 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 LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/%switches/;
+use LatexIndent::LogFile qw/$logger/;
+use File::Basename; # to get the filename and directory path
+use File::Copy; # to copy the original file to backup (if overwrite option set)
+use Exporter qw/import/;
+our @EXPORT_OK = qw/create_back_up_file/;
+
+# copy main file to a back up in the case of the overwrite switch being active
+
+sub create_back_up_file{
+ my $self = shift;
+
+ return unless($switches{overwrite});
+
+ # if we want to over write the current file create a backup first
+ $logger->info("*Backup procedure (-w flag active):");
+
+ my $fileName = ${$self}{fileName};
+
+ # grab the file extension preferences
+ my %fileExtensionPreference= %{$masterSettings{fileExtensionPreference}};
+
+ # sort the file extensions by preference
+ my @fileExtensions = sort { $fileExtensionPreference{$a} <=> $fileExtensionPreference{$b} } keys(%fileExtensionPreference);
+
+ # backup file name is the base name
+ my $backupFile = basename(${$self}{fileName},@fileExtensions);
+
+ # add the user's backup directory to the backup path
+ $backupFile = "${$self}{cruftDirectory}/$backupFile";
+
+ # local variables, determined from the YAML settings
+ my $onlyOneBackUp = $masterSettings{onlyOneBackUp};
+ my $maxNumberOfBackUps = $masterSettings{maxNumberOfBackUps};
+ my $cycleThroughBackUps= $masterSettings{cycleThroughBackUps};
+ my $backupExtension= $masterSettings{backupExtension};
+
+ # if both ($onlyOneBackUp and $maxNumberOfBackUps) then we have
+ # a conflict- er on the side of caution and turn off onlyOneBackUp
+ if($onlyOneBackUp and $maxNumberOfBackUps>1) {
+ $logger->warn("*onlyOneBackUp=$onlyOneBackUp and maxNumberOfBackUps: $maxNumberOfBackUps");
+ $logger->warn("setting onlyOneBackUp=0 which will allow you to reach $maxNumberOfBackUps back ups");
+ $onlyOneBackUp = 0;
+ }
+
+ # if the user has specified that $maxNumberOfBackUps = 1 then
+ # they only want one backup
+ if($maxNumberOfBackUps==1) {
+ $onlyOneBackUp=1 ;
+ $logger->info("you set maxNumberOfBackUps=1, so I'm setting onlyOneBackUp: 1 ");
+ } elsif($maxNumberOfBackUps<=0 and !$onlyOneBackUp) {
+ $onlyOneBackUp=0 ;
+ $maxNumberOfBackUps=-1;
+ }
+
+ # if onlyOneBackUp is set, then the backup file will
+ # be overwritten each time
+ if($onlyOneBackUp) {
+ $backupFile .= $backupExtension;
+ $logger->info("copying $fileName to $backupFile");
+ $logger->info("$backupFile was overwritten (see onlyOneBackUp)") if (-e $backupFile);
+ } else {
+ # start with a backup file .bak0 (or whatever $backupExtension is present)
+ my $backupCounter = 0;
+ $backupFile .= $backupExtension.$backupCounter;
+
+ # if it exists, then keep going: .bak0, .bak1, ...
+ while (-e $backupFile or $maxNumberOfBackUps>1) {
+ if($backupCounter==$maxNumberOfBackUps) {
+ $logger->info("maxNumberOfBackUps reached ($maxNumberOfBackUps, see maxNumberOfBackUps)");
+
+ # some users may wish to cycle through back up files, e.g:
+ # copy myfile.bak1 to myfile.bak0
+ # copy myfile.bak2 to myfile.bak1
+ # copy myfile.bak3 to myfile.bak2
+ #
+ # current back up is stored in myfile.bak4
+ if($cycleThroughBackUps) {
+ $logger->info("cycleThroughBackUps detected (see cycleThroughBackUps) ");
+ for(my $i=1;$i<=$maxNumberOfBackUps;$i++) {
+ # remove number from backUpFile
+ my $oldBackupFile = $backupFile;
+ $oldBackupFile =~ s/$backupExtension.*/$backupExtension/;
+ my $newBackupFile = $oldBackupFile;
+
+ # add numbers back on
+ $oldBackupFile .= $i;
+ $newBackupFile .= $i-1;
+
+ # check that the oldBackupFile exists
+ if(-e $oldBackupFile){
+ $logger->info(" copying $oldBackupFile to $newBackupFile ");
+ copy($oldBackupFile,$newBackupFile) or die "Could not write to backup file $backupFile. Please check permissions. Exiting.";
+ }
+ }
+ }
+
+ # rest maxNumberOfBackUps
+ $maxNumberOfBackUps=1 ;
+ last; # break out of the loop
+ } elsif(!(-e $backupFile)) {
+ $maxNumberOfBackUps=1;
+ last; # break out of the loop
+ }
+ $logger->info("$backupFile already exists, incrementing by 1... (see maxNumberOfBackUps and onlyOneBackUp)");
+ $backupCounter++;
+ $backupFile =~ s/$backupExtension.*/$backupExtension$backupCounter/;
+ }
+ $logger->info("copying $fileName to $backupFile");
+ }
+
+ # output these lines to the log file
+ $logger->info("Backup file: $backupFile");
+ $logger->info("$fileName will be overwritten after indentation");
+ copy($fileName,$backupFile) or die "Could not write to backup file $backupFile. Please check permissions. Exiting.";
+}
+1;
diff --git a/support/latexindent/LatexIndent/BlankLines.pm b/support/latexindent/LatexIndent/BlankLines.pm
new file mode 100644
index 0000000000..abd1ed73a3
--- /dev/null
+++ b/support/latexindent/LatexIndent/BlankLines.pm
@@ -0,0 +1,126 @@
+package LatexIndent::BlankLines;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use Exporter qw/import/;
+our @EXPORT_OK = qw/protect_blank_lines unprotect_blank_lines condense_blank_lines/;
+
+sub protect_blank_lines{
+ return unless $is_m_switch_active;
+ my $self = shift;
+
+ # the text wrap routine, under some circumstances, can
+ # cause new blank lines that haven't been awarded a token; see, for example,
+ # test-cases/maxLineChars/multi-object-all.tex -l=multi-object2.yaml -m
+ # we can circumvent this by forcing blank lines to be protected if
+ # the text wrap option is active, which allows us to remove blank
+ # lines from wrapped text
+ if(ref ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns} eq "HASH"
+ or ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}>0 ){
+ ${$masterSettings{modifyLineBreaks}}{preserveBlankLines} = 1;
+ }
+
+
+ unless(${$masterSettings{modifyLineBreaks}}{preserveBlankLines}){
+ $logger->trace("*Blank lines will not be protected (preserveBlankLines=0)") if $is_t_switch_active;
+ return
+ }
+
+ $logger->trace("*Protecting blank lines (see preserveBlankLines)") if $is_t_switch_active;
+ ${$self}{body} =~ s/^(\h*)?\R/$tokens{blanklines}\n/mg;
+ return;
+}
+
+sub condense_blank_lines{
+ return unless $is_m_switch_active;
+
+ return unless ${$masterSettings{modifyLineBreaks}}{condenseMultipleBlankLinesInto}>0;
+
+ my $self = shift;
+
+ $logger->trace("*condense blank lines routine") if $is_t_switch_active;
+ # if preserveBlankLines is set to 0, then the blank-line-token will not be present
+ # in the document -- we change that here
+ if(${$masterSettings{modifyLineBreaks}}{preserveBlankLines}==0){
+ # turn the switch on
+ ${$masterSettings{modifyLineBreaks}}{preserveBlankLines}=1;
+
+ # log file information
+ $logger->trace("Updating body to include blank line token, this requires preserveBlankLines = 1") if($is_tt_switch_active);
+ $logger->trace("(any blanklines that could have been removed, would have done so by this point)") if($is_tt_switch_active);
+
+ # make the call
+ $self->protect_blank_lines ;
+ $logger->trace("body now looks like:\n${$self}{body}") if($is_tt_switch_active);
+ }
+
+ # grab the value from the settings
+ my $condenseMultipleBlankLinesInto = ${$masterSettings{modifyLineBreaks}}{condenseMultipleBlankLinesInto};
+
+ # grab the blank-line-token
+ my $blankLineToken = $tokens{blanklines};
+
+ # condense!
+ $logger->trace("Condensing multiple blank lines into $condenseMultipleBlankLinesInto (see condenseMultipleBlankLinesInto)") if $is_t_switch_active;
+ my $replacementToken = $blankLineToken;
+ for (my $i=1; $i<$condenseMultipleBlankLinesInto; $i++ ){
+ $replacementToken .= "\n$blankLineToken";
+ }
+
+ $logger->trace("blank line replacement token: $replacementToken") if($is_tt_switch_active);
+ ${$self}{body} =~ s/($blankLineToken\h*\R*\h*){1,}$blankLineToken/$replacementToken/mgs;
+ $logger->trace("body now looks like:\n${$self}{body}") if($is_tt_switch_active);
+ return;
+}
+
+sub unprotect_blank_lines{
+ return unless $is_m_switch_active;
+
+ return unless ${$masterSettings{modifyLineBreaks}}{preserveBlankLines};
+ my $self = shift;
+
+ # remove any empty lines that might have been added by the text_wrap routine; see, for example,
+ # test-cases/maxLineChars/multi-object-all.tex -l=multi-object2.yaml -m
+ ${$self}{body} =~ s/^\h*\R//mg;
+
+ $logger->trace("Unprotecting blank lines (see preserveBlankLines)") if $is_t_switch_active;
+ my $blankLineToken = join("(?:\\h|\\R)*",split(//,$tokens{blanklines}));
+
+ # loop through the body, looking for the blank line token
+ while(${$self}{body} =~ m/$blankLineToken/s){
+ # when the blank line token occupies the whole line
+ ${$self}{body} =~ s/^\h*$blankLineToken$//mg;
+
+ # when there's stuff *after* the blank line token
+ ${$self}{body} =~ s/(^\h*)$blankLineToken/"\n".$1/meg;
+
+ # when there is stuff before and after the blank line token
+ ${$self}{body} =~ s/^(.*?)$blankLineToken\h*(.*?)\h*$/$1."\n".($2?"\n".$2:$2)/meg;
+
+ # when there is only stuff *after* the blank line token
+ ${$self}{body} =~ s/^$blankLineToken\h*(.*?)$/$1."\n"/emg;
+ }
+ $logger->trace("Finished unprotecting lines (see preserveBlankLines)") if $is_t_switch_active;
+ $logger->trace("body now looks like:") if($is_tt_switch_active);
+ $logger->trace("${$self}{body}") if($is_tt_switch_active);
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Braces.pm b/support/latexindent/LatexIndent/Braces.pm
new file mode 100644
index 0000000000..4861dd1f6a
--- /dev/null
+++ b/support/latexindent/LatexIndent/Braces.pm
@@ -0,0 +1,189 @@
+package LatexIndent::Braces;
+# 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 LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Command qw/$commandRegExp $commandRegExpTrailingComment $optAndMandAndRoundBracketsRegExpLineBreaks/;
+use LatexIndent::KeyEqualsValuesBraces qw/$key_equals_values_bracesRegExp $key_equals_values_bracesRegExpTrailingComment/;
+use LatexIndent::NamedGroupingBracesBrackets qw/$grouping_braces_regexp $grouping_braces_regexpTrailingComment/;
+use LatexIndent::UnNamedGroupingBracesBrackets qw/$un_named_grouping_braces_RegExp $un_named_grouping_braces_RegExp_trailing_comment/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_commands_or_key_equals_values_braces $braceBracketRegExpBasic/;
+our $commandCounter;
+our $braceBracketRegExpBasic = qr/\{|\[/;
+
+sub find_commands_or_key_equals_values_braces{
+
+ my $self = shift;
+
+ $logger->trace("*Searching for commands with optional and/or mandatory arguments AND key = {value}") if $is_t_switch_active ;
+
+ # match either a \\command or key={value}
+ while( ${$self}{body} =~ m/$commandRegExpTrailingComment/
+ or
+ ${$self}{body} =~ m/$key_equals_values_bracesRegExpTrailingComment/
+ or
+ ${$self}{body} =~ m/$grouping_braces_regexpTrailingComment/
+ or
+ ${$self}{body} =~ m/$un_named_grouping_braces_RegExp_trailing_comment/
+ ){
+ if(${$self}{body} =~ m/$commandRegExpTrailingComment/){
+
+ # global substitution
+ ${$self}{body} =~ s/
+ $commandRegExpTrailingComment
+ /
+ # create a new command object
+ my $command = LatexIndent::Command->new(begin=>$1.$2.($3?$3:q()).($4?$4:q()),
+ name=>$2,
+ body=>$5.($8?$8:($10?$10:q())), # $8 is linebreak, $10 is trailing comment
+ end=>q(),
+ linebreaksAtEnd=>{
+ begin=>$4?1:0,
+ end=>$8?1:0, # $8 is linebreak before comment check, $10 is after
+ },
+ modifyLineBreaksYamlName=>"commands",
+ endImmediatelyFollowedByComment=>$8?0:($10?1:0),
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"CommandStartsOnOwnLine",
+ # body statements
+ BodyStartsOnOwnLine=>"CommandNameFinishesWithLineBreak",
+ },
+ optAndMandArgsRegExp=>$optAndMandAndRoundBracketsRegExpLineBreaks,
+ );
+
+ # log file output
+ $logger->trace("*command found: $2") if $is_t_switch_active ;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($command);
+ ${@{${$self}{children}}[-1]}{replacementText}.($8?($10?$10:q()):q());
+ /xseg;
+
+ } elsif (${$self}{body} =~ m/$key_equals_values_bracesRegExpTrailingComment/){
+
+ # global substitution
+ ${$self}{body} =~ s/
+ $key_equals_values_bracesRegExpTrailingComment
+ /
+ # create a new key_equals_values_braces object
+ my $key_equals_values_braces = LatexIndent::KeyEqualsValuesBraces->new(
+ begin=>($2?$2:q()).$3.$4.($5?$5:q()),
+ name=>$3,
+ body=>$6.($9?$9:($10?$10:q()).($11?$11:q())), # $9 is linebreak before comment check, $11 is trailing comment
+ end=>q(),
+ linebreaksAtEnd=>{
+ begin=>$5?1:0,
+ end=>$9?1:0, # $9 is linebreak before comment check
+ },
+ modifyLineBreaksYamlName=>"keyEqualsValuesBracesBrackets",
+ beginningbit=>$1,
+ endImmediatelyFollowedByComment=>$9?0:($11?1:0),
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"KeyStartsOnOwnLine",
+ # body statements
+ BodyStartsOnOwnLine=>"EqualsFinishesWithLineBreak",
+ },
+ additionalAssignments=>["EqualsStartsOnOwnLine"],
+ );
+
+ # log file output
+ $logger->trace("*key_equals_values_braces found: $3") if $is_t_switch_active ;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($key_equals_values_braces);
+ ${@{${$self}{children}}[-1]}{replacementText}.($9?($11?$11:q()):q());
+ /xseg;
+
+ } elsif (${$self}{body} =~ m/$grouping_braces_regexpTrailingComment/){
+
+ # global substitution
+ ${$self}{body} =~ s/
+ $grouping_braces_regexpTrailingComment
+ /
+ # create a new key_equals_values_braces object
+ my $grouping_braces = LatexIndent::NamedGroupingBracesBrackets->new(
+ begin=>$2.($3?$3:q()).($4?$4:q()),
+ name=>$2,
+ body=>$5.($8?$8:($9?$9:q())),
+ end=>q(),
+ linebreaksAtEnd=>{
+ begin=>$4?1:0,
+ end=>$8?1:0,
+ },
+ modifyLineBreaksYamlName=>"namedGroupingBracesBrackets",
+ beginningbit=>$1,
+ endImmediatelyFollowedByComment=>$8?0:($9?1:0),
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"NameStartsOnOwnLine",
+ # body statements
+ BodyStartsOnOwnLine=>"NameFinishesWithLineBreak",
+ },
+ );
+ # log file output
+ $logger->trace("*named grouping braces found: $2") if $is_t_switch_active ;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($grouping_braces);
+ ${@{${$self}{children}}[-1]}{replacementText}.($8?($9?$9:q()):q());
+ /xseg;
+
+ } elsif (${$self}{body} =~ m/$un_named_grouping_braces_RegExp_trailing_comment/) {
+ # global substitution
+ ${$self}{body} =~ s/
+ $un_named_grouping_braces_RegExp_trailing_comment
+ /
+ # create a new Un-named-grouping-braces-brackets object
+ my $un_named_grouping_braces = LatexIndent::UnNamedGroupingBracesBrackets->new(
+ begin=>q(),
+ name=>"always-un-named",
+ body=>$3.($6?$6:($8?$8:q())),
+ end=>q(),
+ linebreaksAtEnd=>{
+ begin=>$2?1:0,
+ end=>$6?1:0,
+ },
+ modifyLineBreaksYamlName=>"UnNamedGroupingBracesBrackets",
+ beginningbit=>$1.($2?$2:q()),
+ endImmediatelyFollowedByComment=>$6?0:($8?1:0),
+ # begin statements
+ BeginStartsOnOwnLine=>0,
+ # body statements
+ BodyStartsOnOwnLine=>0,
+ );
+
+ # log file output
+ $logger->trace("*UNnamed grouping braces found: (no name, by definition!)") if $is_t_switch_active ;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($un_named_grouping_braces);
+ ${@{${$self}{children}}[-1]}{replacementText}.($6?($8?$8:q()):q());
+ /xseg;
+
+ }
+ }
+ return;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Command.pm b/support/latexindent/LatexIndent/Command.pm
new file mode 100644
index 0000000000..a877a6295c
--- /dev/null
+++ b/support/latexindent/LatexIndent/Command.pm
@@ -0,0 +1,215 @@
+package LatexIndent::Command;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::LogFile qw/$logger/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/construct_command_regexp $commandRegExp $commandRegExpTrailingComment $optAndMandAndRoundBracketsRegExpLineBreaks/;
+our $commandCounter;
+our $commandRegExp;
+our $commandRegExpTrailingComment;
+our $optAndMandAndRoundBracketsRegExp;
+our $optAndMandAndRoundBracketsRegExpLineBreaks;
+
+# store the regular expresssion for matching and replacing
+sub construct_command_regexp{
+ my $self = shift;
+
+ $optAndMandAndRoundBracketsRegExp = $self->get_arguments_regexp(
+ roundBrackets=>${$masterSettings{commandCodeBlocks}}{roundParenthesesAllowed},
+ stringBetweenArguments=>1);
+
+ $optAndMandAndRoundBracketsRegExpLineBreaks = $self->get_arguments_regexp(
+ roundBrackets=>${$masterSettings{commandCodeBlocks}}{roundParenthesesAllowed},
+ mode=>"lineBreaksAtEnd",
+ stringBetweenArguments=>1);
+
+ # put together a list of the special command names (this was mostly motivated by the \@ifnextchar[ issue)
+ my $commandNameSpecialRegExp = q();
+ if(ref(${$masterSettings{commandCodeBlocks}}{commandNameSpecial}) eq "ARRAY"){
+
+ my @commandNameSpecial = @{${$masterSettings{commandCodeBlocks}}{commandNameSpecial}};
+ $logger->trace("*Looping through array for commandCodeBlocks->commandNameSpecial") if $is_t_switch_active ;
+
+ # note that the zero'th element in this array contains the amalgamate switch, which we don't want!
+ foreach (@commandNameSpecial[1 .. $#commandNameSpecial]) {
+ $logger->trace("$_") if $is_t_switch_active ;
+ $commandNameSpecialRegExp .= ($commandNameSpecialRegExp eq ""?q():"|").$_;
+ }
+
+ # turn the above into a regexp
+ $commandNameSpecialRegExp = qr/$commandNameSpecialRegExp/;
+ }
+
+ # details to log file
+ $logger->trace("*The special command names regexp is: $commandNameSpecialRegExp (see commandNameSpecial)") if $is_t_switch_active;
+
+ # read from fine tuning
+ my $commandNameRegExp = qr/${${$masterSettings{fineTuning}}{commands}}{name}/;
+
+ # construct the command regexp
+ $commandRegExp = qr/
+ (\\|\\@|@)
+ (
+ $commandNameRegExp|$commandNameSpecialRegExp # lowercase|uppercase letters, @, *, numbers
+ )
+ (\h*)
+ (\R*)?
+ ($optAndMandAndRoundBracketsRegExp)
+ (\R)?
+ /sx;
+
+ # command regexp with trailing comment
+ $commandRegExpTrailingComment = qr/$commandRegExp(\h*)((?:$trailingCommentRegExp\h*)*)/;
+
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # check for adding/removing linebreaks before =
+ $self->check_linebreaks_before_equals;
+
+ # search for arguments
+ $self->find_opt_mand_arguments;
+
+ # situation: ${${$self}{linebreaksAtEnd}}{end} == 1, and the argument container object
+ # still contains a linebreak at the end; in this case, we need to remove the linebreak from
+ # the container object
+ if(${${$self}{linebreaksAtEnd}}{end} == 1
+ and ${${${$self}{children}}[0]}{body} =~ m/\R$/s
+ and !${$self}{endImmediatelyFollowedByComment}){
+ $logger->trace("Removing linebreak from argument container of ${$self}{name}") if $is_t_switch_active;
+ ${${${$self}{children}}[0]}{body} =~ s/\R$//s;
+ ${${${${$self}{children}}[0]}{linebreaksAtEnd}}{body} = 0;
+ }
+
+ # situation: ${${$self}{linebreaksAtEnd}}{end} == 1 and the last argument specifies
+ # EndFinishesWithLineBreaks = 0 (see test-cases/commands/just-one-command-mod10.tex)
+ if(${${$self}{linebreaksAtEnd}}{end} == 1
+ and defined ${${${${$self}{children}}[0]}{children}[-1]}{EndFinishesWithLineBreak}
+ and ${${${${$self}{children}}[0]}{children}[-1]}{EndFinishesWithLineBreak} == -1
+ ){
+ $logger->trace("Switching linebreaksAtEnd{end} to be 0 in command ${$self}{name} as last argument specifies EndFinishesWithLineBreak == 0") if $is_t_switch_active;
+ ${${$self}{linebreaksAtEnd}}{end} = 0;
+ ${$self}{EndFinishesWithLineBreak} = -1;
+ }
+
+ # if the last argument finishes with a linebreak, it won't get interpreted at
+ # the right time (see test-cases/commands/commands-one-line-nested-simple-mod1.tex for example)
+ # so this little bit fixes it
+ if(${${${${${$self}{children}}[0]}{children}[-1]}{linebreaksAtEnd}}{end} and ${${$self}{linebreaksAtEnd}}{end} == 0
+ and defined ${${${${$self}{children}}[0]}{children}[-1]}{EndFinishesWithLineBreak}
+ and ${${${${$self}{children}}[0]}{children}[-1]}{EndFinishesWithLineBreak} >= 1
+ and !${$self}{endImmediatelyFollowedByComment}){
+
+ # update the Command object
+ $logger->trace("Adjusting linebreaksAtEnd in command ${$self}{name}") if $is_t_switch_active;
+ ${${$self}{linebreaksAtEnd}}{end} = ${${${${${$self}{children}}[0]}{children}[-1]}{linebreaksAtEnd}}{end};
+ ${$self}{replacementText} .= "\n";
+
+ # if the last argument has EndFinishesWithLineBreak == 3
+ if (${${${${$self}{children}}[0]}{children}[-1]}{EndFinishesWithLineBreak} == 3 ){
+ my $EndStringLogFile = ${${${${$self}{children}}[0]}{children}[-1]}{aliases}{EndFinishesWithLineBreak}||"EndFinishesWithLineBreak";
+ $logger->trace("Adding another blank line to replacement text for ${$self}{name} as last argument has $EndStringLogFile == 3 ") if $is_t_switch_active;
+ ${$self}{replacementText} .= (${$masterSettings{modifyLineBreaks}}{preserveBlankLines}?$tokens{blanklines}:"\n")."\n";
+ }
+
+ # update the argument object
+ $logger->trace("Adjusting argument object in command, ${$self}{name}") if $is_t_switch_active;
+ ${${${${$self}{children}}[0]}{linebreaksAtEnd}}{body} = 0;
+ ${${${$self}{children}}[0]}{body} =~ s/\R$//s;
+
+ # update the last mandatory/optional argument
+ $logger->trace("Adjusting last argument in command, ${$self}{name}") if $is_t_switch_active;
+ ${${${${${$self}{children}}[0]}{children}[-1]}{linebreaksAtEnd}}{end} = 0;
+ ${${${${$self}{children}}[0]}{children}[-1]}{EndFinishesWithLineBreak} = -1;
+ ${${${${$self}{children}}[0]}{children}[-1]}{replacementText} =~ s/\R$//s;
+
+ # output to log file
+ $logger->trace(Dumper(${${${$self}{children}}[0]}{children}[-1])) if $is_tt_switch_active;
+ }
+
+ # situation: ${${$self}{linebreaksAtEnd}}{end} == 1 and the last argument has added
+ # a line break, which can result in a bogus blank line (see test-cases/commands/just-one-command.tex with mand-args-mod1.yaml)
+ if(${${$self}{linebreaksAtEnd}}{end} == 1
+ and defined ${${${${$self}{children}}[0]}{children}[-1]}{EndFinishesWithLineBreak}
+ and ${${${${$self}{children}}[0]}{children}[-1]}{EndFinishesWithLineBreak} >= 1
+ and ${${${${$self}{children}}[0]}{children}[-1]}{replacementText}=~m/\R$/s
+ and !${$self}{endImmediatelyFollowedByComment}){
+
+ # last argument adjustment
+ $logger->trace("Adjusting last argument in command, ${$self}{name} to avoid double line break") if $is_t_switch_active;
+ ${${${${$self}{children}}[0]}{children}[-1]}{replacementText}=~s/\R$//s;
+ ${${${${${$self}{children}}[0]}{children}[-1]}{linebreaksAtEnd}}{end} = 0;
+
+ # argument object adjustment
+ $logger->trace("Adjusting argument object in command, ${$self}{name} to avoid double line break") if $is_t_switch_active;
+ ${${${${$self}{children}}[0]}{linebreaksAtEnd}}{body} = 0;
+ ${${${$self}{children}}[0]}{body}=~s/\R$//s;
+ }
+
+ # the arguments body might finish with horizontal space, in which case, we need to transfer this
+ # to the parent object replacement text.
+ #
+ # see ../test-cases/texexchange/5461.tex which was the first example to demonstrate the need for this
+ if(!${${${$self}{children}}[0]}{endImmediatelyFollowedByComment} and ${${${$self}{children}}[0]}{body} =~ m/\h*$/ and ${$self}{replacementText} !~ m/\R$/){
+ $logger->trace("${$self}{name}: trailling horizontal space found in arguments -- removing it from arguments, adding to replacement text") if $is_t_switch_active;
+ ${${${$self}{children}}[0]}{body} =~ s/(\h*)$//s;
+ ${$self}{replacementText} .= "$1";
+ }
+
+ # search for ifElseFi blocks
+ $self->find_ifelsefi;
+
+ # search for special begin/end
+ $self->find_special;
+
+}
+
+sub check_linebreaks_before_equals{
+ # empty routine, which allows the above routine to function (this routine kicks in for KeyEqualsValuesBraces)
+ return;
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $commandCounter++;
+ ${$self}{id} = "$tokens{commands}$commandCounter";
+ return;
+}
+
+sub align_at_ampersand{
+ # need an empty routine here for commands; see
+ # test-cases/matrix1.tex for example
+ return;
+}
+
+sub double_back_slash_else{
+ # need an empty routine here for commands; see
+ # test-cases/alignment/command-align.tex for example
+ return;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Document.pm b/support/latexindent/LatexIndent/Document.pm
new file mode 100644
index 0000000000..7f6694d049
--- /dev/null
+++ b/support/latexindent/LatexIndent/Document.pm
@@ -0,0 +1,406 @@
+package LatexIndent::Document;
+# 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 Data::Dumper;
+use utf8;
+use open ':std', ':encoding(UTF-8)';
+
+# gain access to subroutines in the following modules
+use LatexIndent::Switches qw/storeSwitches %switches $is_m_switch_active $is_t_switch_active $is_tt_switch_active $is_r_switch_active $is_rr_switch_active $is_rv_switch_active/;
+use LatexIndent::LogFile qw/processSwitches $logger/;
+use LatexIndent::Replacement qw/make_replacements/;
+use LatexIndent::GetYamlSettings qw/yaml_read_settings yaml_modify_line_breaks_settings yaml_get_indentation_settings_for_this_object yaml_poly_switch_get_every_or_custom_value yaml_get_indentation_information yaml_get_object_attribute_for_indentation_settings yaml_alignment_at_ampersand_settings yaml_get_textwrap_removeparagraphline_breaks %masterSettings yaml_get_columns/;
+use LatexIndent::FileExtension qw/file_extension_check/;
+use LatexIndent::BackUpFileProcedure qw/create_back_up_file/;
+use LatexIndent::BlankLines qw/protect_blank_lines unprotect_blank_lines condense_blank_lines/;
+use LatexIndent::ModifyLineBreaks qw/modify_line_breaks_body modify_line_breaks_end remove_line_breaks_begin adjust_line_breaks_end_parent text_wrap remove_paragraph_line_breaks construct_paragraph_reg_exp text_wrap_remove_paragraph_line_breaks verbatim_modify_line_breaks/;
+use LatexIndent::Sentence qw/one_sentence_per_line/;
+use LatexIndent::TrailingComments qw/remove_trailing_comments put_trailing_comments_back_in add_comment_symbol construct_trailing_comment_regexp/;
+use LatexIndent::HorizontalWhiteSpace qw/remove_trailing_whitespace remove_leading_space/;
+use LatexIndent::Indent qw/indent wrap_up_statement determine_total_indentation indent_begin indent_body indent_end_statement final_indentation_check get_surrounding_indentation indent_children_recursively check_for_blank_lines_at_beginning put_blank_lines_back_in_at_beginning add_surrounding_indentation_to_begin_statement post_indentation_check/;
+use LatexIndent::Tokens qw/token_check %tokens/;
+use LatexIndent::HiddenChildren qw/find_surrounding_indentation_for_children update_family_tree get_family_tree check_for_hidden_children/;
+use LatexIndent::AlignmentAtAmpersand qw/align_at_ampersand find_aligned_block double_back_slash_else/;
+use LatexIndent::DoubleBackSlash qw/dodge_double_backslash un_dodge_double_backslash/;
+
+# code blocks
+use LatexIndent::Verbatim qw/put_verbatim_back_in find_verbatim_environments find_noindent_block find_verbatim_commands find_verbatim_special verbatim_common_tasks/;
+use LatexIndent::Environment qw/find_environments $environmentBasicRegExp construct_environments_regexp/;
+use LatexIndent::IfElseFi qw/find_ifelsefi construct_ifelsefi_regexp $ifElseFiBasicRegExp/;
+use LatexIndent::Else qw/check_for_else_statement/;
+use LatexIndent::Arguments qw/get_arguments_regexp find_opt_mand_arguments construct_arguments_regexp comma_else/;
+use LatexIndent::OptionalArgument qw/find_optional_arguments/;
+use LatexIndent::MandatoryArgument qw/find_mandatory_arguments get_mand_arg_reg_exp/;
+use LatexIndent::RoundBrackets qw/find_round_brackets/;
+use LatexIndent::Item qw/find_items construct_list_of_items/;
+use LatexIndent::Braces qw/find_commands_or_key_equals_values_braces $braceBracketRegExpBasic/;
+use LatexIndent::Command qw/construct_command_regexp/;
+use LatexIndent::KeyEqualsValuesBraces qw/construct_key_equals_values_regexp/;
+use LatexIndent::NamedGroupingBracesBrackets qw/construct_grouping_braces_brackets_regexp/;
+use LatexIndent::UnNamedGroupingBracesBrackets qw/construct_unnamed_grouping_braces_brackets_regexp/;
+use LatexIndent::Special qw/find_special construct_special_begin $specialBeginAndBracesBracketsBasicRegExp $specialBeginBasicRegExp/;
+use LatexIndent::Heading qw/find_heading construct_headings_levels $allHeadingsRegexp/;
+use LatexIndent::FileContents qw/find_file_contents_environments_and_preamble/;
+use LatexIndent::Preamble;
+
+sub new{
+ # Create new objects, with optional key/value pairs
+ # passed as initializers.
+ #
+ # See Programming Perl, pg 319
+ my $invocant = shift;
+ my $class = ref($invocant) || $invocant;
+ my $self = {@_};
+ $logger->trace(${$masterSettings{logFilePreferences}}{showDecorationStartCodeBlockTrace}) if ${$masterSettings{logFilePreferences}}{showDecorationStartCodeBlockTrace};
+ bless ($self,$class);
+ return $self;
+}
+
+sub latexindent{
+ my $self = shift;
+ $self->storeSwitches;
+ $self->processSwitches;
+ $self->file_extension_check;
+ $self->operate_on_file;
+}
+
+sub operate_on_file{
+ my $self = shift;
+
+ $self->create_back_up_file;
+ $self->token_check;
+ $self->make_replacements(when=>"before") if ($is_r_switch_active and !$is_rv_switch_active);
+ unless ($is_rr_switch_active){
+ $self->construct_regular_expressions;
+ $self->find_noindent_block;
+ $self->find_verbatim_commands;
+ $self->find_aligned_block;
+ $self->remove_trailing_comments;
+ $self->find_verbatim_environments;
+ $self->find_verbatim_special;
+ $self->verbatim_modify_line_breaks if $is_m_switch_active;
+ $self->make_replacements(when=>"before") if $is_rv_switch_active;
+ $self->text_wrap if ($is_m_switch_active and !${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}>1);
+ $self->protect_blank_lines;
+ $self->remove_trailing_whitespace(when=>"before");
+ $self->find_file_contents_environments_and_preamble;
+ $self->dodge_double_backslash;
+ $self->remove_leading_space;
+ $self->process_body_of_text;
+ $self->remove_trailing_whitespace(when=>"after");
+ $self->condense_blank_lines;
+ $self->unprotect_blank_lines;
+ $self->un_dodge_double_backslash;
+ $self->make_replacements(when=>"after") if $is_rv_switch_active;
+ $self->put_verbatim_back_in (match=>"everything-except-commands");
+ $self->put_trailing_comments_back_in;
+ $self->put_verbatim_back_in (match=>"just-commands");
+ $self->make_replacements(when=>"after") if ($is_r_switch_active and !$is_rv_switch_active);
+ }
+ $self->output_indented_text;
+ return
+}
+
+sub construct_regular_expressions{
+ my $self = shift;
+ $self->construct_trailing_comment_regexp;
+ $self->construct_environments_regexp;
+ $self->construct_ifelsefi_regexp;
+ $self->construct_list_of_items;
+ $self->construct_special_begin;
+ $self->construct_headings_levels;
+ $self->construct_arguments_regexp;
+ $self->construct_command_regexp;
+ $self->construct_key_equals_values_regexp;
+ $self->construct_grouping_braces_brackets_regexp;
+ $self->construct_unnamed_grouping_braces_brackets_regexp;
+ $self->construct_paragraph_reg_exp if $is_m_switch_active;
+}
+
+sub output_indented_text{
+ my $self = shift;
+
+ $logger->info("*Output routine:");
+
+ # if -overwrite is active then output to original fileName
+ if($switches{overwrite}) {
+ $logger->info("Overwriting file ${$self}{fileName}");
+ open(OUTPUTFILE,">",${$self}{fileName});
+ print OUTPUTFILE ${$self}{body};
+ close(OUTPUTFILE);
+ } elsif($switches{outputToFile}) {
+ $logger->info("Outputting to file $switches{outputToFile}");
+ open(OUTPUTFILE,">",$switches{outputToFile});
+ print OUTPUTFILE ${$self}{body};
+ close(OUTPUTFILE);
+ } else {
+ $logger->info("Not outputting to file; see -w and -o switches for more options.");
+ }
+
+ # put the final line in the logfile
+ $logger->info("${$masterSettings{logFilePreferences}}{endLogFileWith}") if ${$masterSettings{logFilePreferences}}{endLogFileWith};
+
+ # github info line
+ $logger->info("*Please direct all communication/issues to:\nhttps://github.com/cmhughes/latexindent.pl") if ${$masterSettings{logFilePreferences}}{showGitHubInfoFooter};
+
+ # output to screen, unless silent mode
+ print ${$self}{body} unless $switches{silentMode};
+
+ return;
+}
+
+sub process_body_of_text{
+ my $self = shift;
+
+ # find objects recursively
+ $logger->info('*Phase 1: searching for objects');
+ $self->find_objects;
+
+ # find all hidden child
+ $logger->info('*Phase 2: finding surrounding indentation');
+ $self->find_surrounding_indentation_for_children;
+
+ # indentation recursively
+ $logger->info('*Phase 3: indenting objects');
+ $self->indent_children_recursively;
+
+ # final indentation check
+ $logger->info('*Phase 4: final indentation check');
+ $self->final_indentation_check;
+
+ return;
+}
+
+sub find_objects{
+ my $self = shift;
+
+ # one sentence per line: sentences are objects, as of V3.5.1
+ $self->one_sentence_per_line if ($is_m_switch_active and ${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{manipulateSentences});
+
+ # search for environments
+ $logger->trace('looking for ENVIRONMENTS') if $is_t_switch_active;
+ $self->find_environments if ${$self}{body} =~ m/$environmentBasicRegExp/s;
+
+ # search for ifElseFi blocks
+ $logger->trace('looking for IFELSEFI') if $is_t_switch_active;
+ $self->find_ifelsefi if ${$self}{body} =~ m/$ifElseFiBasicRegExp/s;
+
+ # search for headings (part, chapter, section, setc)
+ $logger->trace('looking for HEADINGS (chapter, section, part, etc)') if $is_t_switch_active;
+ $self->find_heading if ${$self}{body} =~ m/$allHeadingsRegexp/s;
+
+ # the ordering of finding commands and special code blocks can change
+ $self->find_commands_or_key_equals_values_braces_and_special if ${$self}{body} =~ m/$specialBeginAndBracesBracketsBasicRegExp/s;
+
+ # documents without preamble need a manual call to the paragraph_one_line routine
+ if ($is_m_switch_active and !${$self}{preamblePresent}){
+ $self->yaml_get_textwrap_removeparagraphline_breaks;
+
+ # call the remove_paragraph_line_breaks and text_wrap routines
+ if(${$masterSettings{modifyLineBreaks}{removeParagraphLineBreaks}}{beforeTextWrap}){
+ $self->remove_paragraph_line_breaks if ${$self}{removeParagraphLineBreaks};
+ $self->text_wrap if (${$self}{textWrapOptions} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis});
+ } else {
+ $self->text_wrap if (${$self}{textWrapOptions} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis});
+ $self->remove_paragraph_line_breaks if ${$self}{removeParagraphLineBreaks};
+ }
+ }
+
+ # if there are no children, return
+ if(${$self}{children}){
+ $logger->trace("*Objects have been found.") if $is_t_switch_active;
+ } else {
+ $logger->trace("No objects found.");
+ return;
+ }
+
+ # logfile information
+ $logger->trace(Dumper(\%{$self})) if($is_tt_switch_active);
+
+ return;
+}
+
+sub find_commands_or_key_equals_values_braces_and_special{
+ my $self = shift;
+
+ # the order in which we search for specialBeginEnd and commands/key/braces
+ # can change depending upon specialBeforeCommand
+ if(${$masterSettings{specialBeginEnd}}{specialBeforeCommand}){
+ # search for special begin/end
+ $logger->trace('looking for SPECIAL begin/end *before* looking for commands (see specialBeforeCommand)') if $is_t_switch_active;
+ $self->find_special if ${$self}{body} =~ m/$specialBeginBasicRegExp/s;
+
+ # search for commands with arguments
+ $logger->trace('looking for COMMANDS and key = {value}') if $is_t_switch_active;
+ $self->find_commands_or_key_equals_values_braces if ${$self}{body} =~ m/$braceBracketRegExpBasic/s;
+ } else {
+ # search for commands with arguments
+ $logger->trace('looking for COMMANDS and key = {value}') if $is_t_switch_active;
+ $self->find_commands_or_key_equals_values_braces if ${$self}{body} =~ m/$braceBracketRegExpBasic/s;
+
+ # search for special begin/end
+ $logger->trace('looking for SPECIAL begin/end') if $is_t_switch_active;
+ $self->find_special if ${$self}{body} =~ m/$specialBeginBasicRegExp/s;
+ }
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+ $logger->trace("There are no tasks particular to ${$self}{name}") if $is_t_switch_active;
+}
+
+sub get_settings_and_store_new_object{
+ my $self = shift;
+
+ # grab the object to be operated upon
+ my ($latexIndentObject) = @_;
+
+ # there are a number of tasks common to each object
+ $latexIndentObject->tasks_common_to_each_object(%{$self});
+
+ # tasks particular to each object
+ $latexIndentObject->tasks_particular_to_each_object;
+
+ # removeParagraphLineBreaks and textWrapping fun!
+ $latexIndentObject->text_wrap_remove_paragraph_line_breaks if($is_m_switch_active);
+
+ # store children in special hash
+ push(@{${$self}{children}},$latexIndentObject);
+
+ # possible decoration in log file
+ $logger->trace(${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace}) if ${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace};
+}
+
+sub tasks_common_to_each_object{
+ my $self = shift;
+
+ # grab the parent information
+ my %parent = @_;
+
+ # update/create the ancestor information
+ if($parent{ancestors}){
+ $logger->trace("Ancestors *have* been found for ${$self}{name}") if($is_t_switch_active);
+ push(@{${$self}{ancestors}},@{$parent{ancestors}});
+ } else {
+ $logger->trace("No ancestors found for ${$self}{name}") if($is_t_switch_active);
+ if(defined $parent{id} and $parent{id} ne ''){
+ $logger->trace("Creating ancestors with $parent{id} as the first one") if($is_t_switch_active);
+ push(@{${$self}{ancestors}},{ancestorID=>$parent{id},ancestorIndentation=>\$parent{indentation},type=>"natural",name=>${$self}{name}});
+ }
+ }
+
+ # natural ancestors
+ ${$self}{naturalAncestors} = q();
+ if(${$self}{ancestors}){
+ ${$self}{naturalAncestors} .= "---".${$_}{ancestorID}."\n" for @{${$self}{ancestors}};
+ }
+
+ # in what follows, $self can be an environment, ifElseFi, etc
+
+ # count linebreaks in body
+ my $bodyLineBreaks = 0;
+ $bodyLineBreaks++ while(${$self}{body} =~ m/\R/sxg);
+ ${$self}{bodyLineBreaks} = $bodyLineBreaks;
+
+ # get settings for this object
+ $self->yaml_get_indentation_settings_for_this_object;
+
+ # give unique id
+ $self->create_unique_id;
+
+ # add trailing text to the id to stop, e.g LATEX-INDENT-ENVIRONMENT1 matching LATEX-INDENT-ENVIRONMENT10
+ ${$self}{id} .= $tokens{endOfToken};
+
+ # text wrapping can make the ID split across lines
+ ${$self}{idRegExp} = ${$self}{id};
+
+ if($is_m_switch_active){
+ my $IDwithLineBreaks = join("\\R?\\h*",split(//,${$self}{id}));
+ ${$self}{idRegExp} = qr/$IDwithLineBreaks/s;
+ }
+
+ # the replacement text can be just the ID, but the ID might have a line break at the end of it
+ $self->get_replacement_text;
+
+ # the above regexp, when used below, will remove the trailing linebreak in ${$self}{linebreaksAtEnd}{end}
+ # so we compensate for it here
+ $self->adjust_replacement_text_line_breaks_at_end;
+
+ # modify line breaks on body and end statements
+ $self->modify_line_breaks_body if ($is_m_switch_active and defined ${$self}{BodyStartsOnOwnLine});
+
+ # modify line breaks end statements
+ $self->modify_line_breaks_end if $is_m_switch_active;
+
+ # check the body for current children
+ $self->check_for_hidden_children if ${$self}{body} =~ m/$tokens{beginOfToken}/;
+
+ # double back slash poly-switch check
+ $self->double_back_slash_else if ($is_m_switch_active and ${$self}{lookForAlignDelims});
+ return;
+}
+
+sub get_replacement_text{
+ my $self = shift;
+
+ # the replacement text can be just the ID, but the ID might have a line break at the end of it
+ ${$self}{replacementText} = ${$self}{id};
+ return;
+}
+
+sub adjust_replacement_text_line_breaks_at_end{
+ my $self = shift;
+
+ # the above regexp, when used below, will remove the trailing linebreak in ${$self}{linebreaksAtEnd}{end}
+ # so we compensate for it here
+ $logger->trace("Putting linebreak after replacementText for ${$self}{name}") if($is_t_switch_active);
+ if(defined ${$self}{horizontalTrailingSpace}){
+ ${$self}{replacementText} .= ${$self}{horizontalTrailingSpace} unless(!${$self}{endImmediatelyFollowedByComment} and defined ${$self}{EndFinishesWithLineBreak} and ${$self}{EndFinishesWithLineBreak}==2);
+ }
+ ${$self}{replacementText} .= "\n" if(${$self}{linebreaksAtEnd}{end});
+
+}
+
+sub count_body_line_breaks{
+ my $self = shift;
+
+ my $oldBodyLineBreaks = (defined ${$self}{bodyLineBreaks})? ${$self}{bodyLineBreaks} : 0;
+
+ # count linebreaks in body
+ my $bodyLineBreaks = 0;
+ $bodyLineBreaks++ while(${$self}{body} =~ m/\R/sxg);
+ ${$self}{bodyLineBreaks} = $bodyLineBreaks;
+ $logger->trace("bodyLineBreaks ${$self}{bodyLineBreaks}") if((${$self}{bodyLineBreaks} != $oldBodyLineBreaks) and $is_t_switch_active);
+}
+
+sub wrap_up_tasks{
+ my $self = shift;
+
+ # most recent child object
+ my $child = @{${$self}{children}}[-1];
+
+ # check if the last object was the last thing in the body, and if it has adjusted linebreaks
+ $self->adjust_line_breaks_end_parent if $is_m_switch_active;
+
+ $logger->trace(Dumper(\%{$child})) if($is_tt_switch_active);
+ $logger->trace("replaced with ID: ${$child}{id}") if $is_t_switch_active;
+
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/DoubleBackSlash.pm b/support/latexindent/LatexIndent/DoubleBackSlash.pm
new file mode 100644
index 0000000000..8b8be3e25e
--- /dev/null
+++ b/support/latexindent/LatexIndent/DoubleBackSlash.pm
@@ -0,0 +1,45 @@
+package LatexIndent::DoubleBackSlash;
+# 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 LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::Tokens qw/%tokens/;
+use Exporter qw/import/;
+our @EXPORT_OK = qw/dodge_double_backslash un_dodge_double_backslash/;
+
+# some code can contain, e.g
+# cycle list={blue,mark=none\\},
+# see test-cases/texexchange/29293-christian-feuersanger.tex
+#
+# This is problematic, as the argument regexp won't count the right } because it has a
+# backslash immediately infront of it!
+sub dodge_double_backslash{
+ my $self = shift;
+
+ ${$self}{body} =~ s/(?:\\\\(\{|\}|\]))/$tokens{doubleBackSlash}$1/sg;
+ return;
+}
+
+# this routine replaces the token with the \\\\
+sub un_dodge_double_backslash{
+ my $self = shift;
+
+ ${$self}{body} =~ s/$tokens{doubleBackSlash}/\\\\/sg;
+ return;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Else.pm b/support/latexindent/LatexIndent/Else.pm
new file mode 100644
index 0000000000..5a367c784f
--- /dev/null
+++ b/support/latexindent/LatexIndent/Else.pm
@@ -0,0 +1,134 @@
+package LatexIndent::Else;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::Braces qw/$braceBracketRegExpBasic/;
+use LatexIndent::Special qw/$specialBeginAndBracesBracketsBasicRegExp/;
+use LatexIndent::Heading qw/$allHeadingsRegexp/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/check_for_else_statement/;
+our $elseCounter;
+
+sub check_for_else_statement{
+ my $self = shift;
+
+ # we call the else routine from different places; see IfElseFi.pm and Special.pm
+ my %input = @_;
+
+ # store the regular expresssion for matching and replacing the \else statements
+ my $elseRegExp = qr/
+ (
+ $input{elseNameRegExp}
+ \h* # possible horizontal space
+ (\R*) # possible line breaks after \else statement
+ )
+ (
+ (?:
+ (?!$input{elseNameRegExp}).
+ )*? # body, which can't include another \else
+ )
+ $
+ /sx;
+
+ $logger->trace("*Looking for $input{elseNameRegExp} statement (${$self}{name})") if $is_t_switch_active;
+
+ while(${$self}{body} =~ m/$elseRegExp(\h*)($trailingCommentRegExp)?/){
+ ${$self}{body} =~ s/$elseRegExp(\h*)($trailingCommentRegExp)?
+ /
+ # create a new Else object
+ my $else = LatexIndent::Else->new(begin=>$1,
+ name=>${$self}{name},
+ storageNameAppend=>$input{storageNameAppend},
+ body=>$3,
+ end=>q(),
+ linebreaksAtEnd=>{
+ begin=>$2?1:0,
+ body=>0,
+ end=>0,
+ },
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>$input{ElseStartsOnOwnLine},
+ # end statements
+ BodyStartsOnOwnLine=>$input{ElseFinishesWithLineBreak},
+ },
+ modifyLineBreaksYamlName=>${$self}{modifyLineBreaksYamlName},
+ endImmediatelyFollowedByComment=>0,
+ horizontalTrailingSpace=>q(),
+ # mandatory and optional arguments have a parent, which we need
+ # to detail for double back slash poly-switches
+ # (see test-cases alignment command-align.tex, for example)
+ parent=>(${$self}{parent}?${$self}{parent}:"none"),
+ );
+
+ # log file output
+ $logger->trace("*$input{logName} found: ${$self}{name}")if $is_t_switch_active;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($else);
+ ${@{${$self}{children}}[-1]}{replacementText};
+ /xse;
+ }
+ return;
+}
+
+sub remove_line_breaks_begin{
+ # the \else command can need a trailing white space if the line breaks have been removed after it and
+ # there is no white space
+ my $self = shift;
+ my $BodyStringLogFile = ${$self}{aliases}{BodyStartsOnOwnLine}||"BodyStartsOnOwnLine";
+ $logger->trace("Removing linebreak at the end of begin (see $BodyStringLogFile)");
+ ${$self}{begin} =~ s/\R*$//sx;
+ ${$self}{begin} .= " " unless(${$self}{begin} =~ m/\h$/s or ${$self}{body} =~ m/^\h/s or ${$self}{body} =~ m/^\R/s );
+ ${$self}{linebreaksAtEnd}{begin} = 0;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # search for headings (important to do this before looking for commands!)
+ $self->find_heading if ${$self}{body} =~ m/$allHeadingsRegexp/s;
+
+ # search for commands and special code blocks
+ $self->find_commands_or_key_equals_values_braces_and_special if ${$self}{body} =~ m/$specialBeginAndBracesBracketsBasicRegExp/s;
+
+ # search for arguments
+ $self->find_opt_mand_arguments if ${$self}{body} =~ m/$braceBracketRegExpBasic/s;
+
+ return;
+}
+
+sub yaml_get_indentation_information{
+ return q();
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $elseCounter++;
+
+ ${$self}{id} = "$tokens{else}$elseCounter";
+ return;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Environment.pm b/support/latexindent/LatexIndent/Environment.pm
new file mode 100644
index 0000000000..401cbecbee
--- /dev/null
+++ b/support/latexindent/LatexIndent/Environment.pm
@@ -0,0 +1,139 @@
+package LatexIndent::Environment;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_m_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::Braces qw/$braceBracketRegExpBasic/;
+use LatexIndent::IfElseFi qw/$ifElseFiBasicRegExp/;
+use LatexIndent::Heading qw/$allHeadingsRegexp/;
+use LatexIndent::Special qw/$specialBeginAndBracesBracketsBasicRegExp/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_environments $environmentBasicRegExp construct_environments_regexp/;
+our $environmentCounter;
+our $environmentBasicRegExp = qr/\\begin\{/;
+our $environmentRegExp;
+
+# store the regular expresssion for matching and replacing the \begin{}...\end{} statements
+sub construct_environments_regexp{
+
+ # read from fine tuning
+ my $environmentNameRegExp = qr/${${$masterSettings{fineTuning}}{environments}}{name}/;
+ $environmentRegExp = qr/
+ (
+ \\begin\{
+ (
+ $environmentNameRegExp # lowercase|uppercase letters, @, *, numbers
+ ) # environment name captured into $2
+ \} # \begin{<something>} statement
+ \h* # horizontal space
+ (\R*)? # possible line breaks (into $3)
+ ) # begin statement captured into $1
+ (
+ (?: # cluster-only (), don't capture
+ (?! # don't include \begin in the body
+ (?:\\begin) # cluster-only (), don't capture
+ ). # any character, but not \\begin
+ )*? # non-greedy
+ (\R*)? # possible line breaks (into $5)
+ ) # environment body captured into $4
+ (
+ \\end\{\2\} # \end{<something>} statement
+ ) # captured into $6
+ (\h*)? # possibly followed by horizontal space
+ (\R)? # possibly followed by a line break
+ /sx;
+}
+
+sub find_environments{
+ my $self = shift;
+
+
+ while( ${$self}{body} =~ m/$environmentRegExp\h*($trailingCommentRegExp)?/){
+
+ # global substitution
+ ${$self}{body} =~ s/
+ $environmentRegExp(\h*)($trailingCommentRegExp)?
+ /
+ # create a new Environment object
+ my $env = LatexIndent::Environment->new(begin=>$1,
+ name=>$2,
+ body=>$4,
+ end=>$6,
+ linebreaksAtEnd=>{
+ begin=>$3?1:0,
+ body=>$5?1:0,
+ end=>$8?1:0,
+ },
+ modifyLineBreaksYamlName=>"environments",
+ endImmediatelyFollowedByComment=>$8?0:($10?1:0),
+ horizontalTrailingSpace=>$7?$7:q(),
+ );
+
+ # log file output
+ $logger->trace("*environment found: $2") if $is_t_switch_active;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($env);
+ ${@{${$self}{children}}[-1]}{replacementText}.($9?$9:q()).($10?$10:q());
+ /xseg;
+ $self->adjust_line_breaks_end_parent if $is_m_switch_active;
+ }
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # if the environment is empty, we may need to update linebreaksAtEnd{body}
+ if(${$self}{body} =~ m/^\h*$/s and ${${$self}{linebreaksAtEnd}}{begin}){
+ $logger->trace("empty environment body (${$self}{name}), updating linebreaksAtEnd{body} to be 1") if($is_t_switch_active);
+ ${${$self}{linebreaksAtEnd}}{body} = 1;
+ }
+
+ # search for items as the first order of business
+ $self->find_items if ${$masterSettings{indentAfterItems}}{${$self}{name}};
+
+ # search for headings (important to do this before looking for commands!)
+ $self->find_heading if ${$self}{body} =~ m/$allHeadingsRegexp/s;
+
+ # search for commands and special code blocks
+ $self->find_commands_or_key_equals_values_braces_and_special if ${$self}{body} =~ m/$specialBeginAndBracesBracketsBasicRegExp/s;
+
+ # search for arguments
+ $self->find_opt_mand_arguments if ${$self}{body} =~ m/$braceBracketRegExpBasic/s;
+
+ # search for ifElseFi blocks
+ $self->find_ifelsefi if ${$self}{body} =~ m/$ifElseFiBasicRegExp/s;
+
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $environmentCounter++;
+ ${$self}{id} = "$tokens{environments}$environmentCounter";
+ return;
+}
+
+
+1;
diff --git a/support/latexindent/LatexIndent/FileContents.pm b/support/latexindent/LatexIndent/FileContents.pm
new file mode 100644
index 0000000000..cbb20e5148
--- /dev/null
+++ b/support/latexindent/LatexIndent/FileContents.pm
@@ -0,0 +1,265 @@
+package LatexIndent::FileContents;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_m_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::Environment qw/$environmentBasicRegExp/;
+use LatexIndent::IfElseFi qw/$ifElseFiBasicRegExp/;
+use LatexIndent::Special qw/$specialBeginAndBracesBracketsBasicRegExp/;
+use LatexIndent::Heading qw/$allHeadingsRegexp/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @EXPORT_OK = qw/find_file_contents_environments_and_preamble/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our $fileContentsCounter;
+
+sub find_file_contents_environments_and_preamble{
+ my $self = shift;
+
+ # store the file contents blocks in an array which, depending on the value
+ # of indentPreamble, will be put into the verbatim hash, or otherwise
+ # stored as children to be operated upon
+ my @fileContentsStorageArray;
+
+ # fileContents environments
+ $logger->trace('*Searching for FILE CONTENTS environments (see fileContentsEnvironments)') if $is_t_switch_active;
+ $logger->trace(Dumper(\%{$masterSettings{fileContentsEnvironments}})) if($is_tt_switch_active);
+ while( my ($fileContentsEnv,$yesno)= each %{$masterSettings{fileContentsEnvironments}}){
+ if($yesno){
+ $logger->trace("looking for $fileContentsEnv environments") if $is_t_switch_active;
+
+ # the trailing * needs some care
+ if($fileContentsEnv =~ m/\*$/){
+ $fileContentsEnv =~ s/\*$//;
+ $fileContentsEnv .= '\*';
+ }
+
+ my $fileContentsRegExp = qr/
+ (
+ \\begin\{
+ $fileContentsEnv
+ \}
+ )
+ (
+ .*?
+ )
+ (
+ \\end\{$fileContentsEnv\}
+ \h*
+ )
+ (\R)?
+ /sx;
+
+ while( ${$self}{body} =~ m/$fileContentsRegExp/sx){
+
+ # create a new Environment object
+ my $fileContentsBlock = LatexIndent::FileContents->new( begin=>$1,
+ body=>$2,
+ end=>$3,
+ name=>$fileContentsEnv,
+ linebreaksAtEnd=>{
+ begin=>0,
+ body=>0,
+ end=>$4?1:0,
+ },
+ modifyLineBreaksYamlName=>"filecontents",
+ );
+ # give unique id
+ $fileContentsBlock->create_unique_id;
+
+ # text wrapping can make the ID split across lines
+ ${$fileContentsBlock}{idRegExp} = ${$fileContentsBlock}{id};
+
+ if($is_m_switch_active){
+ my $IDwithLineBreaks = join("\\R?\\h*",split(//,${$fileContentsBlock}{id}));
+ ${$fileContentsBlock}{idRegExp} = qr/$IDwithLineBreaks/s;
+ }
+
+ # the replacement text can be just the ID, but the ID might have a line break at the end of it
+ $fileContentsBlock->get_replacement_text;
+
+ # count body line breaks
+ $fileContentsBlock->count_body_line_breaks;
+
+ # the above regexp, when used below, will remove the trailing linebreak in ${$self}{linebreaksAtEnd}{end}
+ # so we compensate for it here
+ $fileContentsBlock->adjust_replacement_text_line_breaks_at_end;
+
+ # store the fileContentsBlock, and determine location afterwards
+ push(@fileContentsStorageArray,$fileContentsBlock);
+
+ # log file output
+ $logger->trace("FILECONTENTS environment found: $fileContentsEnv");
+
+ # remove the environment block, and replace with unique ID
+ ${$self}{body} =~ s/$fileContentsRegExp/${$fileContentsBlock}{replacementText}/sx;
+
+ $logger->trace("replaced with ID: ${$fileContentsBlock}{id}") if $is_tt_switch_active;
+ }
+ } else {
+ $logger->trace("*not* looking for $fileContentsEnv as $fileContentsEnv:$yesno");
+ }
+ }
+
+ # determine if body of document contains \begin{document} -- if it does, then assume
+ # that the body has a preamble
+ my $preambleRegExp = qr/
+ (.*?)
+ (\R*\h*)? # linebreaks at end of body into $2
+ \\begin\{document\}
+ /sx;
+ my $preamble = q();
+
+ my $needToStorePreamble = 0;
+
+ # try and find the preamble
+ if( ${$self}{body} =~ m/$preambleRegExp/sx and ${$masterSettings{lookForPreamble}}{${$self}{fileExtension}}){
+
+ $logger->trace("\\begin{document} found in body (after searching for filecontents)-- assuming that a preamble exists") if $is_t_switch_active ;
+
+ # create a preamble object
+ $preamble = LatexIndent::Preamble->new( begin=>q(),
+ body=>$1,
+ end=>q(),
+ name=>"preamble",
+ linebreaksAtEnd=>{
+ begin=>0,
+ body=>$2?1:0,
+ end=>0,
+ },
+ afterbit=>($2?$2:q())."\\begin{document}",
+ modifyLineBreaksYamlName=>"preamble",
+ );
+
+ # give unique id
+ $preamble->create_unique_id;
+
+ # text wrapping can make the ID split across lines
+ ${$preamble}{idRegExp} = ${$preamble}{id};
+
+ if($is_m_switch_active){
+ my $IDwithLineBreaks = join("\\R?\\h*",split(//,${$preamble}{id}));
+ ${$preamble}{idRegExp} = qr/$IDwithLineBreaks/s;
+ }
+
+ # get the replacement_text
+ $preamble->get_replacement_text;
+
+ # log file output
+ $logger->trace("preamble found: preamble") if $is_t_switch_active;
+
+ # remove the environment block, and replace with unique ID
+ ${$self}{body} =~ s/$preambleRegExp/${$preamble}{replacementText}/sx;
+
+ $logger->trace("replaced with ID: ${$preamble}{replacementText}") if $is_tt_switch_active;
+ # indentPreamble set to 1
+ if($masterSettings{indentPreamble}){
+ $logger->trace("storing ${$preamble}{id} for indentation (see indentPreamble)");
+ $needToStorePreamble = 1;
+ } else {
+ # indentPreamble set to 0
+ $logger->trace("NOT storing ${$preamble}{id} for indentation -- will store as VERBATIM object (because indentPreamble:0)") if $is_t_switch_active;
+ $preamble->unprotect_blank_lines;
+ ${$self}{verbatim}{${$preamble}{id}} = $preamble;
+ }
+ } else {
+ ${$self}{preamblePresent} = 0;
+ }
+
+ # loop through the fileContents array, check if it's in the preamble
+ foreach(@fileContentsStorageArray){
+ my $indentThisChild = 0;
+ # verbatim children go in special hash
+ if($preamble ne '' and ${$preamble}{body} =~ m/${$_}{id}/){
+ $logger->trace("filecontents (${$_}{id}) is within preamble");
+ # indentPreamble set to 1
+ if($masterSettings{indentPreamble}){
+ $logger->trace("storing ${$_}{id} for indentation (indentPreamble is 1)");
+ $indentThisChild = 1;
+ } else {
+ # indentPreamble set to 0
+ $logger->trace("Storing ${$_}{id} as a VERBATIM object (indentPreamble is 0)");
+ ${$self}{verbatim}{${$_}{id}}=$_;
+ }
+ } else {
+ $logger->trace("storing ${$_}{id} for indentation (${$_}{name} found outside of preamble)");
+ $indentThisChild = 1;
+ }
+ # store the child, if necessary
+ if($indentThisChild){
+ $_->remove_leading_space;
+ $_->yaml_get_indentation_settings_for_this_object;
+ $_->tasks_particular_to_each_object;
+ push(@{${$self}{children}},$_);
+
+ # possible decoration in log file
+ $logger->trace(${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace}) if ${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace};
+ }
+ }
+
+ if($needToStorePreamble){
+ $preamble->dodge_double_backslash;
+ $preamble->remove_leading_space;
+ $preamble->find_commands_or_key_equals_values_braces if($masterSettings{preambleCommandsBeforeEnvironments});
+ $preamble->tasks_particular_to_each_object;
+ push(@{${$self}{children}},$preamble);
+ }
+ return;
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $fileContentsCounter++;
+ ${$self}{id} = "$tokens{filecontents}$fileContentsCounter$tokens{endOfToken}";
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # search for environments
+ $self->find_environments if ${$self}{body} =~ m/$environmentBasicRegExp/s;
+
+ # search for ifElseFi blocks
+ $self->find_ifelsefi if ${$self}{body} =~ m/$ifElseFiBasicRegExp/s;
+
+ # search for headings (part, chapter, section, setc)
+ $self->find_heading if ${$self}{body} =~ m/$allHeadingsRegexp/s;
+
+ # search for commands and special code blocks
+ $self->find_commands_or_key_equals_values_braces_and_special if ${$self}{body} =~ m/$specialBeginAndBracesBracketsBasicRegExp/s;
+
+ # text wrapping, remove paragraph line breaks
+ if ($is_m_switch_active){
+ $self->yaml_get_textwrap_removeparagraphline_breaks;
+
+ # call the remove_paragraph_line_breaks and text_wrap routines
+ if(${$masterSettings{modifyLineBreaks}{removeParagraphLineBreaks}}{beforeTextWrap}){
+ $self->remove_paragraph_line_breaks if ${$self}{removeParagraphLineBreaks};
+ $self->text_wrap if (${$self}{textWrapOptions} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis});
+ } else {
+ $self->text_wrap if (${$self}{textWrapOptions} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis});
+ $self->remove_paragraph_line_breaks if ${$self}{removeParagraphLineBreaks};
+ }
+ }
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/FileExtension.pm b/support/latexindent/LatexIndent/FileExtension.pm
new file mode 100644
index 0000000000..716598de77
--- /dev/null
+++ b/support/latexindent/LatexIndent/FileExtension.pm
@@ -0,0 +1,154 @@
+package LatexIndent::FileExtension;
+# 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 utf8;
+use PerlIO::encoding;
+use open ':std', ':encoding(UTF-8)';
+use File::Basename; # to get the filename and directory path
+use Exporter qw/import/;
+use Log::Log4perl qw(get_logger :levels);
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/%switches/;
+our @EXPORT_OK = qw/file_extension_check/;
+
+sub file_extension_check{
+ my $self = shift;
+
+ # grab the logger object
+ my $logger = get_logger("Document");
+
+ # grab the filename
+ my $fileName = ${$self}{fileName};
+
+ # see if an extension exists for the fileName
+ my ($name,$dir,$ext) = fileparse($fileName,qr/\..[^.]*$/);
+
+ # grab the file extension preferences
+ my %fileExtensionPreference= %{$masterSettings{fileExtensionPreference}};
+
+ # sort the file extensions by preference
+ my @fileExtensions = sort { $fileExtensionPreference{$a} <=> $fileExtensionPreference{$b} } keys(%fileExtensionPreference);
+
+ # store the base name
+ ${$self}{baseName} = $name;
+
+ # if no extension, search according to fileExtensionPreference
+ if ($fileName ne "-"){
+ if (!$ext) {
+ $logger->info("*File extension work:");
+ $logger->info("latexindent called to act upon $fileName without a file extension;\nsearching for file with an extension in the following order (see fileExtensionPreference):");
+ $logger->info(join("\n",@fileExtensions));
+
+ my $fileFound = 0;
+ # loop through the known file extensions (see @fileExtensions)
+ foreach (@fileExtensions ){
+ if ( -e $fileName.$_ ) {
+ $logger->info("$fileName$_ found!");
+ $fileName .= $_;
+ $logger->info("Updated fileName to $fileName");
+ ${$self}{fileName} = $fileName ;
+ $fileFound = 1;
+ $ext = $_;
+ last;
+ }
+ }
+ unless($fileFound){
+ $logger->fatal("*I couldn't find a match for $fileName in fileExtensionPreference (see defaultSettings.yaml)");
+ foreach (@fileExtensions ){
+ $logger->fatal("I searched for $fileName$_");
+ }
+ $logger->fatal("but couldn't find any of them.\nConsider updating fileExtensionPreference.\nExiting, no indendation done.");
+ die "I couldn't find a match for $fileName in fileExtensionPreference.\nExiting, no indendation done.";
+ }
+ } else {
+ # if the file has a recognised extension, check that the file exists
+ unless( -e $fileName ){
+ my $message = "I couldn't find $fileName, are you sure it exists?.\nNo indentation done.\nExiting.";
+ $logger->fatal("*$message");
+ die $message;
+ }
+ }
+ }
+
+ # store the file extension
+ ${$self}{fileExtension} = $ext;
+
+ # check to see if -o switch is active
+ if($switches{outputToFile}){
+
+ $logger->info("*-o switch active: output file check");
+
+ if ($fileName eq "-" and $switches{outputToFile} =~ m/^\+/){
+ $logger->info("STDIN input mode active, -o switch is removing all + symbols");
+ $switches{outputToFile} =~ s/\+//g;
+ }
+ # the -o file name might begin with a + symbol
+ if($switches{outputToFile} =~ m/^\+(.*)/ and $1 ne "+"){
+ $logger->info("-o switch called with + symbol at the beginning: $switches{outputToFile}");
+ $switches{outputToFile} = ${$self}{baseName}.$1;
+ $logger->info("output file is now: $switches{outputToFile}");
+ }
+
+ my $strippedFileExtension = ${$self}{fileExtension};
+ $strippedFileExtension =~ s/\.//;
+ $strippedFileExtension = "tex" if ($strippedFileExtension eq "");
+
+ # grab the name, directory, and extension of the output file
+ my ($name, $dir, $ext) = fileparse($switches{outputToFile}, $strippedFileExtension);
+
+ # if there is no extension, then add the extension from the file to be operated upon
+ if(!$ext){
+ $logger->info("-o switch called with file name without extension: $switches{outputToFile}");
+ $switches{outputToFile} = $name.($name=~m/\.\z/ ? q() : ".").$strippedFileExtension;
+ $logger->info("Updated to $switches{outputToFile} as the file extension of the input file is $strippedFileExtension");
+ }
+
+ # the -o file name might end with ++ in which case we wish to search for existence,
+ # and then increment accordingly
+ $name =~ s/\.$//;
+ if($name =~ m/\+\+$/){
+ $logger->info("-o switch called with file name ending with ++: $switches{outputToFile}");
+ $name =~ s/\+\+$//;
+ $name = ${$self}{baseName} if ($name eq "");
+ my $outputFileCounter = 0;
+ my $fileName = $name.$outputFileCounter.".".$strippedFileExtension;
+ $logger->info("will search for existence and increment counter, starting with $fileName");
+ while( -e $fileName ){
+ $logger->info("$fileName exists, incrementing counter");
+ $outputFileCounter++;
+ $fileName = $name.$outputFileCounter.".".$strippedFileExtension;
+ }
+ $logger->info("$fileName does not exist, and will be the output file");
+ $switches{outputToFile} = $fileName;
+ }
+ }
+
+ # read the file into the Document body
+ my @lines;
+ if($fileName ne "-"){
+ open(MAINFILE, $fileName) or die "Could not open input file, $fileName";
+ push(@lines,$_) while(<MAINFILE>);
+ close(MAINFILE);
+ } else {
+ push(@lines,$_) while (<>)
+ }
+
+ # the all-important step: update the body
+ ${$self}{body} = join("",@lines);
+}
+1;
diff --git a/support/latexindent/LatexIndent/GetYamlSettings.pm b/support/latexindent/LatexIndent/GetYamlSettings.pm
new file mode 100644
index 0000000000..3029043f23
--- /dev/null
+++ b/support/latexindent/LatexIndent/GetYamlSettings.pm
@@ -0,0 +1,929 @@
+package LatexIndent::GetYamlSettings;
+# 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 LatexIndent::Switches qw/%switches $is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use YAML::Tiny; # interpret defaultSettings.yaml and other potential settings files
+use File::Basename; # to get the filename and directory path
+use File::HomeDir;
+use Log::Log4perl qw(get_logger :levels);
+use Exporter qw/import/;
+our @EXPORT_OK = qw/yaml_read_settings yaml_modify_line_breaks_settings yaml_get_indentation_settings_for_this_object yaml_poly_switch_get_every_or_custom_value yaml_get_indentation_information yaml_get_object_attribute_for_indentation_settings yaml_alignment_at_ampersand_settings yaml_get_textwrap_removeparagraphline_breaks %masterSettings yaml_get_columns/;
+
+# Read in defaultSettings.YAML file
+our $defaultSettings;
+
+# master yaml settings is a hash, global to this module
+our %masterSettings;
+
+# previously found settings is a hash, global to this module
+our %previouslyFoundSettings;
+
+# default values for align at ampersand routine
+our @alignAtAmpersandInformation = ( {name=>"lookForAlignDelims",yamlname=>"delims",default=>1},
+ {name=>"alignDoubleBackSlash",default=>1},
+ {name=>"spacesBeforeDoubleBackSlash",default=>1},
+ {name=>"multiColumnGrouping",default=>0},
+ {name=>"alignRowsWithoutMaxDelims",default=>1},
+ {name=>"spacesBeforeAmpersand",default=>1},
+ {name=>"spacesAfterAmpersand",default=>1},
+ {name=>"justification",default=>"left"},
+ );
+
+sub yaml_read_settings{
+ my $self = shift;
+
+ # read the default settings
+ $defaultSettings = YAML::Tiny->read( "$FindBin::RealBin/defaultSettings.yaml" ) if ( -e "$FindBin::RealBin/defaultSettings.yaml" );
+
+ # grab the logger object
+ my $logger = get_logger("Document");
+ $logger->info("*YAML settings read: defaultSettings.yaml\nReading defaultSettings.yaml from $FindBin::RealBin/defaultSettings.yaml");
+
+ # if latexindent.exe is invoked from TeXLive, then defaultSettings.yaml won't be in
+ # the same directory as it; we need to navigate to it
+ if(!$defaultSettings) {
+ $defaultSettings = YAML::Tiny->read( "$FindBin::RealBin/../../texmf-dist/scripts/latexindent/defaultSettings.yaml");
+ $logger->info("Reading defaultSettings.yaml (2nd attempt, TeXLive, Windows) from $FindBin::RealBin/../../texmf-dist/scripts/latexindent/defaultSettings.yaml");
+ }
+
+ # need to exit if we can't get defaultSettings.yaml
+ die "Could not open defaultSettings.yaml" if(!$defaultSettings);
+
+ # master yaml settings is a hash, global to this module
+ our %masterSettings = %{$defaultSettings->[0]};
+
+ # scalar to read user settings
+ my $userSettings;
+
+ # array to store the paths to user settings
+ my @absPaths;
+
+ # we'll need the home directory a lot in what follows
+ my $homeDir = File::HomeDir->my_home;
+ $logger->info("*YAML settings read: indentconfig.yaml or .indentconfig.yaml") unless $switches{onlyDefault};
+
+ # get information about user settings- first check if indentconfig.yaml exists
+ my $indentconfig = "$homeDir/indentconfig.yaml";
+
+ # if indentconfig.yaml doesn't exist, check for the hidden file, .indentconfig.yaml
+ $indentconfig = "$homeDir/.indentconfig.yaml" if(! -e $indentconfig);
+
+ # messages for indentconfig.yaml and/or .indentconfig.yaml
+ if ( -e $indentconfig and !$switches{onlyDefault}) {
+ # read the absolute paths from indentconfig.yaml
+ $userSettings = YAML::Tiny->read( "$indentconfig" );
+
+ # update the absolute paths
+ if($userSettings and (ref($userSettings->[0]) eq 'HASH') and $userSettings->[0]->{paths}){
+ $logger->info("Reading path information from $indentconfig");
+ # if both indentconfig.yaml and .indentconfig.yaml exist
+ if ( -e File::HomeDir->my_home . "/indentconfig.yaml" and -e File::HomeDir->my_home . "/.indentconfig.yaml") {
+ $logger->info("$homeDir/.indentconfig.yaml has been found, but $indentconfig takes priority");
+ } elsif ( -e File::HomeDir->my_home . "/indentconfig.yaml" ) {
+ $logger->info("(Alternatively $homeDir/.indentconfig.yaml can be used)");
+ } elsif ( -e File::HomeDir->my_home . "/.indentconfig.yaml" ) {
+ $logger->info("(Alternatively $homeDir/indentconfig.yaml can be used)");
+ }
+
+ # output the contents of indentconfig to the log file
+ $logger->info(Dump \%{$userSettings->[0]});
+
+ @absPaths = @{$userSettings->[0]->{paths}};
+ } else {
+ $logger->warn("*The paths field cannot be read from $indentconfig; this means it is either empty or contains invalid YAML");
+ $logger->warn("See https://latexindentpl.readthedocs.io/en/latest/sec-indent-config-and-settings.html for an example");
+ }
+ } else {
+ if($switches{onlyDefault}) {
+ $logger->info("*-d switch active: only default settings requested");
+ $logger->info("not reading USER settings from $indentconfig") if (-e $indentconfig);
+ $logger->info("Ignoring the -l switch: $switches{readLocalSettings} (you used the -d switch)") if($switches{readLocalSettings});
+ $logger->info("Ignoring the -y switch: $switches{yaml} (you used the -d switch)") if($switches{yaml});
+ $switches{readLocalSettings}=0;
+ $switches{yaml}=0;
+ } else {
+ # give the user instructions on where to put indentconfig.yaml or .indentconfig.yaml
+ $logger->info("Home directory is $homeDir (didn't find either indentconfig.yaml or .indentconfig.yaml)\nTo specify user settings you would put indentconfig.yaml here: $homeDir/indentconfig.yaml\nAlternatively, you can use the hidden file .indentconfig.yaml as: $homeDir/.indentconfig.yaml");
+ }
+ }
+
+
+ # local settings can be called with a + symbol, for example
+ # -l=+myfile.yaml
+ # -l "+ myfile.yaml"
+ # -l=myfile.yaml+
+ # which translates to, respectively
+ # -l=localSettings.yaml,myfile.yaml
+ # -l=myfile.yaml,localSettings.yaml
+ # Note: the following is *not allowed*:
+ # -l+myfile.yaml
+ # and
+ # -l + myfile.yaml
+ # will *only* load localSettings.yaml, and myfile.yaml will be ignored
+ my @localSettings;
+
+ $logger->info("*YAML settings read: -l switch") if $switches{readLocalSettings};
+
+ # remove leading, trailing, and intermediate space
+ $switches{readLocalSettings} =~ s/^\h*//g;
+ $switches{readLocalSettings} =~ s/\h*$//g;
+ $switches{readLocalSettings} =~ s/\h*,\h*/,/g;
+ if($switches{readLocalSettings} =~ m/\+/){
+ $logger->info("+ found in call for -l switch: will add localSettings.yaml");
+
+ # + can be either at the beginning or the end, which determines if where the comma should go
+ my $commaAtBeginning = ($switches{readLocalSettings} =~ m/^\h*\+/ ? q() : ",");
+ my $commaAtEnd = ($switches{readLocalSettings} =~ m/^\h*\+/ ? "," : q());
+ $switches{readLocalSettings} =~ s/\h*\+\h*/$commaAtBeginning."localSettings.yaml".$commaAtEnd/e;
+ $logger->info("New value of -l switch: $switches{readLocalSettings}");
+ }
+
+ # local settings can be separated by ,
+ # e.g
+ # -l = myyaml1.yaml,myyaml2.yaml
+ # and in which case, we need to read them all
+ if($switches{readLocalSettings} =~ m/,/){
+ $logger->info("Multiple localSettings found, separated by commas:");
+ @localSettings = split(/,/,$switches{readLocalSettings});
+ $logger->info(join(', ',@localSettings));
+ } else {
+ push(@localSettings,$switches{readLocalSettings}) if($switches{readLocalSettings});
+ }
+
+ # add local settings to the paths, if appropriate
+ foreach (@localSettings) {
+ # check for an extension (.yaml)
+ my ($name, $dir , $ext) = fileparse($_, "yaml");
+
+ # if no extension is found, append the current localSetting with .yaml
+ $_ = $_.($_=~m/\.\z/ ? q() : ".")."yaml" if(!$ext);
+
+ # if the -l switch is called on its own, or else with +
+ # and latexindent.pl is called from a different directory, then
+ # we need to account for this
+ if($_ eq "localSettings.yaml"){
+ $_ = dirname (${$self}{fileName})."/".$_;
+ }
+
+ # check for existence and non-emptiness
+ if ( (-e $_) and !(-z $_)) {
+ $logger->info("Adding $_ to YAML read paths");
+ push(@absPaths,"$_");
+ } elsif ( !(-e $_) ) {
+ $logger->warn("*yaml file not found: $_ not found. Proceeding without it.");
+ }
+ }
+
+ # heading for the log file
+ $logger->info("*YAML settings, reading from the following files:") if @absPaths;
+
+ # read in the settings from each file
+ foreach my $settings (@absPaths) {
+ # check that the settings file exists and that it isn't empty
+ if (-e $settings and !(-z $settings)) {
+ $logger->info("Reading USER settings from $settings");
+ $userSettings = YAML::Tiny->read( "$settings" );
+
+ # if we can read userSettings
+ if($userSettings) {
+ # update the MASTER setttings to include updates from the userSettings
+ while(my($firstLevelKey, $firstLevelValue) = each %{$userSettings->[0]}) {
+ # the update approach is slightly different for hashes vs scalars/arrays
+ if (ref($firstLevelValue) eq "HASH") {
+ while(my ($secondLevelKey,$secondLevelValue) = each %{$userSettings->[0]{$firstLevelKey}}) {
+ if (ref $secondLevelValue eq "HASH"){
+ # if masterSettings already contains a *scalar* value in secondLevelKey
+ # then we need to delete it (test-cases/headings-first.tex with indentRules1.yaml first demonstrated this)
+ if(ref $masterSettings{$firstLevelKey}{$secondLevelKey} ne "HASH"){
+ $logger->trace("*masterSettings{$firstLevelKey}{$secondLevelKey} currently contains a *scalar* value, but it needs to be updated with a hash (see $settings); deleting the scalar") if($is_t_switch_active);
+ delete $masterSettings{$firstLevelKey}{$secondLevelKey} ;
+ }
+ while(my ($thirdLevelKey,$thirdLevelValue) = each %{$secondLevelValue}) {
+ if (ref $thirdLevelValue eq "HASH"){
+ # similarly for third level
+ if (ref $masterSettings{$firstLevelKey}{$secondLevelKey}{$thirdLevelKey} ne "HASH"){
+ $logger->trace("*masterSettings{$firstLevelKey}{$secondLevelKey}{$thirdLevelKey} currently contains a *scalar* value, but it needs to be updated with a hash (see $settings); deleting the scalar") if($is_t_switch_active);
+ delete $masterSettings{$firstLevelKey}{$secondLevelKey}{$thirdLevelKey} ;
+ }
+ while(my ($fourthLevelKey,$fourthLevelValue) = each %{$thirdLevelValue}) {
+ $masterSettings{$firstLevelKey}{$secondLevelKey}{$thirdLevelKey}{$fourthLevelKey} = $fourthLevelValue;
+ }
+ } else {
+ $masterSettings{$firstLevelKey}{$secondLevelKey}{$thirdLevelKey} = $thirdLevelValue;
+ }
+ }
+ } else {
+ # settings such as commandCodeBlocks can have arrays, which may wish
+ # to be amalgamated, rather than overwritten
+ if(ref($secondLevelValue) eq "ARRAY"
+ and
+ ${${$masterSettings{$firstLevelKey}{$secondLevelKey}}[0]}{amalgamate}
+ and
+ !(ref(${$secondLevelValue}[0]) eq "HASH" and defined ${$secondLevelValue}[0]{amalgamate} and !${$secondLevelValue}[0]{amalgamate})
+ ){
+ $logger->trace("*$firstLevelKey -> $secondLevelKey, amalgamate: 1") if($is_t_switch_active);
+ foreach (@{$secondLevelValue}){
+ $logger->trace("$_") if($is_t_switch_active);
+ push (@{$masterSettings{$firstLevelKey}{$secondLevelKey}},$_) unless(ref($_) eq "HASH");
+ }
+
+ # remove duplicated entries, https://stackoverflow.com/questions/7651/how-do-i-remove-duplicate-items-from-an-array-in-perl
+ my %seen = ();
+ my @unique = grep { ! $seen{ $_ }++ } @{$masterSettings{$firstLevelKey}{$secondLevelKey}};
+ @{$masterSettings{$firstLevelKey}{$secondLevelKey}} = @unique;
+
+ $logger->trace("*master settings for $firstLevelKey -> $secondLevelKey now look like:") if $is_t_switch_active;
+ foreach (@{$masterSettings{$firstLevelKey}{$secondLevelKey}}){
+ $logger->trace("$_") if($is_t_switch_active);
+ }
+ } else {
+ $masterSettings{$firstLevelKey}{$secondLevelKey} = $secondLevelValue;
+ }
+ }
+ }
+ } elsif (ref($firstLevelValue) eq "ARRAY") {
+ # update amalgamate in master settings
+ if(ref(${$firstLevelValue}[0]) eq "HASH" and defined ${$firstLevelValue}[0]{amalgamate}){
+ ${$masterSettings{$firstLevelKey}[0]}{amalgamate} = ${$firstLevelValue}[0]{amalgamate};
+ shift @{$firstLevelValue} if ${$masterSettings{$firstLevelKey}[0]}{amalgamate};
+ }
+
+ # if amalgamate is set to 1, then append
+ if(${$masterSettings{$firstLevelKey}[0]}{amalgamate}){
+ # loop through the other settings
+ foreach (@{$firstLevelValue}){
+ push (@{$masterSettings{$firstLevelKey}},$_);
+ }
+ } else {
+ # otherwise overwrite
+ $masterSettings{$firstLevelKey} = $firstLevelValue;
+ }
+ } else {
+ $masterSettings{$firstLevelKey} = $firstLevelValue;
+ }
+ }
+
+ # output settings to $logfile
+ if($masterSettings{logFilePreferences}{showEveryYamlRead}){
+ $logger->info(Dump \%{$userSettings->[0]});
+ } else {
+ $logger->info("Not showing settings in the log file (see showEveryYamlRead and showAmalgamatedSettings).");
+ }
+ } else {
+ # otherwise print a warning that we can not read userSettings.yaml
+ $logger->warn("*$settings contains invalid yaml format- not reading from it");
+ }
+ } else {
+ # otherwise keep going, but put a warning in the log file
+ $logger->warn("*$homeDir/indentconfig.yaml");
+ if (-z $settings) {
+ $logger->info("specifies $settings but this file is EMPTY -- not reading from it");
+ } else {
+ $logger->info("specifies $settings but this file does not exist - unable to read settings from this file");
+ }
+ }
+ }
+
+ # read settings from -y|--yaml switch
+ if($switches{yaml}){
+ # report to log file
+ $logger->info("*YAML settings read: -y switch");
+
+ # remove any horizontal space before or after , OR : OR ; or at the beginning or end of the switch value
+ $switches{yaml} =~ s/\h*(,|(?<!\\):|;)\h*/$1/g;
+ $switches{yaml} =~ s/^\h*//g;
+
+ # store settings, possibly multiple ones split by commas
+ my @yamlSettings;
+ if($switches{yaml} =~ m/(?<!\\),/){
+ @yamlSettings = split(/(?<!\\),/,$switches{yaml});
+ } else {
+ push(@yamlSettings,$switches{yaml});
+ }
+
+ # it is possible to specify, for example,
+ #
+ # -y=indentAfterHeadings:paragraph:indentAfterThisHeading:1;level:1
+ # -y=specialBeginEnd:displayMath:begin:'\\\[';end: '\\\]';lookForThis: 1
+ #
+ # which should be translated into
+ #
+ # indentAfterHeadings:
+ # paragraph:
+ # indentAfterThisHeading:1
+ # level:1
+ #
+ # so we need to loop through the comma separated list and search
+ # for semi-colons
+ my $settingsCounter=0;
+ my @originalYamlSettings = @yamlSettings;
+ foreach(@originalYamlSettings){
+ # increment the counter
+ $settingsCounter++;
+
+ # check for a match of the ;
+ if($_ =~ m/(?<!\\);/){
+ my (@subfield) = split(/(?<!\\);/,$_);
+
+ # the content up to the first ; is called the 'root'
+ my $root = shift @subfield;
+
+ # split the root at :
+ my (@keysValues) = split(/:/,$root);
+
+ # get rid of the last *two* elements, which will be
+ # key: value
+ # for example, in
+ # -y=indentAfterHeadings:paragraph:indentAfterThisHeading:1;level:1
+ # then @keysValues holds
+ # indentAfterHeadings:paragraph:indentAfterThisHeading:1
+ # so we need to get rid of both
+ # 1
+ # indentAfterThisHeading
+ # so that we are in a position to concatenate
+ # indentAfterHeadings:paragraph
+ # with
+ # level:1
+ # to form
+ # indentAfterHeadings:paragraph:level:1
+ pop(@keysValues);
+ pop(@keysValues);
+
+ # update the appropriate piece of the -y switch, for example:
+ # -y=indentAfterHeadings:paragraph:indentAfterThisHeading:1;level:1
+ # needs to be changed to
+ # -y=indentAfterHeadings:paragraph:indentAfterThisHeading:1
+ # the
+ # indentAfterHeadings:paragraph:level:1
+ # will be added in the next part
+ $yamlSettings[$settingsCounter-1] = $root;
+
+ # reform the root
+ $root = join(":",@keysValues);
+ $logger->trace("*Sub-field detected (; present) and the root is: $root") if $is_t_switch_active;
+
+ # now we need to attach the $root back together with any subfields
+ foreach(@subfield){
+ # splice the new field into @yamlSettings (reference: https://perlmaven.com/splice-to-slice-and-dice-arrays-in-perl)
+ splice @yamlSettings,$settingsCounter,0,$root.":".$_;
+
+ # increment the counter
+ $settingsCounter++;
+ }
+ $logger->info("-y switch value interpreted as: ".join(',',@yamlSettings));
+ }
+ }
+
+ # loop through each of the settings specified in the -y switch
+ foreach(@yamlSettings){
+ # split each value at semi-colon
+ my (@keysValues) = split(/(?<!(?:\\|\[)):(?!\])/,$_);
+
+ # $value will always be the last element
+ my $value = $keysValues[-1];
+
+ # it's possible that the 'value' will contain an escaped
+ # semi-colon, so we replace it with just a semi-colon
+ $value =~ s/\\:/:/;
+
+ # horizontal space needs special treatment
+ if($value =~ m/^(?:"|')(\h*)(?:"|')$/){
+ # pure horizontal space
+ $value = $1;
+ } elsif($value =~ m/^(?:"|')((?:\\t)*)(?:"|')$/){
+ # tabs
+ $value =~ s/^(?:"|')//;
+ $value =~ s/(?:"|')$//;
+ $value =~ s/\\t/\t/g;
+ }
+
+ if(scalar(@keysValues) == 2){
+ # for example, -y="defaultIndent: ' '"
+ my $key = $keysValues[0];
+ $logger->info("Updating masterSettings with $key: $value");
+ $masterSettings{$key} = $value;
+ } elsif(scalar(@keysValues) == 3){
+ # for example, -y="indentRules: one: '\t\t\t\t'"
+ my $parent = $keysValues[0];
+ my $child = $keysValues[1];
+ $logger->info("Updating masterSettings with $parent: $child: $value");
+ $masterSettings{$parent}{$child} = $value;
+ } elsif(scalar(@keysValues) == 4){
+ # for example, -y='modifyLineBreaks : environments: EndStartsOnOwnLine:3' -m
+ my $parent = $keysValues[0];
+ my $child = $keysValues[1];
+ my $grandchild = $keysValues[2];
+ $logger->info("Updating masterSettings with $parent: $child: $grandchild: $value");
+ $masterSettings{$parent}{$child}{$grandchild} = $value;
+ } elsif(scalar(@keysValues) == 5){
+ # for example, -y='modifyLineBreaks : environments: one: EndStartsOnOwnLine:3' -m
+ my $parent = $keysValues[0];
+ my $child = $keysValues[1];
+ my $grandchild = $keysValues[2];
+ my $greatgrandchild = $keysValues[3];
+ $logger->info("Updating masterSettings with $parent: $child: $grandchild: $greatgrandchild: $value");
+ $masterSettings{$parent}{$child}{$grandchild}{$greatgrandchild} = $value;
+ }
+ }
+ }
+
+ # some users may wish to see showAmalgamatedSettings
+ # which details the overall state of the settings modified
+ # from the default in various user files
+ if($masterSettings{logFilePreferences}{showAmalgamatedSettings}){
+ $logger->info("Amalgamated/overall settings to be used:");
+ $logger->info(Dump \%masterSettings);
+ }
+
+ return;
+}
+
+sub yaml_get_indentation_settings_for_this_object{
+ my $self = shift;
+
+ # create a name for previously found settings
+ my $storageName = ${$self}{name}.${$self}{modifyLineBreaksYamlName}.(defined ${$self}{storageNameAppend}?${$self}{storageNameAppend}:q());
+
+ # grab the logging object
+ my $logger = get_logger("Document");
+
+ # check for storage of repeated objects
+ if ($previouslyFoundSettings{$storageName}){
+ $logger->trace("*Using stored settings for $storageName") if($is_t_switch_active);
+ } else {
+ my $name = ${$self}{name};
+ $logger->trace("Storing settings for $storageName") if($is_t_switch_active);
+
+ # check for noAdditionalIndent and indentRules
+ # otherwise use defaultIndent
+ my $indentation = $self->yaml_get_indentation_information;
+
+ # check for alignment at ampersand settings
+ $self->yaml_alignment_at_ampersand_settings;
+
+ # check for line break settings
+ $self->yaml_modify_line_breaks_settings if $is_m_switch_active;
+
+ # store the settings
+ %{${previouslyFoundSettings}{$storageName}} = (
+ indentation=>$indentation,
+ BeginStartsOnOwnLine=>${$self}{BeginStartsOnOwnLine},
+ BodyStartsOnOwnLine=>${$self}{BodyStartsOnOwnLine},
+ EndStartsOnOwnLine=>${$self}{EndStartsOnOwnLine},
+ EndFinishesWithLineBreak=>${$self}{EndFinishesWithLineBreak},
+ removeParagraphLineBreaks=>${$self}{removeParagraphLineBreaks},
+ textWrapOptions=>${$self}{textWrapOptions},
+ columns=>${$self}{columns},
+ );
+
+ # don't forget alignment settings!
+ foreach (@alignAtAmpersandInformation){
+ ${${previouslyFoundSettings}{$storageName}}{${$_}{name}} = ${$self}{${$_}{name}} if(defined ${$self}{${$_}{name}});
+ }
+
+ # some objects, e.g ifElseFi, can have extra assignments, e.g ElseStartsOnOwnLine
+ # these need to be stored as well!
+ foreach (@{${$self}{additionalAssignments}}){
+ ${${previouslyFoundSettings}{$storageName}}{$_} = ${$self}{$_};
+ }
+
+ # log file information
+ $logger->trace("Settings for $name (stored for future use):") if $is_tt_switch_active;
+ $logger->trace(Dump \%{${previouslyFoundSettings}{$storageName}}) if $is_tt_switch_active;
+
+ }
+
+ # append indentation settings to the current object
+ while( my ($key,$value)= each %{${previouslyFoundSettings}{$storageName}}){
+ ${$self}{$key} = $value;
+ }
+
+ return;
+}
+
+sub yaml_alignment_at_ampersand_settings{
+ my $self = shift;
+
+ # if the YamlName is, for example, optionalArguments, mandatoryArguments, heading, then we'll be looking for information about the *parent*
+ my $name = (defined ${$self}{nameForIndentationSettings}) ? ${$self}{nameForIndentationSettings} : ${$self}{name};
+
+ # check, for example,
+ # lookForAlignDelims:
+ # tabular: 1
+ # or
+ #
+ # lookForAlignDelims:
+ # tabular:
+ # delims: 1
+ # alignDoubleBackSlash: 1
+ # spacesBeforeDoubleBackSlash: 2
+ return unless ${$masterSettings{lookForAlignDelims}}{$name};
+
+ if(ref ${$masterSettings{lookForAlignDelims}}{$name} eq "HASH"){
+ # specified as a hash, e.g
+ #
+ # lookForAlignDelims:
+ # tabular:
+ # delims: 1
+ # alignDoubleBackSlash: 1
+ # spacesBeforeDoubleBackSlash: 2
+ foreach (@alignAtAmpersandInformation){
+ my $yamlname = (defined ${$_}{yamlname} ? ${$_}{yamlname}: ${$_}{name});
+ ${$self}{${$_}{name}} = (defined ${${$masterSettings{lookForAlignDelims}}{$name}}{$yamlname} ) ? ${${$masterSettings{lookForAlignDelims}}{$name}}{$yamlname} : ${$_}{default};
+ }
+ } else {
+ # specified as a scalar, e.g
+ #
+ # lookForAlignDelims:
+ # tabular: 1
+ foreach (@alignAtAmpersandInformation){
+ ${$self}{${$_}{name}} = ${$_}{default};
+ }
+ }
+ return;
+}
+
+sub yaml_modify_line_breaks_settings{
+ my $self = shift;
+
+ # grab the logging object
+ my $logger = get_logger("Document");
+
+ # details to the log file
+ $logger->trace("*-m modifylinebreaks switch active") if $is_t_switch_active;
+ $logger->trace("looking for polyswitch, textWrapOptions, removeParagraphLineBreaks, oneSentencePerLine settings for ${$self}{name} ") if $is_t_switch_active;
+
+ # some objects, e.g ifElseFi, can have extra assignments, e.g ElseStartsOnOwnLine
+ my @toBeAssignedTo = ${$self}{additionalAssignments} ? @{${$self}{additionalAssignments}} : ();
+
+ # the following will *definitley* be in the array, so let's add them
+ push(@toBeAssignedTo,("BeginStartsOnOwnLine","BodyStartsOnOwnLine","EndStartsOnOwnLine","EndFinishesWithLineBreak"));
+
+ # we can efficiently loop through the following
+ foreach (@toBeAssignedTo){
+ $self->yaml_poly_switch_get_every_or_custom_value(
+ toBeAssignedTo=>$_,
+ toBeAssignedToAlias=> ${$self}{aliases}{$_} ? ${$self}{aliases}{$_} : $_,
+ );
+ };
+
+ $self->yaml_get_textwrap_removeparagraphline_breaks;
+ return;
+}
+
+sub yaml_get_textwrap_removeparagraphline_breaks{
+ my $self = shift;
+
+ # grab the logging object
+ my $logger = get_logger("Document");
+
+ # textWrap and removeParagraphLineBreaks settings
+ foreach ("textWrapOptions","removeParagraphLineBreaks"){
+
+ # first check for either
+ #
+ # textWrapOptions:
+ # all: 0
+ #
+ # or
+ #
+ # removeParagraphLineBreaks:
+ # all: 0
+ #
+ # *IMPORTANT*
+ # even if all is set to 1, then it can still be disabled on either a
+ #
+ # per-object:
+ #
+ # for example
+ #
+ # textWrapOptions:
+ # all:
+ # except:
+ # - environments
+ #
+ # will disable textWrapOptions for *all* environments
+ #
+ # per-name
+ #
+ # for example
+ #
+ # textWrapOptions:
+ # all:
+ # except:
+ # - itemize
+ #
+ # will disable textWrapOptions for itemize
+
+ # if 'all' is set as a hash, then the default value is 1, to be turned off (possibly) later
+ ${$self}{$_} = ( ref ${$masterSettings{modifyLineBreaks}{$_}}{all} eq "HASH" ? 1 : ${$masterSettings{modifyLineBreaks}{$_}}{all});
+
+ # get the columns
+ if($_ eq "textWrapOptions" and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis}){
+ $self->yaml_get_columns;
+ }
+
+ # name of the object in the modifyLineBreaks yaml (e.g environments, ifElseFi, etc)
+ my $YamlName = ${$self}{modifyLineBreaksYamlName};
+
+ # if the YamlName is either optionalArguments or mandatoryArguments, then we'll be looking for information about the *parent*
+ my $name = ($YamlName =~ m/Arguments/) ? ${$self}{parent} : ${$self}{name};
+
+ # move to the next <thing> if
+ #
+ # textWrapOptions/removeParagraphLineBreaks::
+ # all: 1
+ #
+ if(${$self}{$_}
+ and
+ ref ${$masterSettings{modifyLineBreaks}{$_}}{all} ne "HASH"
+ and
+ ${$masterSettings{modifyLineBreaks}{$_}}{all}){
+ $logger->trace("$_ for $name is ${$self}{$_}") if $is_t_switch_active;
+ next;
+ };
+
+ # otherwise, look for exceptions, either through
+ #
+ # textWrapOptions/removeParagraphLineBreaks:
+ # all:
+ # except:
+ # - <*type* of thing or *name* of thing>
+ #
+ # so, for example, the following (per code-block) is acceptable
+ # which makes an exception for all *environments*
+ #
+ # all:
+ # except:
+ # - 'environments'
+ #
+ # the following (per-name) is acceptable
+ # which only makes an exception for things called itemize
+ #
+ # all:
+ # except:
+ # - 'itemize'
+ #
+ if(${$self}{$_}
+ and
+ defined ${${$masterSettings{modifyLineBreaks}{$_}}{all}}{except}
+ and
+ ref ${${$masterSettings{modifyLineBreaks}{$_}}{all}}{except} eq "ARRAY"
+ ){
+ my %except = map { $_ => 1 } @{${${$masterSettings{modifyLineBreaks}}{$_}}{all}{except}};
+ if( $except{$name} or $except{$YamlName}){
+ ${$self}{$_} = 0;
+ my $detail = ($except{$name} ? "per-name" : "per-code-block-type");
+ $logger->trace("$_ for $name is ${$self}{$_} (found as exception $detail, see $_:all:except)") if $is_t_switch_active;
+ next;
+ }
+ } else {
+ # or otherwise through, for example
+ #
+ # all: 0
+ # ifElseFi: 1
+ #
+ # the textWrapOptions/removeParagraphLineBreaks can contain fields that are hashes or scalar
+ #
+ if(ref ${$masterSettings{modifyLineBreaks}{$_}}{$YamlName} eq "HASH"){
+ # textWrapOptions/removeParagraphLineBreaks:
+ # all: 0
+ # environments:
+ # quotation: 0
+ $logger->trace("*$YamlName specified with fields in $_, looking for $name") if $is_t_switch_active;
+ ${$self}{$_} = ${${$masterSettings{modifyLineBreaks}{$_}}{$YamlName}}{$name} if (defined ${${$masterSettings{modifyLineBreaks}{$_}}{$YamlName}}{$name});
+ } elsif(defined ${$masterSettings{modifyLineBreaks}{$_}}{$YamlName}){
+ # textWrapOptions/removeParagraphLineBreaks:
+ # all: 0
+ # environments: 0
+ $logger->trace("*$YamlName specified with just a number in $_ ${$masterSettings{modifyLineBreaks}{$_}}{$YamlName}") if $is_t_switch_active;
+ ${$self}{$_} = ${$masterSettings{modifyLineBreaks}{$_}}{$YamlName} if (defined ${$masterSettings{modifyLineBreaks}{$_}}{$YamlName});
+ }
+ }
+
+ # summary to log file
+ $logger->trace("$_ for $name is ${$self}{$_}") if $is_t_switch_active;
+ }
+
+ return;
+}
+
+sub yaml_get_columns{
+ my $self = shift;
+
+ my $YamlName = ${$self}{modifyLineBreaksYamlName};
+
+ # the columns settings can have a variety of different ways of being specified
+ if(ref ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns} eq "HASH"){
+ # assign default value of $columns
+ my $columns;
+ if(defined ${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{default}){
+ $columns = ${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{default};
+ } else {
+ $columns = 80;
+ }
+
+ # possibly specify object wrapping on a per-name basis
+ if(ref ${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{$YamlName} eq "HASH"){
+ # for example:
+ # modifyLineBreaks:
+ # textWrapOptions:
+ # columns:
+ # default: 80
+ # environments:
+ # default: 80
+ # something: 10
+ # another: 20
+ if(defined ${${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{$YamlName}}{${$self}{name}}){
+ $columns = ${${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{$YamlName}}{${$self}{name}};
+ } elsif (${${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{$YamlName}}{default}){
+ $columns = ${${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{$YamlName}}{default};
+ }
+ } else {
+ # for example:
+ # modifyLineBreaks:
+ # textWrapOptions:
+ # columns:
+ # default: 80
+ # environments: 10
+ $columns = ${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{$YamlName};
+ }
+ ${$self}{columns} = $columns;
+ } else {
+ ${$self}{columns} = ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns};
+ }
+ return;
+}
+
+sub yaml_poly_switch_get_every_or_custom_value{
+ my $self = shift;
+ my %input = @_;
+
+ my $toBeAssignedTo = $input{toBeAssignedTo};
+ my $toBeAssignedToAlias = $input{toBeAssignedToAlias};
+
+ # grab the logging object
+ my $logger = get_logger("Document");
+
+ # alias
+ if(${$self}{aliases}{$toBeAssignedTo}){
+ $logger->trace("aliased $toBeAssignedTo using ${$self}{aliases}{$toBeAssignedTo}") if($is_t_switch_active);
+ }
+
+ # name of the object in the modifyLineBreaks yaml (e.g environments, ifElseFi, etc)
+ my $YamlName = ${$self}{modifyLineBreaksYamlName};
+
+ # if the YamlName is either optionalArguments or mandatoryArguments, then we'll be looking for information about the *parent*
+ my $name = ($YamlName =~ m/Arguments/) ? ${$self}{parent} : ${$self}{name};
+
+ # these variables just ease the notation what follows
+ my $everyValue = ${${$masterSettings{modifyLineBreaks}}{$YamlName}}{$toBeAssignedToAlias};
+ my $customValue = ${${${$masterSettings{modifyLineBreaks}}{$YamlName}}{$name}}{$toBeAssignedToAlias};
+
+ # check for the *custom* value
+ if (defined $customValue){
+ $logger->trace("$name: $toBeAssignedToAlias=$customValue, (*per-name* value) adjusting $toBeAssignedTo") if($is_t_switch_active);
+ ${$self}{$toBeAssignedTo} = $customValue !=0 ? $customValue : undef;
+ } else {
+ # check for the *every* value
+ if (defined $everyValue and $everyValue != 0){
+ $logger->trace("$name: $toBeAssignedToAlias=$everyValue, (*global* value) adjusting $toBeAssignedTo") if($is_t_switch_active);
+ ${$self}{$toBeAssignedTo} = $everyValue;
+ }
+ }
+ return;
+}
+
+sub yaml_get_indentation_information{
+ my $self = shift;
+
+ #**************************************
+ # SEARCHING ORDER:
+ # noAdditionalIndent *per-name* basis
+ # indentRules *per-name* basis
+ # noAdditionalIndentGlobal
+ # indentRulesGlobal
+ #**************************************
+
+ # noAdditionalIndent can be a scalar or a hash, e.g
+ #
+ # noAdditionalIndent:
+ # myexample: 1
+ #
+ # OR
+ #
+ # noAdditionalIndent:
+ # myexample:
+ # body: 1
+ # optionalArguments: 1
+ # mandatoryArguments: 1
+ #
+ # specifying as a scalar with no field (e.g myexample: 1)
+ # will be interpreted as noAdditionalIndent for *every*
+ # field, so the body, optional arguments and mandatory arguments
+ # will *all* receive noAdditionalIndent
+ #
+ # indentRules can also be a scalar or a hash, e.g
+ # indentRules:
+ # myexample: "\t"
+ #
+ # OR
+ #
+ # indentRules:
+ # myexample:
+ # body: " "
+ # optionalArguments: "\t \t"
+ # mandatoryArguments: ""
+ #
+ # specifying as a scalar with no field will
+ # mean that *every* field will receive the same treatment
+
+ # if the YamlName is, for example, optionalArguments, mandatoryArguments, heading, then we'll be looking for information about the *parent*
+ my $name = (defined ${$self}{nameForIndentationSettings}) ? ${$self}{nameForIndentationSettings} : ${$self}{name};
+
+ # if the YamlName is not optionalArguments, mandatoryArguments, heading (possibly others) then assume we're looking for 'body'
+ my $YamlName = $self->yaml_get_object_attribute_for_indentation_settings;
+
+ # grab the logging object
+ my $logger = get_logger("Document");
+
+ my $indentationInformation;
+ foreach my $indentationAbout ("noAdditionalIndent","indentRules"){
+ # check that the 'thing' is defined
+ if(defined ${$masterSettings{$indentationAbout}}{$name}){
+ if(ref ${$masterSettings{$indentationAbout}}{$name} eq "HASH"){
+ $logger->trace("$indentationAbout indentation specified with multiple fields for $name, searching for $name: $YamlName (see $indentationAbout)") if $is_t_switch_active ;
+ $indentationInformation = ${${$masterSettings{$indentationAbout}}{$name}}{$YamlName};
+ } else {
+ $indentationInformation = ${$masterSettings{$indentationAbout}}{$name};
+ $logger->trace("$indentationAbout indentation specified for $name (for *all* fields, body, optionalArguments, mandatoryArguments, afterHeading), using '$indentationInformation' (see $indentationAbout)") if $is_t_switch_active ;
+ }
+ # return, after performing an integrity check
+ if(defined $indentationInformation){
+ if($indentationAbout eq "noAdditionalIndent" and $indentationInformation == 1){
+ $logger->trace("Found! Using '' (see $indentationAbout)") if $is_t_switch_active;
+ return q();
+ } elsif($indentationAbout eq "indentRules" and $indentationInformation=~m/^\h*$/){
+ $logger->trace("Found! Using '$indentationInformation' (see $indentationAbout)") if $is_t_switch_active;
+ return $indentationInformation ;
+ }
+ }
+ }
+ }
+
+ # gather information
+ $YamlName = ${$self}{modifyLineBreaksYamlName};
+
+ foreach my $indentationAbout ("noAdditionalIndent","indentRules"){
+ # global assignments in noAdditionalIndentGlobal and/or indentRulesGlobal
+ my $globalInformation = $indentationAbout."Global";
+ next if(!(defined ${$masterSettings{$globalInformation}}{$YamlName}));
+ if( ($globalInformation eq "noAdditionalIndentGlobal") and ${$masterSettings{$globalInformation}}{$YamlName}==1){
+ $logger->trace("$globalInformation specified for $YamlName (see $globalInformation)") if $is_t_switch_active;
+ return q();
+ } elsif($globalInformation eq "indentRulesGlobal") {
+ if(${$masterSettings{$globalInformation}}{$YamlName}=~m/^\h*$/){
+ $logger->trace("$globalInformation specified for $YamlName (see $globalInformation)") if $is_t_switch_active;
+ return ${$masterSettings{$globalInformation}}{$YamlName};
+ } else {
+ $logger->trace("$globalInformation specified (${$masterSettings{$globalInformation}}{$YamlName}) for $YamlName, but it needs to only contain horizontal space -- I'm ignoring this one") if $is_t_switch_active;
+ }
+ }
+ }
+
+ # return defaultIndent, by default
+ $logger->trace("Using defaultIndent for $name") if $is_t_switch_active;
+ return $masterSettings{defaultIndent};
+}
+
+sub yaml_get_object_attribute_for_indentation_settings{
+ # when looking for noAdditionalIndent or indentRules, we may need to determine
+ # which thing we're looking for, e.g
+ #
+ # chapter:
+ # body: 0
+ # optionalArguments: 1
+ # mandatoryArguments: 1
+ # afterHeading: 0
+ #
+ # this method returns 'body' by default, but the other objects (optionalArgument, mandatoryArgument, afterHeading)
+ # return their appropriate identifier.
+ return "body";
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Heading.pm b/support/latexindent/LatexIndent/Heading.pm
new file mode 100644
index 0000000000..208dfa9715
--- /dev/null
+++ b/support/latexindent/LatexIndent/Heading.pm
@@ -0,0 +1,245 @@
+package LatexIndent::Heading;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::Switches qw/$is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::Special qw/$specialBeginBasicRegExp/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_heading construct_headings_levels $allHeadingsRegexp/;
+our $headingCounter;
+our @headingsRegexpArray;
+our $allHeadingsRegexp = q();
+
+sub construct_headings_levels{
+ my $self = shift;
+
+ # grab the heading levels
+ my %headingsLevels = %{$masterSettings{indentAfterHeadings}};
+
+ # output to log file
+ $logger->trace("*Constructing headings reg exp for example, chapter, section, etc (see indentAfterThisHeading)") if $is_t_switch_active ;
+
+ # delete the values that have indentAfterThisHeading set to 0
+ while( my ($headingName,$headingInfo)= each %headingsLevels){
+ if(!${$headingsLevels{$headingName}}{indentAfterThisHeading}){
+ $logger->trace("Not indenting after $headingName (see indentAfterThisHeading)") if $is_t_switch_active;
+ delete $headingsLevels{$headingName};
+ } else {
+ # *all heading* regexp, remembering to put starred headings at the front of the regexp
+ if($headingName =~ m/\*/){
+ $logger->trace("Putting $headingName at the beginning of the allHeadings regexp, as it contains a *") if $is_t_switch_active ;
+ $allHeadingsRegexp = $headingName.($allHeadingsRegexp eq '' ?q():"|$allHeadingsRegexp");
+ } else {
+ $logger->trace("Putting $headingName at the END of the allHeadings regexp") if $is_t_switch_active ;
+ $allHeadingsRegexp .= ($allHeadingsRegexp eq '' ?q():"|").$headingName ;
+ }
+ }
+ }
+
+ # check for a * in the name
+ $allHeadingsRegexp =~ s/\*/\\\*/g;
+
+ # sort the file extensions by preference
+ my @sortedByLevels = sort { ${$headingsLevels{$a}}{level} <=> $headingsLevels{$b}{level} } keys(%headingsLevels);
+
+ # it could be that @sortedByLevels is empty;
+ return if !@sortedByLevels;
+
+ $logger->trace("*All headings regexp: $allHeadingsRegexp") if $is_tt_switch_active;
+ $logger->trace("*Now to construct headings regexp for each level:") if $is_t_switch_active;
+
+ # loop through the levels, and create a regexp for each (min and max values are the first and last values respectively from sortedByLevels)
+ for(my $i = ${$headingsLevels{$sortedByLevels[0]}}{level}; $i <= ${$headingsLevels{$sortedByLevels[-1]}}{level}; $i++ ){
+ # level regexp
+ my @tmp = grep { ${$headingsLevels{$_}}{level} == $i } keys %headingsLevels;
+ if(@tmp){
+ my $headingsAtThisLevel = q();
+ foreach(@tmp){
+ # put starred headings at the front of the regexp
+ if($_ =~ m/\*/){
+ $logger->trace("Putting $_ at the beginning of this regexp (level $i), as it contains a *") if $is_t_switch_active;
+ $headingsAtThisLevel = $_.($headingsAtThisLevel eq '' ?q():"|$headingsAtThisLevel");
+ } else {
+ $logger->trace("Putting $_ at the END of this regexp (level $i)") if $is_t_switch_active;
+ $headingsAtThisLevel .= ($headingsAtThisLevel eq '' ?q():"|").$_ ;
+ }
+ }
+
+ # make the stars escaped correctly
+ $headingsAtThisLevel =~ s/\*/\\\*/g;
+ push(@headingsRegexpArray,$headingsAtThisLevel);
+ $logger->trace("Heading level regexp for level $i will contain: $headingsAtThisLevel") if $is_t_switch_active;
+ }
+ }
+ }
+
+sub find_heading{
+
+ # if there are no headings regexps, there's no point going any further
+ return if!@headingsRegexpArray;
+
+ my $self = shift;
+
+ # otherwise loop through the headings regexp
+ $logger->trace("*Searching ${$self}{name} for headings ") if $is_t_switch_active;
+
+ # loop through each headings match; note that we need to
+ # do it in *reverse* so as to ensure that the lower level headings get matched first of all
+ foreach(reverse(@headingsRegexpArray)){
+
+ # the regexp
+ my $headingRegExp = qr/
+ (
+ \\($_) # name stored into $2
+ ) # beginning bit into $1
+ (
+ .*?
+ ) # body into $3
+ (\R*)? # linebreaks at end of body into $4
+ ((?:\\(?:$allHeadingsRegexp))|$) # up to another heading, or else the end of the file
+ /sx;
+
+ while(${$self}{body} =~ m/$headingRegExp/){
+
+ # log file output
+ $logger->trace("heading found: $2") if $is_t_switch_active;
+
+ ${$self}{body} =~ s/
+ $headingRegExp
+ /
+ # create a new heading object
+ my $headingObject = LatexIndent::Heading->new(begin=>q(),
+ body=>$1.$3,
+ end=>q(),
+ afterbit=>($4?$4:q()).($5?$5:q()),
+ name=>$2.":heading",
+ parent=>$2,
+ nameForIndentationSettings=>$2,
+ linebreaksAtEnd=>{
+ begin=>0,
+ body=>0,
+ end=>0,
+ },
+ modifyLineBreaksYamlName=>"afterHeading",
+ endImmediatelyFollowedByComment=>0,
+ );
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($headingObject);
+ ${@{${$self}{children}}[-1]}{replacementText};
+ /xse;
+ }
+ }
+}
+
+sub get_replacement_text{
+ my $self = shift;
+
+ # the replacement text for a heading (chapter, section, etc) needs to put the trailing part back in
+ $logger->trace("Custom replacement text routine for ${$self}{name}") if $is_t_switch_active;
+ ${$self}{replacementText} = ${$self}{id}.${$self}{afterbit};
+ delete ${$self}{afterbit};
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $headingCounter++;
+
+ ${$self}{id} = "$tokens{afterHeading}$headingCounter";
+ return;
+}
+
+sub adjust_replacement_text_line_breaks_at_end{
+ return;
+}
+
+sub yaml_get_object_attribute_for_indentation_settings{
+ # when looking for noAdditionalIndent or indentRules, we may need to determine
+ # which thing we're looking for, e.g
+ #
+ # chapter:
+ # body: 0
+ # optionalArguments: 1
+ # mandatoryArguments: 1
+ # afterHeading: 0
+ #
+ # this method returns 'body' by default, but the other objects (optionalArgument, mandatoryArgument, afterHeading)
+ # return their appropriate identifier.
+ my $self = shift;
+
+ return ${$self}{modifyLineBreaksYamlName};
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # search for commands, keys, named grouping braces
+ $self->find_commands_or_key_equals_values_braces;
+
+ # we need to transfer the details from the modifyLineBreaks of the command
+ # child object to the heading object.
+ #
+ # for example, if we have
+ #
+ # \chapter{some heading here}
+ #
+ # and we want to modify the linebreak before the \chapter command using, for example,
+ #
+ # commands:
+ # CommandStartsOnOwnLine: 1
+ #
+ # then we need to transfer this information to the heading object
+ if($is_m_switch_active){
+ $logger->trace("Searching for linebreak preferences immediately infront of ${$self}{parent}") if $is_t_switch_active;
+ foreach(@{${$self}{children}}){
+ if(${$_}{name} eq ${$self}{parent}){
+ $logger->trace("Named child found: ${$_}{name}") if $is_t_switch_active;
+ if(defined ${$_}{BeginStartsOnOwnLine}){
+ $logger->trace("Transferring information from ${$_}{id} (${$_}{name}) to ${$self}{id} (${$self}{name}) for BeginStartsOnOwnLine") if $is_t_switch_active;
+ ${$self}{BeginStartsOnOwnLine} = ${$_}{BeginStartsOnOwnLine};
+ } else {
+ $logger->trace("No information found in ${$_}{name} for BeginStartsOnOwnLine") if $is_t_switch_active;
+ }
+ last;
+ }
+ }
+ }
+
+ # search for special begin/end
+ $self->find_special if ${$self}{body} =~ m/$specialBeginBasicRegExp/s;
+
+ return;
+}
+
+sub add_surrounding_indentation_to_begin_statement{
+ # almost all of the objects add surrounding indentation to the 'begin' statements,
+ # but some (e.g HEADING) have their own method
+ my $self = shift;
+
+ $logger->trace("Adding surrounding indentation after (empty, by design!) begin statement of ${$self}{name} (${$self}{id})") if $is_t_switch_active;
+ ${$self}{begin} .= ${$self}{surroundingIndentation}; # add indentation
+
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/HiddenChildren.pm b/support/latexindent/LatexIndent/HiddenChildren.pm
new file mode 100644
index 0000000000..878939fd41
--- /dev/null
+++ b/support/latexindent/LatexIndent/HiddenChildren.pm
@@ -0,0 +1,205 @@
+package LatexIndent::HiddenChildren;
+# 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 LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_m_switch_active /;
+use LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::LogFile qw/$logger/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @EXPORT_OK = qw/find_surrounding_indentation_for_children update_family_tree get_family_tree check_for_hidden_children %familyTree/;
+
+# hiddenChildren can be stored in a global array, it doesn't matter what level they're at
+our %familyTree;
+our %allChildren;
+
+
+#----------------------------------------------------------
+# Discussion surrounding hidden children
+#
+# Consider the following latex code
+#
+# \begin{one}
+# body of one
+# body of one
+# body of one
+# \begin{two}
+# body of two
+# body of two
+# body of two
+# body of two
+# \end{two}
+# \end{one}
+#
+# From the visual perspective, we might say that <one> and <two> are *nested* children;
+# from the persepective of latexindent.pl, however, they actually have *the same level*.
+#
+# Graphically, you might represent it as follows
+#
+# *
+# / \
+# / \
+# / \
+# O O
+#
+# where * represents the 'root' document object, and each 'O' is an environment object; the
+# first one, on the left, represents <two> and the second one, on the right, represents <one>.
+# (Remember that the environment regexp does not allow \begin within its body.)
+#
+# When processing the document, <one> will be processed *before* <two>. Furthermore, because
+# <one> and <two> are at the same level, they are not *natural* ancestors of each other; as such,
+# we say that <two> is a *hidden* child, and that its 'adopted' ancestor is <one>.
+#
+# We need to go to a lot of effort to make sure that <two> knows about its ancestors and its
+# surrounding indentation (<one> in this case). The subroutines in this file do that effort.
+#----------------------------------------------------------
+
+sub find_surrounding_indentation_for_children{
+ my $self = shift;
+
+ # output to logfile
+ $logger->trace("*FamilyTree before update:") if $is_tt_switch_active;
+ $logger->trace(Dumper(\%familyTree)) if($is_tt_switch_active);
+
+ # update the family tree with ancestors
+ $self->update_family_tree;
+
+ # output information to the logfile
+ $logger->trace("*FamilyTree after update:") if $is_tt_switch_active;
+ $logger->trace(Dumper(\%familyTree)) if($is_tt_switch_active);
+
+ while( my ($idToSearch,$ancestorToSearch) = each %familyTree){
+ $logger->trace("*Hidden child ID: ,$idToSearch, here are its ancestors:") if $is_t_switch_active;
+ foreach(@{${$ancestorToSearch}{ancestors}}){
+ $logger->trace("ID: ${$_}{ancestorID}") if($is_t_switch_active);
+ my $tmpIndentation = ref(${$_}{ancestorIndentation}) eq 'SCALAR'?${${$_}{ancestorIndentation}}:${$_}{ancestorIndentation};
+ $tmpIndentation = $tmpIndentation ? $tmpIndentation : q();
+ $logger->trace("indentation: '$tmpIndentation'") if($is_t_switch_active);
+ }
+ }
+
+ return;
+}
+
+sub update_family_tree{
+ my $self = shift;
+
+ # loop through the hash
+ $logger->trace("*Updating FamilyTree...") if $is_t_switch_active;
+ while( my ($idToSearch,$ancestorToSearch)= each %familyTree){
+ $logger->trace("*current ID: $idToSearch") if($is_t_switch_active);
+ foreach(@{${$ancestorToSearch}{ancestors}}){
+ my $ancestorID = ${$_}{ancestorID};
+
+ # construct the natural ancestors
+ my $naturalAncestors = q();
+ foreach(@{${$familyTree{$idToSearch}}{ancestors}}){
+ $naturalAncestors .= "---".${$_}{ancestorID} if(${$_}{type} eq "natural");
+ }
+
+ # we only need to update the family tree if the $ancestorID is *not* a natural
+ # ancestor, otherwise everything will be taken care of by the natural ancestor
+ if($naturalAncestors !~ m/$ancestorID/){
+ $logger->trace("ancestor: $ancestorID") if($is_t_switch_active);
+ if($familyTree{$ancestorID}){
+ $logger->trace("$ancestorID is a key within familyTree, grabbing its ancestors") if($is_t_switch_active);
+ foreach(@{${$familyTree{$ancestorID}}{ancestors}}){
+ $logger->trace("ancestor of *hidden* child: ${$_}{ancestorID}") if($is_t_switch_active);
+ my $newAncestorId = ${$_}{ancestorID};
+ my $type;
+ if($naturalAncestors =~ m/$ancestorID/){
+ $type = "natural";
+ } else {
+ $type = "adopted";
+ }
+ my $matched = grep { $_->{ancestorID} eq $newAncestorId } @{${$familyTree{$idToSearch}}{ancestors}};
+ push(@{${$familyTree{$idToSearch}}{ancestors}},{ancestorID=>${$_}{ancestorID},ancestorIndentation=>${$_}{ancestorIndentation},type=>$type}) unless($matched);
+ }
+ } else {
+ $logger->trace("natural ancestors of $ancestorID: $naturalAncestors") if($is_t_switch_active);
+ foreach(@{${$allChildren{$ancestorID}}{ancestors}}){
+ my $newAncestorId = ${$_}{ancestorID};
+ my $type;
+ if($naturalAncestors =~ m/$newAncestorId/){
+ $type = "natural";
+ } else {
+ $type = "adopted";
+ }
+ my $matched = grep { $_->{ancestorID} eq $newAncestorId } @{${$familyTree{$idToSearch}}{ancestors}};
+ unless($matched){
+ $logger->trace("ancestor of UNHIDDEN child: ${$_}{ancestorID}") if($is_t_switch_active);
+ push(@{${$familyTree{$idToSearch}}{ancestors}},{ancestorID=>${$_}{ancestorID},ancestorIndentation=>${$_}{ancestorIndentation},type=>$type});
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
+
+sub check_for_hidden_children{
+
+ my $self = shift;
+
+ my @matched;
+ # grab the matches
+ if($is_m_switch_active){
+ # if modifyLineBreaks is active, then the IDS can be split across lines
+ my $ifElseFiSpecialBegin = join("\\R?\\h*",split(//,$tokens{ifelsefiSpecial}));
+ my $BeginwithLineBreaks = join("\\R?\\h*",split(//,$tokens{beginOfToken}));
+ my $EndwithLineBreaks = join("\\R?\\h*",split(//,$tokens{endOfToken}));
+ my $BlankLinesWithLineBreaks = join("\\R?\\h*",split(//,$tokens{blanklines}));
+ @matched = (${$self}{body} =~ /(?!$BlankLinesWithLineBreaks)((?:$ifElseFiSpecialBegin)?$BeginwithLineBreaks[-a-z0-9\n]+?$EndwithLineBreaks)/ig);
+
+ # remove line breaks and horizontal space from matches
+ $_ =~ s/\R|\h//gs foreach (@matched);
+ } else {
+ @matched = (${$self}{body} =~ /((?:$tokens{ifelsefiSpecial})?$tokens{beginOfToken}.[-a-z0-9]+?$tokens{endOfToken})/igs);
+ }
+
+ # log file
+ $logger->trace("*Hidden children check") if $is_t_switch_active;
+ $logger->trace(join("|",@matched)) if $is_t_switch_active;
+
+ my $naturalAncestors = ${$self}{naturalAncestors};
+
+ # loop through the hidden children
+ foreach my $match (@matched){
+ # update the family tree with ancestors of self
+ if(${$self}{ancestors}){
+ foreach(@{${$self}{ancestors}}){
+ my $newAncestorId = ${$_}{ancestorID};
+ unless (grep { $_->{ancestorID} eq $newAncestorId } @{${$familyTree{$match}}{ancestors}}){
+ my $type = ($naturalAncestors =~ m/${$_}{ancestorID}/ ) ? "natural" : "adopted";
+ $logger->trace("Adding ${$_}{ancestorID} to the $type family tree of $match") if($is_t_switch_active);
+ push(@{$familyTree{$match}{ancestors}},{ancestorID=>${$_}{ancestorID},ancestorIndentation=>${$_}{ancestorIndentation},type=>$type});
+ }
+ }
+ }
+
+ # update the family tree with self
+ unless (grep { $_->{ancestorID} eq ${$self}{id}} @{${$familyTree{$match}}{ancestors}}){
+ my $type = ($naturalAncestors =~ m/${$self}{id}/ ) ? "natural" : "adopted";
+ $logger->trace("Adding ${$self}{id} to the $type family tree of hiddenChild $match") if($is_t_switch_active);
+ push(@{$familyTree{$match}{ancestors}},{ancestorID=>${$self}{id},ancestorIndentation=>${$self}{indentation},type=>$type});
+ }
+ }
+
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/HorizontalWhiteSpace.pm b/support/latexindent/LatexIndent/HorizontalWhiteSpace.pm
new file mode 100644
index 0000000000..9c5a04e2fb
--- /dev/null
+++ b/support/latexindent/LatexIndent/HorizontalWhiteSpace.pm
@@ -0,0 +1,79 @@
+package LatexIndent::HorizontalWhiteSpace;
+# 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 LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use Exporter qw/import/;
+our @EXPORT_OK = qw/remove_trailing_whitespace remove_leading_space/;
+
+sub remove_trailing_whitespace{
+ my $self = shift;
+ my %input = @_;
+
+ $logger->trace("*Horizontal space removal routine") if $is_t_switch_active;
+
+ # removeTrailingWhitespace can be either a hash or a scalar, but if
+ # it's a scalar, we need to fix it
+ if(ref($masterSettings{removeTrailingWhitespace}) ne 'HASH'){
+ $logger->trace("removeTrailingWhitespace specified as scalar, will update it to be a hash") if $is_t_switch_active;
+ # grab the value
+ my $removeTWS = $masterSettings{removeTrailingWhitespace};
+
+ # delete the scalar
+ delete $masterSettings{removeTrailingWhitespace};
+
+ # redefine it as a hash
+ ${$masterSettings{removeTrailingWhitespace}}{beforeProcessing} = $removeTWS;
+ ${$masterSettings{removeTrailingWhitespace}}{afterProcessing} = $removeTWS;
+ $logger->trace("removeTrailingWhitespace: beforeProcessing is now $removeTWS") if $is_t_switch_active;
+ $logger->trace("removeTrailingWhitespace: afterProcessing is now $removeTWS") if $is_t_switch_active;
+ }
+
+ # this method can be called before the indendation, and after, depending upon the input
+ if($input{when} eq "before"){
+ return unless(${$masterSettings{removeTrailingWhitespace}}{beforeProcessing});
+ $logger->trace("Removing trailing white space *before* the document is processed (see removeTrailingWhitespace: beforeProcessing)") if $is_t_switch_active;
+ } elsif($input{when} eq "after"){
+ return unless(${$masterSettings{removeTrailingWhitespace}}{afterProcessing});
+ $logger->trace("Removing trailing white space *after* the document is processed (see removeTrailingWhitespace: afterProcessing)") if $is_t_switch_active;
+ } else {
+ return;
+ }
+
+ ${$self}{body} =~ s/
+ \h+ # followed by possible horizontal space
+ $ # up to the end of a line
+ //xsmg;
+
+}
+
+sub remove_leading_space{
+ my $self = shift;
+ $logger->trace("*Removing leading space from ${$self}{name} (verbatim/noindentblock already accounted for)") if $is_t_switch_active;
+ ${$self}{body} =~ s/
+ (
+ ^ # beginning of the line
+ \h* # with 0 or more horizontal spaces
+ )? # possibly
+ //mxg;
+ return;
+}
+
+
+1;
diff --git a/support/latexindent/LatexIndent/IfElseFi.pm b/support/latexindent/LatexIndent/IfElseFi.pm
new file mode 100644
index 0000000000..056b36d8c3
--- /dev/null
+++ b/support/latexindent/LatexIndent/IfElseFi.pm
@@ -0,0 +1,211 @@
+package LatexIndent::IfElseFi;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::Heading qw/$allHeadingsRegexp/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_ifelsefi construct_ifelsefi_regexp $ifElseFiBasicRegExp/;
+our $ifElseFiCounter;
+our $ifElseFiRegExp;
+our $ifElseFiBasicRegExp = qr/\\if/;
+
+# store the regular expresssion for matching and replacing the \if...\else...\fi statements
+# note: we search for \else separately in an attempt to keep this regexp a little more managable
+
+sub construct_ifelsefi_regexp{
+ my $ifElseFiNameRegExp = qr/${${$masterSettings{fineTuning}}{ifElseFi}}{name}/;
+ $ifElseFiRegExp = qr/
+ (
+ \\
+ ($ifElseFiNameRegExp)
+ \h*
+ (\R*)
+ ) # begin statement, e.g \ifnum, \ifodd
+ (
+ \\(?!if)|[0-9]|\R|\h|\#|!-!|$trailingCommentRegExp # up until a \\, linebreak # or !-!, which is
+ ) # part of the tokens used for latexindent
+ (
+ (?:
+ (?!\\if).
+ )*? # body, which can't include another \if
+ )
+ (\R*) # linebreaks after body
+ (
+ \\fi(?![a-zA-Z]) # \fi statement
+ )
+ (\h*) # 0 or more horizontal spaces
+ (\R)? # linebreaks after \fi
+/sx;
+}
+
+sub find_ifelsefi{
+ my $self = shift;
+
+ while( ${$self}{body} =~ m/$ifElseFiRegExp\h*($trailingCommentRegExp)?/){
+
+ ${$self}{body} =~ s/
+ $ifElseFiRegExp(\h*)($trailingCommentRegExp)?
+ /
+ # create a new IfElseFi object
+ my $ifElseFi = LatexIndent::IfElseFi->new(begin=>$1.(($4 eq "\n" and !$3)?"\n":q()),
+ name=>$2,
+ # if $4 is a line break, don't count it twice (it will already be in 'begin')
+ body=>($4 eq "\n") ? $5.$6 : $4.$5.$6,
+ end=>$7,
+ linebreaksAtEnd=>{
+ begin=>(($4 eq "\n")||$3)?1:0,
+ body=>$6?1:0,
+ end=>$9?1:0,
+ },
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"IfStartsOnOwnLine",
+ # end statements
+ EndStartsOnOwnLine=>"FiStartsOnOwnLine",
+ # after end statements
+ EndFinishesWithLineBreak=>"FiFinishesWithLineBreak",
+ },
+ modifyLineBreaksYamlName=>"ifElseFi",
+ endImmediatelyFollowedByComment=>$9?0:($11?1:0),
+ horizontalTrailingSpace=>$8?$8:q(),
+ );
+ # log file output
+ $logger->trace("*IfElseFi found: $2")if $is_t_switch_active;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($ifElseFi);
+ ${@{${$self}{children}}[-1]}{replacementText}.($10?$10:q()).($11?$11:q());
+ /xse;
+
+ }
+ return;
+}
+
+sub post_indentation_check{
+ # needed to remove leading horizontal space before \else
+ my $self = shift;
+
+ # loop through \else and \or
+ foreach ({regExp=>qr/\\else/},{regExp=>qr/\\or/}){
+ my %else = %{$_};
+ if(${$self}{body} =~ m/^\h*$else{regExp}/sm
+ and
+ !(${$self}{body} =~ m/^\h*$else{regExp}/s and ${$self}{linebreaksAtEnd}{begin}==0)
+ ){
+ $logger->trace("*Adding surrounding indentation to $else{regExp} statement(s) ('${$self}{surroundingIndentation}')") if $is_t_switch_active;
+ ${$self}{body} =~ s/^\h*($else{regExp})/${$self}{surroundingIndentation}$1/smg;
+ }
+ }
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # check for existence of \else statement, and associated line break information
+ $self->check_for_else_statement(
+ # else name regexp
+ elseNameRegExp=>qr|\\else|,
+ # else statements name
+ ElseStartsOnOwnLine=>"ElseStartsOnOwnLine",
+ # end statements
+ ElseFinishesWithLineBreak=>"ElseFinishesWithLineBreak",
+ # for the YAML settings storage
+ storageNameAppend=>"else",
+ # logfile information
+ logName=>"else",
+ );
+
+ # check for existence of \or statement, and associated line break information
+ $self->check_for_else_statement(
+ # else name regexp
+ elseNameRegExp=>qr|\\or|,
+ # else statements name
+ ElseStartsOnOwnLine=>"OrStartsOnOwnLine",
+ # end statements
+ ElseFinishesWithLineBreak=>"OrFinishesWithLineBreak",
+ # for the YAML settings storage
+ storageNameAppend=>"or",
+ # logfile information
+ logName=>"or",
+ );
+
+ # search for headings (important to do this before looking for commands!)
+ $self->find_heading if ${$self}{body} =~ m/$allHeadingsRegexp/s;
+
+ # search for commands and special code blocks
+ $self->find_commands_or_key_equals_values_braces_and_special;
+
+}
+
+sub indent_begin{
+ my $self = shift;
+ # line break checks after \if statement, can get messy if we
+ # have, for example
+ # \ifnum
+ # something
+ # which might be changed into
+ # \ifnumsomething
+ # which is undeserible
+ if (defined ${$self}{BodyStartsOnOwnLine}
+ and ${$self}{BodyStartsOnOwnLine}==-1
+ and ${$self}{body} !~ m/^(\h|\\|(?:!-!))/s
+ ){
+ ${$self}{begin} .= " ";
+ }
+}
+
+sub wrap_up_statement{
+ my $self = shift;
+
+ # line break checks *after* \end{statement}
+ if (defined ${$self}{EndFinishesWithLineBreak}
+ and ${$self}{EndFinishesWithLineBreak}==-1
+ ) {
+ # add a single horizontal space after the child id, otherwise we can end up
+ # with things like
+ # before:
+ # \fi
+ # text
+ # after:
+ # \fitext
+ $logger->trace("*Adding a single space after \\fi statement (otherwise \\fi can be comined with next line of text in an unwanted way)") if $is_t_switch_active;
+ ${$self}{end} =${$self}{end}." ";
+ }
+ $logger->trace("*Finished indenting ${$self}{name}") if $is_t_switch_active;
+ return $self;
+}
+
+
+sub create_unique_id{
+ my $self = shift;
+
+ $ifElseFiCounter++;
+
+ ${$self}{id} = "$tokens{ifElseFi}$ifElseFiCounter";
+ return;
+}
+
+
+1;
diff --git a/support/latexindent/LatexIndent/Indent.pm b/support/latexindent/LatexIndent/Indent.pm
new file mode 100644
index 0000000000..eb36db2108
--- /dev/null
+++ b/support/latexindent/LatexIndent/Indent.pm
@@ -0,0 +1,425 @@
+package LatexIndent::Indent;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::Switches qw/$is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::HiddenChildren qw/%familyTree/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::LogFile qw/$logger/;
+use Text::Tabs;
+use Data::Dumper;
+use Exporter qw/import/;
+our @EXPORT_OK = qw/indent wrap_up_statement determine_total_indentation indent_begin indent_body indent_end_statement final_indentation_check push_family_tree_to_indent get_surrounding_indentation indent_children_recursively check_for_blank_lines_at_beginning put_blank_lines_back_in_at_beginning add_surrounding_indentation_to_begin_statement post_indentation_check/;
+our %familyTree;
+
+sub indent{
+ my $self = shift;
+
+ # determine the surrounding and current indentation
+ $self->determine_total_indentation;
+
+ # indent the begin statement
+ $self->indent_begin;
+
+ # indent the body
+ $self->indent_body;
+
+ # indent the end statement
+ $self->indent_end_statement;
+
+ # output the completed object to the log file
+ $logger->trace("Complete indented object (${$self}{name}) after indentation:\n${$self}{begin}${$self}{body}${$self}{end}") if $is_tt_switch_active;
+
+ # wrap-up statement
+ $self->wrap_up_statement;
+ return $self;
+}
+
+sub wrap_up_statement{
+ my $self = shift;
+ $logger->trace("*Finished indenting ${$self}{name}") if $is_t_switch_active;
+ return $self;
+ }
+
+sub determine_total_indentation{
+ my $self = shift;
+
+ # calculate and grab the surrounding indentation
+ $self->get_surrounding_indentation;
+
+ # logfile information
+ my $surroundingIndentation = ${$self}{surroundingIndentation};
+ $logger->trace("indenting object ${$self}{name}") if($is_t_switch_active);
+ (my $during = $surroundingIndentation) =~ s/\t/TAB/g;
+ $logger->trace("indentation *surrounding* object: '$during'") if($is_t_switch_active);
+ ($during = ${$self}{indentation}) =~ s/\t/TAB/g;
+ $logger->trace("indentation *of* object: '$during'") if($is_t_switch_active);
+ ($during = $surroundingIndentation.${$self}{indentation}) =~ s/\t/TAB/g;
+ $logger->trace("*total* indentation to be added: '$during'") if($is_t_switch_active);
+
+ # form the total indentation of the object
+ ${$self}{indentation} = $surroundingIndentation.${$self}{indentation};
+
+}
+
+sub get_surrounding_indentation{
+ my $self = shift;
+
+ my $surroundingIndentation = q();
+
+ if($familyTree{${$self}{id}}){
+ $logger->trace("Adopted ancestors found!") if($is_t_switch_active);
+ foreach(@{${$familyTree{${$self}{id}}}{ancestors}}){
+ if(${$_}{type} eq "adopted"){
+ my $newAncestorId = ${$_}{ancestorID};
+ $logger->trace("ancestor ID: $newAncestorId, adding indentation of $newAncestorId to surroundingIndentation of ${$self}{id}") if($is_t_switch_active);
+ $surroundingIndentation .= ref(${$_}{ancestorIndentation}) eq 'SCALAR'
+ ?
+ (${${$_}{ancestorIndentation}}?${${$_}{ancestorIndentation}}:q())
+ :
+ (${$_}{ancestorIndentation}?${$_}{ancestorIndentation}:q());
+ }
+ }
+ }
+ ${$self}{surroundingIndentation} = $surroundingIndentation;
+
+}
+
+sub indent_begin{
+ # for most objects, the begin statement is just one line, but there are exceptions, e.g KeyEqualsValuesBraces
+ return;
+}
+
+sub indent_body{
+ my $self = shift;
+
+ # grab the indentation of the object
+ my $indentation = ${$self}{indentation};
+
+ # output to the logfile
+ $logger->trace("Body (${$self}{name}) before indentation:\n${$self}{body}") if $is_tt_switch_active;
+
+ # last minute check for modified bodyLineBreaks
+ $self->count_body_line_breaks if $is_m_switch_active;
+
+ # some objects need to check for blank line tokens at the beginning
+ $self->check_for_blank_lines_at_beginning if $is_m_switch_active;
+
+ # some objects can format their body to align at the & character
+ $self->align_at_ampersand if ${$self}{lookForAlignDelims};
+
+ # possibly remove paragraph line breaks
+ $self->remove_paragraph_line_breaks if ($is_m_switch_active and ${$self}{removeParagraphLineBreaks} and !${$masterSettings{modifyLineBreaks}{removeParagraphLineBreaks}}{beforeTextWrap});
+
+ # body indendation
+ if(${$self}{linebreaksAtEnd}{begin}==1){
+ if(${$self}{body} =~ m/^\h*$/s){
+ $logger->trace("Body of ${$self}{name} is empty, not applying indentation") if $is_t_switch_active;
+ } else {
+ # put any existing horizontal space after the current indentation
+ $logger->trace("Entire body of ${$self}{name} receives indendentation") if $is_t_switch_active;
+ ${$self}{body} =~ s/^(\h*)/$indentation$1/mg; # add indentation
+ }
+ } elsif(${$self}{linebreaksAtEnd}{begin}==0 and ${$self}{bodyLineBreaks}>0) {
+ if(${$self}{body} =~ m/
+ (.*?) # content of first line
+ \R # first line break
+ (.*$) # rest of body
+ /sx){
+ my $bodyFirstLine = $1;
+ my $remainingBody = $2;
+ $logger->trace("first line of body: $bodyFirstLine") if $is_tt_switch_active;
+ $logger->trace("remaining body (before indentation):\n'$remainingBody'") if($is_tt_switch_active);
+
+ # add the indentation to all the body except first line
+ $remainingBody =~ s/^/$indentation/mg unless($remainingBody eq ''); # add indentation
+ $logger->trace("remaining body (after indentation):\n$remainingBody'") if($is_tt_switch_active);
+
+ # put the body back together
+ ${$self}{body} = $bodyFirstLine."\n".$remainingBody;
+ }
+ }
+
+ # some objects need a post-indentation check, e.g ifElseFi
+ $self->post_indentation_check;
+ # if the routine check_for_blank_lines_at_beginning has been called, then the following routine
+ # puts blank line tokens back in
+ $self->put_blank_lines_back_in_at_beginning if $is_m_switch_active;
+
+ # the final linebreak can be modified by a child object; see test-cases/commands/figureValign-mod5.tex, for example
+ if($is_m_switch_active and defined ${$self}{linebreaksAtEnd}{body} and ${$self}{linebreaksAtEnd}{body}==1 and ${$self}{body} !~ m/\R$/ and ${$self}{body} ne ''){
+ $logger->trace("Adding a linebreak at end of body for ${$self}{name} to contain a linebreak at the end (linebreaksAtEnd is 1, but there isn't currently a linebreak)") if($is_t_switch_active);
+ ${$self}{body} .= "\n";
+ }
+
+ # output to the logfile
+ $logger->trace("Body (${$self}{name}) after indentation:\n${$self}{body}") if $is_tt_switch_active;
+ return $self;
+}
+
+sub post_indentation_check{
+ return;
+}
+
+sub check_for_blank_lines_at_beginning{
+ # some objects need this routine
+ return;
+}
+
+sub put_blank_lines_back_in_at_beginning{
+ # some objects need this routine
+ return;
+}
+
+sub indent_end_statement{
+ my $self = shift;
+ my $surroundingIndentation = (${$self}{surroundingIndentation} and $familyTree{${$self}{id}})
+ ?
+ (ref(${$self}{surroundingIndentation}) eq 'SCALAR'?${${$self}{surroundingIndentation}}:${$self}{surroundingIndentation})
+ :q();
+
+ # end{statement} indentation, e.g \end{environment}, \fi, }, etc
+ if(${$self}{linebreaksAtEnd}{body}){
+ ${$self}{end} =~ s/^\h*/$surroundingIndentation/mg; # add indentation
+ $logger->trace("Adding surrounding indentation to ${$self}{end} (${$self}{name}: '$surroundingIndentation')") if($is_t_switch_active);
+ }
+ return $self;
+}
+
+sub final_indentation_check{
+ # problem:
+ # if a tab is appended to spaces, it will look different
+ # from spaces appended to tabs (see test-cases/items/spaces-and-tabs.tex)
+ # solution:
+ # move all of the tabs to the beginning of ${$self}{indentation}
+ # notes;
+ # this came to light when studying test-cases/items/items1.tex
+
+ my $self = shift;
+
+ my $indentation;
+ my $numberOfTABS;
+ my $after;
+ ${$self}{body} =~ s/
+ ^((\h*|\t*)((\h+)(\t+))+)
+ /
+ # fix the indentation
+ $indentation = $1;
+
+ # count the number of tabs
+ $numberOfTABS = () = $indentation=~ \/\t\/g;
+ $logger->trace("Number of tabs: $numberOfTABS") if($is_t_switch_active);
+
+ # log the after
+ ($after = $indentation) =~ s|\t||g;
+ $after = "TAB"x$numberOfTABS.$after;
+ $logger->trace("Indentation after: '$after'") if($is_t_switch_active);
+ ($indentation = $after) =~s|TAB|\t|g;
+
+ $indentation;
+ /xsmeg;
+
+ return unless($masterSettings{maximumIndentation} =~ m/^\h+$/);
+
+ # maximum indentation check
+ $logger->trace("*Maximum indentation check") if($is_t_switch_active);
+
+ # replace any leading tabs with spaces, and update the body
+ my @expanded_lines = expand(${$self}{body});
+ ${$self}{body} = join("",@expanded_lines);
+
+ # grab the maximum indentation
+ my $maximumIndentation = $masterSettings{maximumIndentation};
+ my $maximumIndentationLength = length($maximumIndentation)+1;
+
+ # replace any leading space that is greater than the
+ # specified maximum indentation with the maximum indentation
+ ${$self}{body} =~ s/^\h{$maximumIndentationLength,}/$maximumIndentation/smg;
+}
+
+sub indent_children_recursively{
+ my $self = shift;
+
+ unless(defined ${$self}{children}) {
+ $logger->trace("No child objects (${$self}{name})") if $is_t_switch_active;
+ return;
+ }
+
+ $logger->trace('Pre-processed body:') if $is_tt_switch_active;
+ $logger->trace(${$self}{body}) if($is_tt_switch_active);
+
+ # send the children through this indentation routine recursively
+ if(defined ${$self}{children}){
+ foreach my $child (@{${$self}{children}}){
+ $logger->trace("Indenting child objects on ${$child}{name}") if $is_t_switch_active;
+ $child->indent_children_recursively;
+ }
+ }
+
+ $logger->trace("*Replacing ids with begin, body, and end statements:") if $is_t_switch_active;
+
+ # loop through document children hash
+ while( scalar (@{${$self}{children}}) > 0 ){
+ my $index = 0;
+ # we work through the array *in order*
+ foreach my $child (@{${$self}{children}}){
+ $logger->trace("Searching ${$self}{name} for ${$child}{id}...") if $is_t_switch_active;
+ if(${$self}{body} =~ m/${$child}{idRegExp}/s){
+ # we only care if id is first non-white space character
+ # and if followed by line break
+ # if m switch is active
+ my $IDFirstNonWhiteSpaceCharacter = 0;
+ my $IDFollowedImmediatelyByLineBreak = 0;
+
+ # update the above two, if necessary
+ if ($is_m_switch_active){
+ $IDFirstNonWhiteSpaceCharacter = (${$self}{body} =~ m/^${$child}{idRegExp}/m
+ or
+ ${$self}{body} =~ m/^\h\h*${$child}{idRegExp}/m
+ ) ?1:0;
+ $IDFollowedImmediatelyByLineBreak = (${$self}{body} =~ m/${$child}{idRegExp}\h*\R+/m) ?1:0;
+ ${$child}{IDFollowedImmediatelyByLineBreak} = $IDFollowedImmediatelyByLineBreak;
+ }
+
+ # log file info
+ $logger->trace("${$child}{id} found!") if($is_t_switch_active);
+ $logger->trace("*Indenting ${$child}{name} (id: ${$child}{id})") if $is_t_switch_active;
+ $logger->trace("looking up indentation scheme for ${$child}{name}") if($is_t_switch_active);
+
+ # line break checks *after* <end statement>
+ if (defined ${$child}{EndFinishesWithLineBreak}
+ and ${$child}{EndFinishesWithLineBreak}==-1
+ and $IDFollowedImmediatelyByLineBreak) {
+ # remove line break *after* <end statement>, if appropriate
+ my $EndStringLogFile = ${$child}{aliases}{EndFinishesWithLineBreak}||"EndFinishesWithLineBreak";
+ $logger->trace("Removing linebreak after ${$child}{end} (see $EndStringLogFile)") if $is_t_switch_active;
+ ${$self}{body} =~ s/${$child}{idRegExp}(\h*)?(\R|\h)*/${$child}{id}$1/s;
+ ${$child}{linebreaksAtEnd}{end} = 0;
+ }
+
+ # perform indentation
+ $child->indent;
+
+ # surrounding indentation is now up to date
+ my $surroundingIndentation = (${$child}{surroundingIndentation} and ${$child}{hiddenChildYesNo})
+ ?
+ (ref(${$child}{surroundingIndentation}) eq 'SCALAR'?${${$child}{surroundingIndentation}}:${$child}{surroundingIndentation})
+ :q();
+
+ # line break checks before <begin statement>
+ if(defined ${$child}{BeginStartsOnOwnLine}){
+ my $BeginStringLogFile = ${$child}{aliases}{BeginStartsOnOwnLine}||"BeginStartsOnOwnLine";
+
+ #
+ # Blank line poly-switch notes (==4)
+ #
+ # when BeginStartsOnOwnLine=4 we adopt the following approach:
+ # temporarily change BeginStartsOnOwnLine to -1, make adjustments
+ # temporarily change BeginStartsOnOwnLine to 3, make adjustments
+ #
+ # we use an array, @polySwitchValues to facilitate this
+ my @polySwitchValues = (${$child}{BeginStartsOnOwnLine}==4)?(-1,3):(${$child}{BeginStartsOnOwnLine});
+
+ foreach(@polySwitchValues){
+ # if BeginStartsOnOwnLine is 4, then we hack
+ # $IDFirstNonWhiteSpaceCharacter
+ # to be 0 on the second time through (poly-switch set to 3)
+ $IDFirstNonWhiteSpaceCharacter = 0 if (${$child}{BeginStartsOnOwnLine}==4 and $_==3);
+
+ # if the child ID is not the first character and BeginStartsOnOwnLine>=1
+ # then we will need to add a line break (==1), a comment (==2) or another blank line (==3)
+ if($_>=1 and !$IDFirstNonWhiteSpaceCharacter){
+ # by default, assume that no trailing comment token is needed
+ my $trailingCharacterToken = q();
+ if($_==2){
+ $logger->trace("Removing space immediately before ${$child}{id}, in preparation for adding % ($BeginStringLogFile == 2)") if $is_t_switch_active;
+ ${$self}{body} =~ s/\h*${$child}{idRegExp}/${$child}{id}/s;
+ $logger->trace("Adding a % at the end of the line that ${$child}{begin} is on, then a linebreak ($BeginStringLogFile == 2)") if $is_t_switch_active;
+ $trailingCharacterToken = "%".$self->add_comment_symbol;
+ } elsif ($_==3){
+ $logger->trace("Adding a blank line at the end of the line that ${$child}{begin} is on, then a linebreak ($BeginStringLogFile == 3)") if $is_t_switch_active;
+ $trailingCharacterToken = "\n".(${$masterSettings{modifyLineBreaks}}{preserveBlankLines}?$tokens{blanklines}:q());
+ } else {
+ $logger->trace("Adding a linebreak at the beginning of ${$child}{begin} (see $BeginStringLogFile)") if $is_t_switch_active;
+ }
+
+ # the trailing comment/linebreak magic
+ ${$child}{begin} = "$trailingCharacterToken\n".${$child}{begin};
+ $child->add_surrounding_indentation_to_begin_statement;
+
+ # remove surrounding indentation ahead of %
+ ${$child}{begin} =~ s/^(\h*)%/%/ if($_==2);
+ } elsif ($_==-1 and $IDFirstNonWhiteSpaceCharacter){
+ # finally, if BeginStartsOnOwnLine == -1 then we might need to *remove* a blank line(s)
+ # important to check we don't move the begin statement next to a blank-line-token
+ my $blankLineToken = $tokens{blanklines};
+ if(${$self}{body} !~ m/$blankLineToken\R*\h*${$child}{idRegExp}/s){
+ $logger->trace("Removing linebreak before ${$child}{begin} (see $BeginStringLogFile in ${$child}{modifyLineBreaksYamlName} YAML)") if $is_t_switch_active;
+ ${$self}{body} =~ s/(\h*)(?:\R*|\h*)+${$child}{idRegExp}/$1${$child}{id}/s;
+ } else {
+ $logger->trace("Not removing linebreak ahead of ${$child}{begin}, as blank-line-token present (see preserveBlankLines)") if $is_t_switch_active;
+ }
+ }
+ }
+ }
+
+ $logger->trace(Dumper(\%{$child})) if($is_tt_switch_active);
+
+ # replace ids with body
+ ${$self}{body} =~ s/${$child}{idRegExp}/${$child}{begin}${$child}{body}${$child}{end}/;
+
+ # log file info
+ $logger->trace("Body (${$self}{name}) now looks like:") if $is_tt_switch_active;
+ $logger->trace(${$self}{body}) if($is_tt_switch_active);
+
+ # remove element from array: http://stackoverflow.com/questions/174292/what-is-the-best-way-to-delete-a-value-from-an-array-in-perl
+ splice(@{${$self}{children}}, $index, 1);
+
+ # output to the log file
+ $logger->trace("deleted child key ${$child}{name} (parent is: ${$self}{name})") if $is_t_switch_active;
+
+ # restart the loop, as the size of the array has changed
+ last;
+ } else {
+ $logger->trace("${$child}{id} not found") if($is_t_switch_active);
+ }
+
+ # increment the loop counter
+ $index++;
+ }
+ }
+
+ # logfile info
+ $logger->trace("${$self}{name} has this many children:") if $is_tt_switch_active;
+ $logger->trace(scalar @{${$self}{children}}) if $is_tt_switch_active;
+ $logger->trace("Post-processed body (${$self}{name}):") if($is_tt_switch_active);
+ $logger->trace(${$self}{body}) if($is_tt_switch_active);
+
+}
+
+sub add_surrounding_indentation_to_begin_statement{
+ # almost all of the objects add surrounding indentation to the 'begin' statements,
+ # but some (e.g HEADING) have their own method
+ my $self = shift;
+
+ my $surroundingIndentation = ${$self}{surroundingIndentation};
+ ${$self}{begin} =~ s/^(\h*)?/$surroundingIndentation/mg; # add indentation
+
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Item.pm b/support/latexindent/LatexIndent/Item.pm
new file mode 100644
index 0000000000..f9fbf8dd4b
--- /dev/null
+++ b/support/latexindent/LatexIndent/Item.pm
@@ -0,0 +1,148 @@
+package LatexIndent::Item;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::IfElseFi qw/$ifElseFiBasicRegExp/;
+use LatexIndent::Special qw/$specialBeginAndBracesBracketsBasicRegExp/;
+use LatexIndent::Heading qw/$allHeadingsRegexp/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_items construct_list_of_items $listOfItems/;
+our $itemCounter;
+our $listOfItems = q();
+our $itemRegExp;
+
+sub construct_list_of_items{
+ my $self = shift;
+
+ # put together a list of the items
+ while( my ($item,$lookForThisItem)= each %{$masterSettings{itemNames}}){
+ $listOfItems .= ($listOfItems eq "")?"$item":"|$item" if($lookForThisItem);
+ }
+
+ # detail items in the log
+ $logger->trace("*List of items: $listOfItems (see itemNames)") if $is_t_switch_active;
+
+ $itemRegExp = qr/
+ (
+ \\($listOfItems)
+ \h*
+ (\R*)?
+ )
+ (
+ (?: # cluster-only (), don't capture
+ (?!
+ (?:\\(?:$listOfItems)) # cluster-only (), don't capture
+ ). # any character, but not \\$item
+ )*
+ )
+ (\R)?
+ /sx;
+
+
+ return;
+}
+
+sub find_items{
+ # no point carrying on if the list of items is empty
+ return if($listOfItems eq "");
+
+ my $self = shift;
+
+ # otherwise loop through the item names
+ $logger->trace("Searching for items (see itemNames) in ${$self}{name} (see indentAfterItems)") if $is_t_switch_active;
+ $logger->trace(Dumper(\%{$masterSettings{itemNames}})) if $is_tt_switch_active;
+
+ while(${$self}{body} =~ m/$itemRegExp\h*($trailingCommentRegExp)?/){
+
+ # log file output
+ $logger->trace("*Item found: $2") if $is_t_switch_active;
+
+ ${$self}{body} =~ s/
+ $itemRegExp(\h*)($trailingCommentRegExp)?
+ /
+ # create a new Item object
+ my $itemObject = LatexIndent::Item->new(begin=>$1,
+ body=>$4,
+ end=>q(),
+ name=>$2,
+ linebreaksAtEnd=>{
+ begin=>$3?1:0,
+ body=>$5?1:0,
+ },
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"ItemStartsOnOwnLine",
+ # body statements
+ BodyStartsOnOwnLine=>"ItemFinishesWithLineBreak",
+ },
+ modifyLineBreaksYamlName=>"items",
+ endImmediatelyFollowedByComment=>$5?0:($7?1:0),
+ );
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($itemObject);
+ ${@{${$self}{children}}[-1]}{replacementText}.($6?$6:q()).($7?$7:q());
+ /xseg;
+ }
+}
+
+
+sub create_unique_id{
+ my $self = shift;
+
+ $itemCounter++;
+
+ ${$self}{id} = "$tokens{items}$itemCounter";
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # the item body could hoover up line breaks; we do an additional check
+ ${${$self}{linebreaksAtEnd}}{body}=1 if(${$self}{body} =~ m/\R+$/s );
+
+ # search for ifElseFi blocks
+ $self->find_ifelsefi if ${$self}{body} =~ m/$ifElseFiBasicRegExp/s;
+
+ # search for headings (part, chapter, section, setc)
+ $self->find_heading if ${$self}{body} =~ m/$allHeadingsRegexp/s;
+
+ # search for commands and special code blocks
+ $self->find_commands_or_key_equals_values_braces_and_special if ${$self}{body} =~ m/$specialBeginAndBracesBracketsBasicRegExp/s;
+
+}
+
+sub remove_line_breaks_begin{
+ # the \item command can need a trailing white space if the line breaks have been removed after it and
+ # there is no white space
+ my $self = shift;
+ my $BodyStringLogFile = ${$self}{aliases}{BodyStartsOnOwnLine}||"BodyStartsOnOwnLine";
+ $logger->trace("Removing linebreak at the end of begin (see $BodyStringLogFile)");
+ ${$self}{begin} =~ s/\R*$//sx;
+ ${$self}{begin} .= " " unless(${$self}{begin} =~ m/\h$/s or ${$self}{body} =~ m/^\h/s or ${$self}{body} =~ m/^\R/s );
+ ${$self}{linebreaksAtEnd}{begin} = 0;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/KeyEqualsValuesBraces.pm b/support/latexindent/LatexIndent/KeyEqualsValuesBraces.pm
new file mode 100644
index 0000000000..590d9acb8c
--- /dev/null
+++ b/support/latexindent/LatexIndent/KeyEqualsValuesBraces.pm
@@ -0,0 +1,121 @@
+package LatexIndent::KeyEqualsValuesBraces;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Command"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/construct_key_equals_values_regexp $key_equals_values_bracesRegExp $key_equals_values_bracesRegExpTrailingComment/;
+our $key_equals_values_braces_Counter;
+our $key_equals_values_bracesRegExp;
+our $key_equals_values_bracesRegExpTrailingComment;
+
+sub construct_key_equals_values_regexp{
+ my $self = shift;
+
+ # grab the arguments regexp
+ my $optAndMandRegExp = $self->get_arguments_regexp;
+
+ # blank line token
+ my $blankLineToken = $tokens{blanklines};
+
+ # read from fine tuning
+ my $keyEqualsValuesBracesBrackets = qr/${${$masterSettings{fineTuning}}{keyEqualsValuesBracesBrackets}}{name}/;
+ my $keyEqualsValuesBracesBracketsFollow = qr/${${$masterSettings{fineTuning}}{keyEqualsValuesBracesBrackets}}{follow}/;
+
+ # store the regular expresssion for matching and replacing
+ $key_equals_values_bracesRegExp = qr/
+ (
+ (?:$keyEqualsValuesBracesBracketsFollow)
+ (?:\h|\R|$blankLineToken|$trailingCommentRegExp)*
+ ) # $1 pre-key bit: could be { OR , OR [
+ (\\)? # $2 possible backslash
+ (
+ $keyEqualsValuesBracesBrackets? # lowercase|uppercase letters, @, *, numbers, forward slash, dots
+ ) # $3 name
+ (
+ (?:\h|\R|$blankLineToken|$trailingCommentRegExp)*
+ =\h*
+ (?:\d*\:?)
+ ) # $4 = symbol
+ (\R*)? # $5 linebreak after =
+ ($optAndMandRegExp) # $6 opt|mand arguments
+ (\R)? # $9 linebreak at end
+ /sx;
+
+ $key_equals_values_bracesRegExpTrailingComment = qr/$key_equals_values_bracesRegExp(\h*)((?:$trailingCommentRegExp\h*)*)?/;
+}
+
+sub indent_begin{
+ my $self = shift;
+
+ # blank line token
+ my $blankLineToken = $tokens{blanklines};
+
+ if(${$self}{begin} =~ /\R=/s or ${$self}{begin} =~ /$blankLineToken\h*=/s ){
+ $logger->trace("= found on own line in ${$self}{name}, adding indentation") if $is_t_switch_active;
+ ${$self}{begin} =~ s/=/${$self}{indentation}=/s;
+ }
+}
+
+sub check_linebreaks_before_equals{
+ # check if -m switch is active
+ return unless $is_m_switch_active;
+
+ my $self = shift;
+
+ # linebreaks *infront* of = symbol
+ if(${$self}{begin} =~ /\R\h*=/s){
+ if(defined ${$self}{EqualsStartsOnOwnLine} and ${$self}{EqualsStartsOnOwnLine}==-1){
+ $logger->trace("Removing linebreak before = symbol in ${$self}{name} (see EqualsStartsOnOwnLine)") if $is_t_switch_active;
+ ${$self}{begin} =~ s/(\R|\h)*=/=/s;
+ }
+ } else {
+ if(defined ${$self}{EqualsStartsOnOwnLine} and ${$self}{EqualsStartsOnOwnLine}==1){
+ $logger->trace("Adding a linebreak before = symbol for ${$self}{name} (see EqualsStartsOnOwnLine)") if $is_t_switch_active;
+ ${$self}{begin} =~ s/=/\n=/s;
+ } elsif(defined ${$self}{EqualsStartsOnOwnLine} and ${$self}{EqualsStartsOnOwnLine}==2){
+ $logger->trace("Adding a % linebreak immediately before = symbol for ${$self}{name} (see EqualsStartsOnOwnLine)") if $is_t_switch_active;
+ ${$self}{begin} =~ s/\h*=/%\n=/s;
+ }
+ }
+ return;
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $key_equals_values_braces_Counter++;
+ ${$self}{id} = "$tokens{keyEqualsValuesBracesBrackets}$key_equals_values_braces_Counter";
+ return;
+}
+
+sub get_replacement_text{
+ my $self = shift;
+
+ # the replacement text for a key = {value} needes to accomodate the leading [ OR { OR % OR , OR any combination thereof
+ $logger->trace("Custom replacement text routine for ${$self}{name}") if $is_t_switch_active;
+ ${$self}{replacementText} = ${$self}{beginningbit}.${$self}{id};
+ delete ${$self}{beginningbit};
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/LogFile.pm b/support/latexindent/LatexIndent/LogFile.pm
new file mode 100644
index 0000000000..75ebe0b2ea
--- /dev/null
+++ b/support/latexindent/LatexIndent/LogFile.pm
@@ -0,0 +1,251 @@
+package LatexIndent::LogFile;
+# 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 FindBin;
+use File::Basename; # to get the filename and directory path
+use Exporter qw/import/;
+use Log::Log4perl qw(get_logger :levels);
+use Log::Log4perl::Appender::Screen;
+use Log::Dispatch::File;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/%switches/;
+use LatexIndent::Version qw/$versionNumber $versionDate/;
+our @EXPORT_OK = qw/processSwitches $logger/;
+our @logFileNotes;
+our $logger = get_logger("Document");
+
+# log file methods, using log4perl; references
+# pattern layout: http://search.cpan.org/~mschilli/Log-Log4perl-1.32/lib/Log/Log4perl/Layout/PatternLayout.pm
+# multiple appenders: https://stackoverflow.com/questions/8620347/perl-log4perl-printing-and-logging-at-the-same-time-in-a-line?rq=1
+# getting started: https://www.perl.com/pub/2002/09/11/log4perl.html
+
+sub processSwitches{
+ # -v switch is just to show the version number
+ if($switches{version}) {
+ print $versionNumber,", ",$versionDate,"\n";
+ exit(2);
+ }
+
+ if(scalar(@ARGV) < 1 or $switches{showhelp}) {
+ print <<ENDQUOTE
+latexindent.pl version $versionNumber, $versionDate
+usage: latexindent.pl [options] [file][.tex|.sty|.cls|.bib|...]
+ -v, --version
+ displays the version number and date of release
+ -h, --help
+ help (see the documentation for detailed instructions and examples)
+ -sl, --screenlog
+ log file will also be output to the screen
+ -o, --outputfile=<name-of-output-file>
+ output to another file; sample usage:
+ latexindent.pl -o outputfile.tex myfile.tex
+ latexindent.pl -o=outputfile.tex myfile.tex
+ -w, --overwrite
+ overwrite the current file; a backup will be made, but still be careful
+ -s, --silent
+ silent mode: no output will be given to the terminal
+ -t, --trace
+ tracing mode: verbose information given to the log file
+ -l, --local[=myyaml.yaml]
+ use localSettings.yaml (assuming it exists in the directory of your file);
+ alternatively, use myyaml.yaml, if it exists; sample usage:
+ latexindent.pl -l some.yaml myfile.tex
+ latexindent.pl -l=another.yaml myfile.tex
+ latexindent.pl -l=some.yaml,another.yaml myfile.tex
+ -y, --yaml=<yaml settings>
+ specify YAML settings; sample usage:
+ latexindent.pl -y="defaultIndent:' '" myfile.tex
+ latexindent.pl -y="defaultIndent:' ',maximumIndentation:' '" myfile.tex
+ -d, --onlydefault
+ ONLY use defaultSettings.yaml, ignore ALL (yaml) user files
+ -g, --logfile=<name of log file>
+ used to specify the name of logfile (default is indent.log)
+ -c, --cruft=<cruft directory>
+ used to specify the location of backup files and indent.log
+ -m, --modifylinebreaks
+ modify linebreaks before, during, and at the end of code blocks;
+ trailing comments and blank lines can also be added using this feature
+ -r,--replacement
+ replacement mode, allows you to replace strings and regular expressions
+ verbatim blocks not respected
+ -rv,--replacementrespectverb
+ replacement mode, allows you to replace strings and regular expressions
+ while respecting verbatim code blocks
+ -rr,--onlyreplacement
+ *only* replacement mode, no indentation
+ verbatim blocks not respected
+ENDQUOTE
+ ;
+ exit(2);
+}
+
+ # if we've made it this far, the processing of switches and logging begins
+ my $self = shift;
+
+ ($switches{trace}||$switches{ttrace}) ? $logger->level($TRACE): $logger->level($INFO);
+
+ # cruft directory
+ ${$self}{cruftDirectory} = $switches{cruftDirectory}||(dirname ${$self}{fileName});
+ die "Could not find directory ${$self}{cruftDirectory}\nExiting, no indentation done." if(!(-d ${$self}{cruftDirectory}));
+
+ my $logfileName = ($switches{cruftDirectory} ? ${$self}{cruftDirectory} : '').($switches{logFileName}||"indent.log");
+
+ # layout of the logfile information, for example
+ #
+ # 2017/09/16 11:59:09 INFO: message
+ # 2017/09/16 12:23:53 INFO: LogFile.pm:156 LatexIndent::LogFile::processSwitches - message
+ # reference: https://stackoverflow.com/questions/46262844/log4perl-grouping-messages/46309392#46309392
+ Log::Log4perl::Layout::PatternLayout::add_global_cspec(
+ 'A', sub {
+ if($_[1] =~ /^\*/){
+ $_[1]=~s/^\*//;
+ if($_[1]=~m/\R/s){
+ my $indentation = ' '.(' ' x length $_[3]);
+ $_[1] =~ s/\R/\n$indentation/gs;
+ }
+ return "$_[3]: ".$_[1];
+ } else {
+ my $indentation = ' '.(' ' x length $_[3]);
+ $_[1] =~ s/\R/\n$indentation/gs if($_[1]=~m/\R/s);
+ return $indentation.$_[1];
+ }
+ });
+
+ my $layout = Log::Log4perl::Layout::PatternLayout->new("%A%n");
+
+ # details for the Log4perl logging
+ my $appender = Log::Log4perl::Appender->new(
+ "Log::Dispatch::File",
+ filename => $logfileName,
+ mode => "write",
+ utf8 => 1,
+ );
+
+ # add the layout
+ $appender->layout($layout);
+
+ # adjust the logger object
+ $logger->add_appender($appender);
+
+ # appender object for output to screen
+ my $appender_screen = q();
+
+ # output to screen, if appropriate
+ if($switches{screenlog}){
+ $appender_screen = Log::Log4perl::Appender->new(
+ "Log::Log4perl::Appender::Screen",
+ stderr => 1,
+ utf8 => 1,
+ );
+
+ $appender_screen->layout($layout);
+ $logger->add_appender($appender_screen);
+ }
+
+ # details of the script to log file
+ $logger->info("*$FindBin::Script version $versionNumber, $versionDate, a script to indent .tex files");
+ $logger->info("$FindBin::Script lives here: $FindBin::RealBin/");
+
+ my $time = localtime();
+ $logger->info($time);
+
+ if (${$self}{fileName} ne "-"){
+ $logger->info("Filename: ${$self}{fileName}");
+ } else {
+ $logger->info("Reading input from STDIN");
+ my $buttonText = ($FindBin::Script eq 'latexindent.exe') ? 'CTRL+Z followed by ENTER':'CTRL+D';
+ print STDERR "Please enter text to be indented: (press $buttonText when finished)\n";
+ }
+
+ # log the switches from the user
+ $logger->info("*Processing switches:");
+
+ # check on the trace mode switch (should be turned on if ttrace mode active)
+ $switches{trace} = $switches{ttrace} ? 1 : $switches{trace};
+
+ # output details of switches
+ $logger->info("-sl|--screenlog: log file will also be output to the screen") if($switches{screenlog});
+ $logger->info("-t|--trace: Trace mode active (you have used either -t or --trace)") if($switches{trace} and !$switches{ttrace});
+ $logger->info("-tt|--ttrace: TTrace mode active (you have used either -tt or --ttrace)") if($switches{ttrace});
+ $logger->info("-s|--silent: Silent mode active (you have used either -s or --silent)") if($switches{silentMode});
+ $logger->info("-d|--onlydefault: Only defaultSettings.yaml will be used (you have used either -d or --onlydefault)") if($switches{onlyDefault});
+ $logger->info("-w|--overwrite: Overwrite mode active, will make a back up of ${$self}{fileName} first") if($switches{overwrite});
+ $logger->info("-l|--localSettings: Read localSettings YAML file") if($switches{readLocalSettings});
+ $logger->info("-y|--yaml: YAML settings specified via command line") if($switches{yaml});
+ $logger->info("-o|--outputfile: output to file") if($switches{outputToFile});
+ $logger->info("-m|--modifylinebreaks: modify line breaks") if($switches{modifyLineBreaks});
+ $logger->info("-g|--logfile: logfile name") if($switches{logFileName});
+ $logger->info("-c|--cruft: cruft directory") if($switches{cruftDirectory});
+ $logger->info("-r|--replacement: replacement mode") if($switches{replacement});
+ $logger->info("-rr|--onlyreplacement: *only* replacement mode, no indentation") if($switches{onlyreplacement});
+
+ # check if overwrite and outputfile are active similtaneously
+ if($switches{overwrite} and $switches{outputToFile}){
+ $logger->info("Options check, -w and -o specified\nYou have called latexindent.pl with both -o and -w\noutput to file) will take priority, and -w (over write) will be ignored");
+ $switches{overwrite}=0;
+ }
+
+ $logger->info("*Directory for backup files and $logfileName: ${$self}{cruftDirectory}");
+
+ # output location of modules
+ if($FindBin::Script eq 'latexindent.pl' or ($FindBin::Script eq 'latexindent.exe' and $switches{trace} )) {
+ my @listOfModules = ('FindBin', 'YAML::Tiny', 'File::Copy', 'File::Basename', 'Getopt::Long','File::HomeDir','Unicode::GCString','Log::Log4perl');
+ $logger->info("*Perl modules are being loaded from the following directories:");
+ foreach my $moduleName (@listOfModules) {
+ (my $file = $moduleName) =~ s|::|/|g;
+ $logger->info($INC{$file .'.pm'});
+ }
+ $logger->info("*Latex Indent perl modules are being loaded from, for example:");
+ (my $file = 'LatexIndent::Document') =~ s|::|/|g;
+ $logger->info($INC{$file .'.pm'});
+ }
+
+ # read the YAML settings
+ $self->yaml_read_settings;
+
+ # the user may have specified their own settings for the rest of the log file,
+ # for example:
+ #
+ # logFilePreferences:
+ # PatternLayout:
+ # default: "%p: %m{indent}%n"
+ # trace: "%p: %m{indent}%n"
+ # ttrace: "%d %p: %F{1}:%L %M - %m{indent}%n"
+ #
+ # e.g, default mode:
+ # 2017/09/16 11:59:09 INFO: message
+ # or trace mode:
+ # 2017/09/16 11:59:09 INFO: message
+ # or in trace mode:
+ # 2017/09/16 12:23:53 INFO: LogFile.pm:156 LatexIndent::LogFile::processSwitches - message
+ my $pattern = q();
+ if($switches{ttrace}){
+ $pattern = ${${$masterSettings{logFilePreferences}}{PatternLayout}}{ttrace};
+ } elsif($switches{trace}){
+ $pattern = ${${$masterSettings{logFilePreferences}}{PatternLayout}}{trace};
+ } else {
+ $pattern = ${${$masterSettings{logFilePreferences}}{PatternLayout}}{default};
+ }
+ $layout = Log::Log4perl::Layout::PatternLayout->new($pattern);
+ $appender->layout($layout);
+
+ $appender_screen->layout($layout) if $switches{screenlog};
+ return;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/MandatoryArgument.pm b/support/latexindent/LatexIndent/MandatoryArgument.pm
new file mode 100644
index 0000000000..b5b3ac8de6
--- /dev/null
+++ b/support/latexindent/LatexIndent/MandatoryArgument.pm
@@ -0,0 +1,135 @@
+package LatexIndent::MandatoryArgument;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_m_switch_active /;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::IfElseFi qw/$ifElseFiBasicRegExp/;
+use LatexIndent::Special qw/$specialBeginBasicRegExp/;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_mandatory_arguments get_mand_arg_reg_exp/;
+our $mandatoryArgumentCounter;
+
+sub find_mandatory_arguments{
+ my $self = shift;
+
+ my $mandArgRegExp = $self->get_mand_arg_reg_exp;
+
+ # pick out the mandatory arguments
+ while(${$self}{body} =~ m/$mandArgRegExp\h*($trailingCommentRegExp)*(.*)/s){
+ # log file output
+ $logger->trace("*Mandatory argument found, body in ${$self}{name}") if $is_t_switch_active;
+ $logger->trace("(last argument)") if($9 eq '' and $is_t_switch_active);
+
+ ${$self}{body} =~ s/
+ $mandArgRegExp(\h*)($trailingCommentRegExp)*(.*)
+ /
+ # create a new Mandatory Argument object
+ my $mandatoryArg = LatexIndent::MandatoryArgument->new(begin=>$1,
+ name=>${$self}{name}.":mandatoryArgument",
+ nameForIndentationSettings=>${$self}{parent},
+ parent=>${$self}{parent},
+ body=>$3.($4?$4:q()),
+ end=>$5,
+ linebreaksAtEnd=>{
+ begin=>$2?1:0,
+ body=>$4?1:0,
+ end=>$7?1:0,
+ },
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"LCuBStartsOnOwnLine",
+ # body statements
+ BodyStartsOnOwnLine=>"MandArgBodyStartsOnOwnLine",
+ # end statements
+ EndStartsOnOwnLine=>"RCuBStartsOnOwnLine",
+ # after end statements
+ EndFinishesWithLineBreak=>"RCuBFinishesWithLineBreak",
+ },
+ horizontalTrailingSpace=>$6?$6:q(),
+ modifyLineBreaksYamlName=>"mandatoryArguments",
+ # the last argument (determined by $10 eq '') needs information from the argument container object
+ endImmediatelyFollowedByComment=>($10 eq '')?${$self}{endImmediatelyFollowedByComment}:($9?1:0),
+ );
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($mandatoryArg);
+ ${@{${$self}{children}}[-1]}{replacementText}.($8?$8:q()).($9?$9:q()).($10?$10:q());
+ /xseg;
+ $self->wrap_up_tasks;
+ }
+ }
+
+sub create_unique_id{
+ my $self = shift;
+
+ $mandatoryArgumentCounter++;
+ ${$self}{id} = "$tokens{mandatoryArguments}$mandatoryArgumentCounter";
+ return;
+}
+
+sub get_mand_arg_reg_exp{
+
+ my $mandArgRegExp = qr/
+ (?<!\\) # not immediately pre-ceeded by \
+ (
+ \{
+ \h*
+ (\R*) # linebreaks after { into $2
+ ) # { captured into $1
+ (
+ (?:
+ (?!
+ (?:(?<!\\)\{)
+ ).
+ )*? # not including {, but \{ ok
+ ) # body into $3
+ (\R*) # linebreaks after body into $4
+ (?<!\\) # not immediately pre-ceeded by \
+ (
+ \} # {mandatory arguments}
+ ) # } into $5
+ (\h*)
+ (\R)? # linebreaks after } into $6
+ /sx;
+
+ return $mandArgRegExp;
+}
+
+sub yaml_get_object_attribute_for_indentation_settings{
+ my $self = shift;
+
+ return ${$self}{modifyLineBreaksYamlName};
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # search for ifElseFi blocks
+ $self->find_ifelsefi if ${$self}{body} =~ m/$ifElseFiBasicRegExp/s;
+
+ # search for special begin/end
+ $self->find_special if ${$self}{body} =~ m/$specialBeginBasicRegExp/s;
+
+ # comma poly-switch check
+ $self->comma_else if $is_m_switch_active;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/ModifyLineBreaks.pm b/support/latexindent/LatexIndent/ModifyLineBreaks.pm
new file mode 100644
index 0000000000..0f33f88b83
--- /dev/null
+++ b/support/latexindent/LatexIndent/ModifyLineBreaks.pm
@@ -0,0 +1,394 @@
+package LatexIndent::ModifyLineBreaks;
+# 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 Data::Dumper;
+use Exporter qw/import/;
+use Text::Wrap;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_m_switch_active $is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::Item qw/$listOfItems/;
+use LatexIndent::LogFile qw/$logger/;
+our @EXPORT_OK = qw/modify_line_breaks_body modify_line_breaks_end adjust_line_breaks_end_parent remove_line_breaks_begin text_wrap remove_paragraph_line_breaks construct_paragraph_reg_exp text_wrap_remove_paragraph_line_breaks verbatim_modify_line_breaks/;
+our $paragraphRegExp = q();
+
+sub modify_line_breaks_body{
+ my $self = shift;
+ #
+ # Blank line poly-switch notes (==4)
+ #
+ # when BodyStartsOnOwnLine=4 we adopt the following approach:
+ # temporarily change BodyStartsOnOwnLine to -1, make adjustments
+ # temporarily change BodyStartsOnOwnLine to 3, make adjustments
+ # switch BodyStartsOnOwnLine back to 4
+
+ # add a line break after \begin{statement} if appropriate
+ my @polySwitchValues = (${$self}{BodyStartsOnOwnLine}==4)?(-1,3):(${$self}{BodyStartsOnOwnLine});
+ foreach(@polySwitchValues){
+ my $BodyStringLogFile = ${$self}{aliases}{BodyStartsOnOwnLine}||"BodyStartsOnOwnLine";
+ if($_>=1 and !${$self}{linebreaksAtEnd}{begin}){
+ # if the <begin> statement doesn't finish with a line break,
+ # then we have different actions based upon the value of BodyStartsOnOwnLine:
+ # BodyStartsOnOwnLine == 1 just add a new line
+ # BodyStartsOnOwnLine == 2 add a comment, and then new line
+ # BodyStartsOnOwnLine == 3 add a blank line, and then new line
+ if($_==1){
+ # modify the begin statement
+ $logger->trace("Adding a linebreak at the end of begin statement ${$self}{begin} (see $BodyStringLogFile)") if $is_t_switch_active;
+ ${$self}{begin} .= "\n";
+ ${$self}{linebreaksAtEnd}{begin} = 1;
+ $logger->trace("Removing leading space from body of ${$self}{name} (see $BodyStringLogFile)") if $is_t_switch_active;
+ ${$self}{body} =~ s/^\h*//;
+ } elsif($_==2){
+ # by default, assume that no trailing comment token is needed
+ my $trailingCommentToken = q();
+ if(${$self}{body} !~ m/^\h*$trailingCommentRegExp/s){
+ # modify the begin statement
+ $logger->trace("Adding a % at the end of begin ${$self}{begin} followed by a linebreak ($BodyStringLogFile == 2)") if $is_t_switch_active;
+ $trailingCommentToken = "%".$self->add_comment_symbol;
+ ${$self}{begin} =~ s/\h*$//;
+ ${$self}{begin} .= "$trailingCommentToken\n";
+ ${$self}{linebreaksAtEnd}{begin} = 1;
+ $logger->trace("Removing leading space from body of ${$self}{name} (see $BodyStringLogFile)") if $is_t_switch_active;
+ ${$self}{body} =~ s/^\h*//;
+ } else {
+ $logger->trace("Even though $BodyStringLogFile == 2, ${$self}{begin} already finishes with a %, so not adding another.") if $is_t_switch_active;
+ }
+ } elsif ($_==3){
+ my $trailingCharacterToken = q();
+ $logger->trace("Adding a blank line at the end of begin ${$self}{begin} followed by a linebreak ($BodyStringLogFile == 3)") if $is_t_switch_active;
+ ${$self}{begin} =~ s/\h*$//;
+ ${$self}{begin} .= (${$masterSettings{modifyLineBreaks}}{preserveBlankLines}?$tokens{blanklines}:"\n")."\n";
+ ${$self}{linebreaksAtEnd}{begin} = 1;
+ $logger->trace("Removing leading space from body of ${$self}{name} (see $BodyStringLogFile)") if $is_t_switch_active;
+ ${$self}{body} =~ s/^\h*//;
+ }
+ } elsif ($_==-1 and ${$self}{linebreaksAtEnd}{begin}){
+ # remove line break *after* begin, if appropriate
+ $self->remove_line_breaks_begin;
+ }
+ }
+}
+
+sub remove_line_breaks_begin{
+ my $self = shift;
+ my $BodyStringLogFile = ${$self}{aliases}{BodyStartsOnOwnLine}||"BodyStartsOnOwnLine";
+ $logger->trace("Removing linebreak at the end of begin (see $BodyStringLogFile)") if $is_t_switch_active;
+ ${$self}{begin} =~ s/\R*$//sx;
+ ${$self}{linebreaksAtEnd}{begin} = 0;
+}
+
+sub modify_line_breaks_end{
+ my $self = shift;
+
+ #
+ # Blank line poly-switch notes (==4)
+ #
+ # when EndStartsOnOwnLine=4 we adopt the following approach:
+ # temporarily change EndStartsOnOwnLine to -1, make adjustments
+ # temporarily change EndStartsOnOwnLine to 3, make adjustments
+ # switch EndStartsOnOwnLine back to 4
+ #
+
+ my @polySwitchValues =(defined ${$self}{EndStartsOnOwnLine} and ${$self}{EndStartsOnOwnLine}==4) ?(-1,3):(${$self}{EndStartsOnOwnLine});
+ foreach(@polySwitchValues){
+ # possibly modify line break *before* \end{statement}
+ if(defined ${$self}{EndStartsOnOwnLine}){
+ my $EndStringLogFile = ${$self}{aliases}{EndStartsOnOwnLine}||"EndStartsOnOwnLine";
+ if($_>=1 and !${$self}{linebreaksAtEnd}{body}){
+ # if the <body> statement doesn't finish with a line break,
+ # then we have different actions based upon the value of EndStartsOnOwnLine:
+ # EndStartsOnOwnLine == 1 just add a new line
+ # EndStartsOnOwnLine == 2 add a comment, and then new line
+ # EndStartsOnOwnLine == 3 add a blank line, and then new line
+ $logger->trace("Adding a linebreak at the end of body (see $EndStringLogFile)") if $is_t_switch_active;
+
+ # by default, assume that no trailing character token is needed
+ my $trailingCharacterToken = q();
+ if($_==2){
+ $logger->trace("Adding a % immediately after body of ${$self}{name} ($EndStringLogFile==2)") if $is_t_switch_active;
+ $trailingCharacterToken = "%".$self->add_comment_symbol;
+ ${$self}{body} =~ s/\h*$//s;
+ } elsif ($_==3) {
+ $logger->trace("Adding a blank line immediately after body of ${$self}{name} ($EndStringLogFile==3)") if $is_t_switch_active;
+ $trailingCharacterToken = "\n".(${$masterSettings{modifyLineBreaks}}{preserveBlankLines}?$tokens{blanklines}:q());
+ ${$self}{body} =~ s/\h*$//s;
+ }
+
+ # modified end statement
+ if(${$self}{body} =~ m/^\h*$/s and (defined ${$self}{BodyStartsOnOwnLine}) and ${$self}{BodyStartsOnOwnLine} >=1 ){
+ ${$self}{linebreaksAtEnd}{body} = 0;
+ } else {
+ ${$self}{body} .= "$trailingCharacterToken\n";
+ ${$self}{linebreaksAtEnd}{body} = 1;
+ }
+ } elsif ($_==-1 and ${$self}{linebreaksAtEnd}{body}){
+ # remove line break *after* body, if appropriate
+
+ # check to see that body does *not* finish with blank-line-token,
+ # if so, then don't remove that final line break
+ if(${$self}{body} !~ m/$tokens{blanklines}$/s){
+ $logger->trace("Removing linebreak at the end of body (see $EndStringLogFile)") if $is_t_switch_active;
+ ${$self}{body} =~ s/\R*$//sx;
+ ${$self}{linebreaksAtEnd}{body} = 0;
+ } else {
+ $logger->trace("Blank line token found at end of body (${$self}{name}), see preserveBlankLines, not removing line break before ${$self}{end}") if $is_t_switch_active;
+ }
+ }
+ }
+ }
+
+ #
+ # Blank line poly-switch notes (==4)
+ #
+ # when EndFinishesWithLineBreak=4 we adopt the following approach:
+ # temporarily change EndFinishesWithLineBreak to -1, make adjustments
+ # temporarily change EndFinishesWithLineBreak to 3, make adjustments
+ # switch EndFinishesWithLineBreak back to 4
+ #
+ @polySwitchValues =(defined ${$self}{EndFinishesWithLineBreak} and ${$self}{EndFinishesWithLineBreak}==4) ?(-1,3):(${$self}{EndFinishesWithLineBreak});
+ foreach(@polySwitchValues){
+ last if !(defined $_);
+ ${$self}{linebreaksAtEnd}{end} = 0 if($_==3 and (defined ${$self}{EndFinishesWithLineBreak} and ${$self}{EndFinishesWithLineBreak}==4));
+
+ # possibly modify line break *after* \end{statement}
+ if(defined $_ and $_>=1
+ and !${$self}{linebreaksAtEnd}{end}){
+ # if the <end> statement doesn't finish with a line break,
+ # then we have different actions based upon the value of EndFinishesWithLineBreak:
+ # EndFinishesWithLineBreak == 1 just add a new line
+ # EndFinishesWithLineBreak == 2 add a comment, and then new line
+ # EndFinishesWithLineBreak == 3 add a blank line, and then new line
+ my $EndStringLogFile = ${$self}{aliases}{EndFinishesWithLineBreak}||"EndFinishesWithLineBreak";
+ if($_==1){
+ $logger->trace("Adding a linebreak at the end of ${$self}{end} ($EndStringLogFile==1)") if $is_t_switch_active;
+ ${$self}{linebreaksAtEnd}{end} = 1;
+
+ # modified end statement
+ ${$self}{replacementText} .= "\n";
+ } elsif($_==2){
+ if(${$self}{endImmediatelyFollowedByComment}){
+ # no need to add a % if one already exists
+ $logger->trace("Even though $EndStringLogFile == 2, ${$self}{end} is immediately followed by a %, so not adding another; not adding line break.") if $is_t_switch_active;
+ } else {
+ # otherwise, create a trailing comment, and tack it on
+ $logger->trace("Adding a % immediately after, ${$self}{end} ($EndStringLogFile==2)") if $is_t_switch_active;
+ my $trailingCommentToken = "%".$self->add_comment_symbol;
+ ${$self}{end} =~ s/\h*$//s;
+ ${$self}{replacementText} .= "$trailingCommentToken\n";
+ ${$self}{linebreaksAtEnd}{end} = 1;
+ }
+ } elsif($_==3){
+ $logger->trace("Adding a blank line at the end of ${$self}{end} ($EndStringLogFile==3)") if $is_t_switch_active;
+ ${$self}{linebreaksAtEnd}{end} = 1;
+
+ # modified end statement
+ ${$self}{replacementText} .= (${$masterSettings{modifyLineBreaks}}{preserveBlankLines}?$tokens{blanklines}:"\n")."\n";
+ }
+ }
+ }
+
+}
+
+sub adjust_line_breaks_end_parent{
+ # when a parent object contains a child object, the line break
+ # at the end of the parent object can become messy
+
+ my $self = shift;
+
+ # most recent child object
+ my $child = @{${$self}{children}}[-1];
+
+ # adjust parent linebreaks information
+ if(${$child}{linebreaksAtEnd}{end} and ${$self}{body} =~ m/${$child}{replacementText}\h*\R*$/s and !${$self}{linebreaksAtEnd}{body}){
+ $logger->trace("ID: ${$child}{id}") if($is_t_switch_active);
+ $logger->trace("${$child}{begin}...${$child}{end} is found at the END of body of parent, ${$self}{name}, avoiding a double line break:") if($is_t_switch_active);
+ $logger->trace("adjusting ${$self}{name} linebreaksAtEnd{body} to be 1") if($is_t_switch_active);
+ ${$self}{linebreaksAtEnd}{body}=1;
+ }
+
+ # the modify line switch can adjust line breaks, so we need another check,
+ # see for example, test-cases/environments/environments-remove-line-breaks-trailing-comments.tex
+ if(defined ${$child}{linebreaksAtEnd}{body}
+ and !${$child}{linebreaksAtEnd}{body}
+ and ${$child}{body} =~ m/\R(?:$trailingCommentRegExp\h*)?$/s ){
+ # log file information
+ $logger->trace("Undisclosed line break at the end of body of ${$child}{name}: '${$child}{end}'") if($is_t_switch_active);
+ $logger->trace("Adding a linebreak at the end of body for ${$child}{id}") if($is_t_switch_active);
+
+ # make the adjustments
+ ${$child}{body} .= "\n";
+ ${$child}{linebreaksAtEnd}{body}=1;
+ }
+
+}
+
+sub verbatim_modify_line_breaks{
+ # verbatim modify line breaks are a bit special, as they happen before
+ # any of the main processes have been done
+ my $self = shift;
+ while ( my ($key,$child)= each %{${$self}{verbatim}}){
+ if(defined ${$child}{BeginStartsOnOwnLine}){
+ my $BeginStringLogFile = ${$child}{aliases}{BeginStartsOnOwnLine};
+ $logger->trace("*$BeginStringLogFile is ${$child}{BeginStartsOnOwnLine} for ${$child}{name}") if $is_t_switch_active ;
+ if (${$child}{BeginStartsOnOwnLine}==-1){
+ # VerbatimStartsOnOwnLine = -1
+ if(${$self}{body}=~m/^\h*${$child}{id}/m){
+ $logger->trace("${$child}{name} begins on its own line, removing leading line break") if $is_t_switch_active ;
+ ${$self}{body} =~ s/(\R|\h)*${$child}{id}/${$child}{id}/s;
+ }
+ } elsif (${$child}{BeginStartsOnOwnLine}>=1 and ${$self}{body}!~m/^\h*${$child}{id}/m){
+ # VerbatimStartsOnOwnLine = 1, 2 or 3
+ my $trailingCharacterToken = q();
+ if(${$child}{BeginStartsOnOwnLine}==1){
+ $logger->trace("Adding a linebreak at the beginning of ${$child}{begin} (see $BeginStringLogFile)") if $is_t_switch_active;
+ } elsif (${$child}{BeginStartsOnOwnLine}==2){
+ $logger->trace("Adding a % at the end of the line that ${$child}{begin} is on, then a linebreak ($BeginStringLogFile == 2)") if $is_t_switch_active;
+ $trailingCharacterToken = "%".$self->add_comment_symbol;
+ } elsif (${$child}{BeginStartsOnOwnLine}==3){
+ $logger->trace("Adding a blank line at the end of the line that ${$child}{begin} is on, then a linebreak ($BeginStringLogFile == 3)") if $is_t_switch_active;
+ $trailingCharacterToken = "\n";
+ }
+ ${$self}{body} =~ s/\h*${$child}{id}/$trailingCharacterToken\n${$child}{id}/s;
+ }
+ }
+ }
+}
+sub text_wrap_remove_paragraph_line_breaks{
+ my $self = shift;
+
+ if(${$masterSettings{modifyLineBreaks}{removeParagraphLineBreaks}}{beforeTextWrap}){
+ $self->remove_paragraph_line_breaks if ${$self}{removeParagraphLineBreaks};
+ $self->text_wrap if (${$self}{textWrapOptions} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis});
+ } else {
+ $self->text_wrap if (${$self}{textWrapOptions} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis});
+ }
+
+}
+
+sub text_wrap{
+
+ my $self = shift;
+
+ # alignment at ampersand can take priority
+ return if(${$self}{lookForAlignDelims} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{alignAtAmpersandTakesPriority});
+
+ # call the text wrapping routine
+ my $columns;
+
+ # columns might have been defined by the user
+ if(defined ${$self}{columns}){
+ $columns = ${$self}{columns};
+ } elsif(ref ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns} eq "HASH"){
+ if(defined ${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{default}){
+ $columns = ${${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}}{default};
+ } else {
+ $columns = 80;
+ }
+ } elsif (defined ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}){
+ $columns = ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns} ;
+ } else {
+ $columns = 80;
+ }
+
+ $Text::Wrap::columns=$columns;
+ if(${$masterSettings{modifyLineBreaks}{textWrapOptions}}{separator} ne ''){
+ $Text::Wrap::separator=${$masterSettings{modifyLineBreaks}{textWrapOptions}}{separator};
+ }
+ ${$self}{body} = wrap('','',${$self}{body});
+}
+
+sub construct_paragraph_reg_exp{
+ my $self = shift;
+
+ $logger->trace("*Constructing the paragraph-stop regexp (see paragraphsStopAt)") if $is_t_switch_active ;
+ my $stopAtRegExp = q();
+ while( my ($paragraphStopAt,$yesNo)= each %{${$masterSettings{modifyLineBreaks}{removeParagraphLineBreaks}}{paragraphsStopAt}}){
+ if($yesNo){
+ # the headings (chapter, section, etc) need a slightly special treatment
+ $paragraphStopAt = "afterHeading" if($paragraphStopAt eq "heading");
+
+ # the comment need a slightly special treatment
+ $paragraphStopAt = "trailingComment" if($paragraphStopAt eq "comments");
+
+ # output to log file
+ $logger->trace("The paragraph-stop regexp WILL include $tokens{$paragraphStopAt} (see paragraphsStopAt)") if $is_t_switch_active ;
+
+ # update the regexp
+ if($paragraphStopAt eq "items"){
+ $stopAtRegExp .= "|(?:\\\\(?:".$listOfItems."))";
+ } else {
+ $stopAtRegExp .= "|(?:".($paragraphStopAt eq "trailingComment" ? "%" : q() ).$tokens{$paragraphStopAt}."\\d+)";
+ }
+ } else {
+ $logger->trace("The paragraph-stop regexp won't include $tokens{$paragraphStopAt} (see paragraphsStopAt)") if ($tokens{$paragraphStopAt} and $is_t_switch_active);
+ }
+ }
+
+ $paragraphRegExp = qr/
+ ^
+ (?!$tokens{beginOfToken})
+ (\w
+ (?:
+ (?!
+ (?:$tokens{blanklines}|\\par)
+ ).
+ )*?
+ )
+ (
+ (?:
+ ^(?:(\h*\R)|\\par|$tokens{blanklines}$stopAtRegExp)
+ )
+ |
+ \z # end of string
+ )/sxm;
+
+ $logger->trace("The paragraph-stop-regexp is:") if $is_tt_switch_active ;
+ $logger->trace($paragraphRegExp) if $is_tt_switch_active ;
+}
+
+sub remove_paragraph_line_breaks{
+ my $self = shift;
+ return unless ${$self}{removeParagraphLineBreaks};
+
+ # alignment at ampersand can take priority
+ return if(${$self}{lookForAlignDelims} and ${$masterSettings{modifyLineBreaks}{removeParagraphLineBreaks}}{alignAtAmpersandTakesPriority});
+
+ $logger->trace("Checking ${$self}{name} for paragraphs (see removeParagraphLineBreaks)") if $is_t_switch_active;
+
+ my $paragraphCounter;
+ my @paragraphStorage;
+
+ ${$self}{body} =~ s/$paragraphRegExp/
+ $paragraphCounter++;
+ push(@paragraphStorage,{id=>$tokens{paragraph}.$paragraphCounter.$tokens{endOfToken},value=>$1});
+
+ # replace comment with dummy text
+ $tokens{paragraph}.$paragraphCounter.$tokens{endOfToken}.$2;
+ /xsmeg;
+
+ while( my $paragraph = pop @paragraphStorage){
+ # remove all line breaks from paragraph, except for any at the very end
+ ${$paragraph}{value} =~ s/\R(?!\z)/ /sg;
+ ${$self}{body} =~ s/${$paragraph}{id}/${$paragraph}{value}/;
+ }
+}
+
+
+1;
diff --git a/support/latexindent/LatexIndent/NamedGroupingBracesBrackets.pm b/support/latexindent/LatexIndent/NamedGroupingBracesBrackets.pm
new file mode 100644
index 0000000000..f20e23ca54
--- /dev/null
+++ b/support/latexindent/LatexIndent/NamedGroupingBracesBrackets.pm
@@ -0,0 +1,77 @@
+package LatexIndent::NamedGroupingBracesBrackets;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Command"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/construct_grouping_braces_brackets_regexp $grouping_braces_regexp $grouping_braces_regexpTrailingComment/;
+our $groupingBracesCounter;
+our $grouping_braces_regexp;
+our $grouping_braces_regexpTrailingComment;
+
+sub construct_grouping_braces_brackets_regexp{
+ my $self = shift;
+
+ # grab the arguments regexp
+ my $optAndMandRegExp = $self->get_arguments_regexp;
+
+ # read from fine tuning
+ my $NamedGroupingBracesBracketsRegExp = qr/${${$masterSettings{fineTuning}}{NamedGroupingBracesBrackets}}{name}/;
+ my $NamedGroupingFollowRegExp = qr/${${$masterSettings{fineTuning}}{NamedGroupingBracesBrackets}}{follow}/;
+
+ # store the regular expresssion for matching and replacing
+ $grouping_braces_regexp = qr/
+ (
+ $NamedGroupingFollowRegExp
+ )
+ (
+ $NamedGroupingBracesBracketsRegExp # lowercase|uppercase letters, @, *, numbers, forward slash, dots
+ ) # $2 name
+ (\h*) # $3 h-space
+ (\R*) # $4 linebreaks
+ ($optAndMandRegExp) # $5 mand|opt arguments (at least one)
+ (\R)? # $8 linebreak
+ /sx;
+
+ # something {value} grouping braces with trailing comment
+ $grouping_braces_regexpTrailingComment = qr/$grouping_braces_regexp\h*((?:$trailingCommentRegExp\h*)*)?/;
+
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $groupingBracesCounter++;
+ ${$self}{id} = "$tokens{namedGroupingBracesBrackets}$groupingBracesCounter";
+ return;
+}
+
+sub get_replacement_text{
+ my $self = shift;
+
+ # the replacement text for a key = {value} needes to accomodate the leading [ OR { OR % OR , OR any combination thereof
+ $logger->trace("Custom replacement text routine for ${$self}{name}") if $is_t_switch_active;
+ ${$self}{replacementText} = ${$self}{beginningbit}.${$self}{id};
+ delete ${$self}{beginningbit};
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/OptionalArgument.pm b/support/latexindent/LatexIndent/OptionalArgument.pm
new file mode 100644
index 0000000000..fdaa549a7a
--- /dev/null
+++ b/support/latexindent/LatexIndent/OptionalArgument.pm
@@ -0,0 +1,120 @@
+package LatexIndent::OptionalArgument;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_m_switch_active /;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::IfElseFi qw/$ifElseFiBasicRegExp/;
+use LatexIndent::Special qw/$specialBeginBasicRegExp/;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_optional_arguments/;
+our $optionalArgumentCounter;
+our $optArgRegExp = qr/
+ (?<!\\) # not immediately pre-ceeded by \
+ (
+ \[
+ \h*
+ (\R*)
+ )
+ (.*?)
+ (\R*)
+ (?<!\\) # not immediately pre-ceeded by \
+ (
+ \] # [optional arguments]
+ )
+ (\h*)
+ (\R)?
+ /sx;
+
+sub find_optional_arguments{
+ my $self = shift;
+
+ # pick out the optional arguments
+ while(${$self}{body} =~ m/$optArgRegExp\h*($trailingCommentRegExp)*(.*)/s){
+ # log file output
+ $logger->trace("*Optional argument found, body in ${$self}{name}") if $is_t_switch_active;
+ $logger->trace("(last argument)") if($9 eq '' and $is_t_switch_active);
+
+ ${$self}{body} =~ s/
+ $optArgRegExp(\h*)($trailingCommentRegExp)*(.*)
+ /
+ # create a new Optional Argument object
+ my $optionalArg = LatexIndent::OptionalArgument->new(begin=>$1,
+ name=>${$self}{name}.":optionalArgument",
+ nameForIndentationSettings=>${$self}{parent},
+ parent=>${$self}{parent},
+ body=>$3.($4?$4:q()),
+ end=>$5,
+ linebreaksAtEnd=>{
+ begin=>$2?1:0,
+ body=>$4?1:0,
+ end=>$7?1:0,
+ },
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"LSqBStartsOnOwnLine",
+ # body statements
+ BodyStartsOnOwnLine=>"OptArgBodyStartsOnOwnLine",
+ # end statements
+ EndStartsOnOwnLine=>"RSqBStartsOnOwnLine",
+ # after end statements
+ EndFinishesWithLineBreak=>"RSqBFinishesWithLineBreak",
+ },
+ modifyLineBreaksYamlName=>"optionalArguments",
+ # the last argument (determined by $10 eq '') needs information from the argument container object
+ endImmediatelyFollowedByComment=>($10 eq '')?${$self}{endImmediatelyFollowedByComment}:($9?1:0),
+ horizontalTrailingSpace=>$6?$6:q(),
+ );
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($optionalArg);
+ ${@{${$self}{children}}[-1]}{replacementText}.($8?$8:q()).($9?$9:q()).($10?$10:q());
+ /xseg;
+ }
+ }
+
+sub yaml_get_object_attribute_for_indentation_settings{
+ my $self = shift;
+
+ return ${$self}{modifyLineBreaksYamlName};
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $optionalArgumentCounter++;
+ ${$self}{id} = "$tokens{optionalArguments}$optionalArgumentCounter";
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # search for ifElseFi blocks
+ $self->find_ifelsefi if ${$self}{body} =~ m/$ifElseFiBasicRegExp/s;
+
+ # search for special begin/end
+ $self->find_special if ${$self}{body} =~ m/$specialBeginBasicRegExp/s;
+
+ # comma poly-switch check
+ $self->comma_else if $is_m_switch_active;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Preamble.pm b/support/latexindent/LatexIndent/Preamble.pm
new file mode 100644
index 0000000000..a31efd1a49
--- /dev/null
+++ b/support/latexindent/LatexIndent/Preamble.pm
@@ -0,0 +1,90 @@
+package LatexIndent::Preamble;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_m_switch_active/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::Environment qw/$environmentBasicRegExp/;
+use LatexIndent::IfElseFi qw/$ifElseFiBasicRegExp/;
+use LatexIndent::Special qw/$specialBeginBasicRegExp/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our $preambleCounter;
+
+sub create_unique_id{
+ my $self = shift;
+
+ $preambleCounter++;
+ ${$self}{id} = "$tokens{preamble}$preambleCounter$tokens{endOfToken}";
+ return;
+}
+
+sub get_replacement_text{
+ my $self = shift;
+
+ # the replacement text for preamble needs to put the \\begin{document} back in
+ $logger->trace("Custom replacement text routine for preamble ${$self}{name}") if $is_t_switch_active;
+ ${$self}{replacementText} = ${$self}{id}.${$self}{afterbit};
+ delete ${$self}{afterbit};
+}
+
+sub indent{
+ # preamble doesn't receive any additional indentation
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # search for environments
+ $self->find_environments if ${$self}{body} =~ m/$environmentBasicRegExp/;
+
+ # search for ifElseFi blocks
+ $self->find_ifelsefi if ${$self}{body} =~ m/$ifElseFiBasicRegExp/s;
+
+ if(${$masterSettings{specialBeginEnd}}{specialBeforeCommand}){
+ # search for special begin/end
+ $self->find_special if ${$self}{body} =~ m/$specialBeginBasicRegExp/s;
+
+ # search for commands with arguments
+ $self->find_commands_or_key_equals_values_braces if(!$masterSettings{preambleCommandsBeforeEnvironments});
+ } else {
+ # search for commands with arguments
+ $self->find_commands_or_key_equals_values_braces if(!$masterSettings{preambleCommandsBeforeEnvironments});
+
+ # search for special begin/end
+ $self->find_special if ${$self}{body} =~ m/$specialBeginBasicRegExp/s;
+ }
+
+ # text wrapping, remove paragraph line breaks
+ if ($is_m_switch_active){
+ $self->yaml_get_textwrap_removeparagraphline_breaks;
+
+ # call the remove_paragraph_line_breaks and text_wrap routines
+ if(${$masterSettings{modifyLineBreaks}{removeParagraphLineBreaks}}{beforeTextWrap}){
+ $self->remove_paragraph_line_breaks if ${$self}{removeParagraphLineBreaks};
+ $self->text_wrap if (${$self}{textWrapOptions} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis});
+ } else {
+ $self->text_wrap if (${$self}{textWrapOptions} and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{perCodeBlockBasis});
+ $self->remove_paragraph_line_breaks if ${$self}{removeParagraphLineBreaks};
+ }
+ }
+
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Replacement.pm b/support/latexindent/LatexIndent/Replacement.pm
new file mode 100644
index 0000000000..1bc51caed2
--- /dev/null
+++ b/support/latexindent/LatexIndent/Replacement.pm
@@ -0,0 +1,89 @@
+package LatexIndent::Replacement;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_rr_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/make_replacements/;
+
+sub make_replacements{
+ my $self = shift;
+ my %input = @_;
+ if ($is_t_switch_active and !$is_rr_switch_active){
+ $logger->trace("*Replacement mode *$input{when}* indentation: -r") ;
+ } elsif ($is_t_switch_active and $is_rr_switch_active) {
+ $logger->trace("*Replacement mode, -rr switch is active") if $is_t_switch_active ;
+ }
+
+ my @replacements = @{$masterSettings{replacements}};
+
+ foreach ( @replacements ){
+ next if !(${$_}{this} or ${$_}{substitution});
+
+ # default value of "lookForThis" is 1
+ ${$_}{lookForThis} = 1 if( !(defined ${$_}{lookForThis}));
+
+ # move on if this one shouldn't be looked for
+ next if(!${$_}{lookForThis});
+
+ # default value of "when" is before
+ ${$_}{when} = "before" if( !(defined ${$_}{when}) or $is_rr_switch_active);
+
+ # update to the logging file
+ if($is_t_switch_active and (${$_}{when} eq $input{when})){
+ $logger->trace("-");
+ $logger->trace("this: ${$_}{this}") if(${$_}{this});
+ $logger->trace("that: ${$_}{that}") if(${$_}{that});
+ $logger->trace("substitution: ${$_}{substitution}") if(${$_}{substitution});
+ $logger->trace("when: ${$_}{when}");
+ }
+
+ # perform the substitutions
+ if(${$_}{when} eq $input{when}){
+ $logger->warn("*You have specified both 'this' and 'substitution'; the 'substitution' field will be ignored") if(${$_}{this} and ${$_}{substitution});
+ if(${$_}{this}){
+ # *string* replacement
+ # *string* replacement
+ # *string* replacement
+ my $this = qq{${$_}{this}};
+ my $that = (defined ${$_}{that}) ? qq{${$_}{that}} : q();
+ my $index_match = index(${$self}{body}, $this);
+ while ( $index_match != -1 ) {
+ substr (${$self}{body}, $index_match, length($this), $that );
+ $index_match = index(${$self}{body}, $this);
+ }
+ } else {
+ # *regex* replacement
+ # *regex* replacement
+ # *regex* replacement
+
+ # https://stackoverflow.com/questions/12423337/how-to-pass-a-replacing-regex-as-a-command-line-argument-to-a-perl-script
+ my $body = ${$self}{body};
+ eval("\$body =~ ${$_}{substitution}");
+ ${$self}{body} = $body ;
+ }
+ }
+ }
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/RoundBrackets.pm b/support/latexindent/LatexIndent/RoundBrackets.pm
new file mode 100644
index 0000000000..fff5efedd0
--- /dev/null
+++ b/support/latexindent/LatexIndent/RoundBrackets.pm
@@ -0,0 +1,100 @@
+package LatexIndent::RoundBrackets;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_round_brackets/;
+our $roundBracketCounter;
+our $roundBracketRegExp = qr/
+ (?<!\\)
+ (
+ \(
+ \h*
+ (\R*)
+ )
+ (.*?)
+ (\R*)
+ (?<!\\) # not immediately pre-ceeded by \
+ (
+ \) # [optional arguments]
+ )
+ (\h*)
+ (\R)?
+ /sx;
+
+sub indent{
+ return;
+}
+
+sub find_round_brackets{
+ my $self = shift;
+
+ # pick out the optional arguments
+ while(${$self}{body} =~ m/$roundBracketRegExp\h*($trailingCommentRegExp)*(.*)/s){
+ # log file output
+
+ ${$self}{body} =~ s/
+ $roundBracketRegExp(\h*)($trailingCommentRegExp)*(.*)
+ /
+ # create a new Optional Argument object
+ my $roundBracket = LatexIndent::RoundBrackets->new(begin=>$1,
+ name=>${$self}{name}.":roundBracket",
+ nameForIndentationSettings=>${$self}{parent},
+ parent=>${$self}{parent},
+ body=>$3.($4?$4:q()),
+ end=>$5,
+ linebreaksAtEnd=>{
+ begin=>$2?1:0,
+ body=>$4?1:0,
+ end=>$7?1:0,
+ },
+ modifyLineBreaksYamlName=>"roundBracket",
+ # the last argument (determined by $10 eq '') needs information from the argument container object
+ endImmediatelyFollowedByComment=>($10 eq '')?${$self}{endImmediatelyFollowedByComment}:($9?1:0),
+ horizontalTrailingSpace=>$6?$6:q(),
+ );
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($roundBracket);
+ ${@{${$self}{children}}[-1]}{replacementText}.($8?$8:q()).($9?$9:q()).($10?$10:q());
+ /xseg;
+ }
+ }
+
+sub yaml_get_object_attribute_for_indentation_settings{
+ my $self = shift;
+
+ return ${$self}{modifyLineBreaksYamlName};
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $roundBracketCounter++;
+ ${$self}{id} = "$tokens{roundBracket}$roundBracketCounter";
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ return;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Sentence.pm b/support/latexindent/LatexIndent/Sentence.pm
new file mode 100644
index 0000000000..cc11997e36
--- /dev/null
+++ b/support/latexindent/LatexIndent/Sentence.pm
@@ -0,0 +1,362 @@
+package LatexIndent::Sentence;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_m_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::Environment qw/$environmentBasicRegExp/;
+use LatexIndent::IfElseFi qw/$ifElseFiBasicRegExp/;
+use LatexIndent::Heading qw/$allHeadingsRegexp/;
+use LatexIndent::Special qw/$specialBeginAndBracesBracketsBasicRegExp/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/one_sentence_per_line/;
+our $sentenceCounter;
+
+sub one_sentence_per_line{
+ my $self = shift;
+
+ $logger->trace("*One sentence per line regular expression construction: (see oneSentencePerLine: manipulateSentences)") if $is_t_switch_active;
+
+ # sentences FOLLOW
+ # sentences FOLLOW
+ # sentences FOLLOW
+ my $sentencesFollow = q();
+
+ while( my ($sentencesFollowEachPart,$yesNo)= each %{${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesFollow}}){
+ if($yesNo){
+ if($sentencesFollowEachPart eq "par"){
+ $sentencesFollowEachPart = qr/\R?\\par/s;
+ } elsif ($sentencesFollowEachPart eq "blankLine"){
+ $sentencesFollowEachPart = qr/
+ (?:\A(?:$tokens{blanklines}\R)+) # the order of each of these
+ | # is important, as (like always) the first
+ (?:\G(?:$tokens{blanklines}\R)+) # thing to be matched will
+ | # be accepted
+ (?:(?:$tokens{blanklines}\h*\R)+)
+ |
+ \R{2,}
+ |
+ \G
+ /sx;
+ } elsif ($sentencesFollowEachPart eq "fullStop"){
+ $sentencesFollowEachPart = qr/\./s;
+ } elsif ($sentencesFollowEachPart eq "exclamationMark"){
+ $sentencesFollowEachPart = qr/\!/s;
+ } elsif ($sentencesFollowEachPart eq "questionMark"){
+ $sentencesFollowEachPart = qr/\?/s;
+ } elsif ($sentencesFollowEachPart eq "rightBrace"){
+ $sentencesFollowEachPart = qr/\}/s;
+ } elsif ($sentencesFollowEachPart eq "commentOnPreviousLine"){
+ $sentencesFollowEachPart = qr/$trailingCommentRegExp\h*\R/s;
+ } elsif ($sentencesFollowEachPart eq "other"){
+ $sentencesFollowEachPart = qr/$yesNo/;
+ }
+ $sentencesFollow .= ($sentencesFollow eq '' ? q() : "|").qr/$sentencesFollowEachPart/sx;
+ }
+ }
+ # if blankLine is not active from sentencesFollow then we need to set up the
+ # beginning of the string, but make sure that it is *not* followed by a
+ # blank line token, or a blank line
+ if(!${${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesFollow}}{blankLine}){
+ $sentencesFollow .= ($sentencesFollow eq '' ? q() : "|").
+ qr/
+ \G
+ (?!$tokens{blanklines})
+ /sx;
+ }
+
+ if(${${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesFollow}}{blankLine}){
+ $sentencesFollow = ($sentencesFollow eq '' ? q() : qr/(?:$sentencesFollow)(?:\h|\R)*/sx );
+ } else {
+ $sentencesFollow = ($sentencesFollow eq '' ? q() : qr/(?:$sentencesFollow)(?:\h*\R?)/sx );
+ }
+
+
+ $logger->trace("Sentences follow regexp:") if $is_tt_switch_active;
+ $logger->trace($sentencesFollow) if $is_tt_switch_active;
+
+ # sentences BEGIN with
+ # sentences BEGIN with
+ # sentences BEGIN with
+ my $sentencesBeginWith = q();
+
+ while( my ($sentencesBeginWithEachPart,$yesNo)= each %{${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesBeginWith}}){
+ if($yesNo){
+ if($sentencesBeginWithEachPart eq "A-Z"){
+ $logger->trace("sentence BEGINS with capital letters (see oneSentencePerLine:sentencesBeginWith:A-Z)") if $is_t_switch_active;
+ $sentencesBeginWithEachPart = qr/(?!(?:$tokens{blanklines}|$tokens{verbatim}|$tokens{preamble}))[A-Z]/;
+ } elsif ($sentencesBeginWithEachPart eq "a-z"){
+ $logger->trace("sentence BEGINS with lower-case letters (see oneSentencePerLine:sentencesBeginWith:a-z)") if $is_t_switch_active;
+ $sentencesBeginWithEachPart = qr/[a-z]/;
+ } elsif ($sentencesBeginWithEachPart eq "other"){
+ $logger->trace("sentence BEGINS with other $yesNo (reg exp) (see oneSentencePerLine:sentencesBeginWith:other)") if $is_t_switch_active;
+ $sentencesBeginWithEachPart = qr/$yesNo/;
+ }
+ $sentencesBeginWith .= ($sentencesBeginWith eq "" ? q(): "|" ).$sentencesBeginWithEachPart;
+ }
+ }
+ $sentencesBeginWith = qr/$sentencesBeginWith/;
+
+ # sentences END with
+ # sentences END with
+ # sentences END with
+ ${${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesEndWith}}{basicFullStop} = 0 if ${${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesEndWith}}{betterFullStop};
+ my $sentencesEndWith = q();
+
+ while( my ($sentencesEndWithEachPart,$yesNo)= each %{${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesEndWith}}){
+ if($yesNo){
+ if($sentencesEndWithEachPart eq "basicFullStop"){
+ $logger->trace("sentence ENDS with full stop (see oneSentencePerLine:sentencesEndWith:basicFullStop") if $is_t_switch_active;
+ $sentencesEndWithEachPart = qr/\./;
+ } elsif($sentencesEndWithEachPart eq "betterFullStop"){
+ $logger->trace("sentence ENDS with *better* full stop (see oneSentencePerLine:sentencesEndWith:betterFullStop") if $is_t_switch_active;
+ $sentencesEndWithEachPart = qr/${${$masterSettings{fineTuning}}{modifyLineBreaks}}{betterFullStop}/;
+ } elsif ($sentencesEndWithEachPart eq "exclamationMark"){
+ $logger->trace("sentence ENDS with exclamation mark (see oneSentencePerLine:sentencesEndWith:exclamationMark)") if $is_t_switch_active;
+ $sentencesEndWithEachPart = qr/!/;
+ } elsif ($sentencesEndWithEachPart eq "questionMark"){
+ $logger->trace("sentence ENDS with question mark (see oneSentencePerLine:sentencesEndWith:questionMark)") if $is_t_switch_active;
+ $sentencesEndWithEachPart = qr/\?/;
+ } elsif ($sentencesEndWithEachPart eq "other"){
+ $logger->trace("sentence ENDS with other $yesNo (reg exp) (see oneSentencePerLine:sentencesEndWith:other)") if $is_t_switch_active;
+ $sentencesEndWithEachPart = qr/$yesNo/;
+ }
+ $sentencesEndWith .= ($sentencesEndWith eq "" ? q(): "|" ).$sentencesEndWithEachPart;
+ }
+ }
+ $sentencesEndWith = qr/$sentencesEndWith/;
+
+ # the OVERALL sentence regexp
+ # the OVERALL sentence regexp
+ # the OVERALL sentence regexp
+ $logger->trace("Overall sentences end with regexp:") if $is_tt_switch_active;
+ $logger->trace($sentencesEndWith) if $is_tt_switch_active;
+
+ $logger->trace("Finding sentences...") if $is_t_switch_active;
+
+ my $notWithinSentence = qr/$trailingCommentRegExp/s;
+
+ # if
+ #
+ # modifyLineBreaks
+ # oneSentencePerLine
+ # sentencesFollow
+ # blankLine
+ #
+ # is set to 0 then we need to *exclude* the $tokens{blanklines} from the sentence routine,
+ # otherwise we could begin a sentence with $tokens{blanklines}.
+ if(!${${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesFollow}}{blankLine}){
+ $notWithinSentence .= "|".qr/(?:\h*\R?$tokens{blanklines})/s;
+ }
+
+ # similarly for \par
+ if(${${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentencesFollow}}{par}){
+ $notWithinSentence .= "|".qr/(?:\R?\\par)/s;
+ }
+
+ # initiate the sentence counter
+ my @sentenceStorage;
+
+ # make the sentence manipulation
+ ${$self}{body} =~ s/((?:$sentencesFollow))
+ (\h*)
+ (?!$notWithinSentence)
+ ((?:$sentencesBeginWith).*?)
+ ($sentencesEndWith)
+ (\h*)? # possibly followed by horizontal space
+ (\R)? # possibly followed by a line break
+ ($trailingCommentRegExp)? # possibly followed by trailing comments
+ /
+ my $beginning = $1;
+ my $h_space = ($2?$2:q());
+ my $middle = $3;
+ my $end = $4;
+ my $trailing = ($5?$5:q()).($6?$6:q()).($7?$7:q());
+ my $lineBreaksAtEnd = ($6? 1 : ($7?1:0) );
+ my $trailingComments = q();
+ # remove trailing comments from within the body of the sentence
+ if (${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{removeSentenceLineBreaks}){
+ while($middle =~ m|$trailingCommentRegExp|){
+ $middle =~ s|\h*($trailingCommentRegExp)||s;
+ $trailingComments .= $1;
+ }
+ }
+ # remove line breaks from within a sentence
+ $middle =~ s|
+ (?!\A) # not at the *beginning* of a match
+ (\h*)\R # possible horizontal space, then line break
+ |$1?$1:" ";|esgx if ${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{removeSentenceLineBreaks};
+ $middle =~ s|$tokens{blanklines}\h*\R?|$tokens{blanklines}\n|sg;
+ $logger->trace("follows: $beginning") if $is_tt_switch_active;
+ $logger->trace("sentence: $middle") if $is_tt_switch_active;
+ $logger->trace("ends with: $end") if $is_tt_switch_active;
+ # if indentation is specified for sentences, then we treat
+ # them as objects; otherwise we don't
+ my $replacementText = q();
+ if(${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentenceIndent} =~ m|\h+|){
+ my $sentenceObj = LatexIndent::Sentence->new(
+ name=>"sentence",
+ begin=>q(),
+ body=>$middle.$end,
+ end=>q(),
+ indentation=>${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentenceIndent},
+ modifyLineBreaksYamlName=>"sentence",
+ BeginStartsOnOwnLine=>1,
+ );
+ # log file output
+ $logger->trace("*sentence found: $middle.$end") if $is_t_switch_active;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($sentenceObj);
+ ${@{${$self}{children}}[-1]}{replacementText} = $beginning.$h_space.$tokens{sentence}.$sentenceCounter.$tokens{endOfToken}.$trailingComments.$trailing.($lineBreaksAtEnd ? q() : "\n");
+ $replacementText = ${@{${$self}{children}}[-1]}{replacementText};
+ } else {
+ $sentenceCounter++;
+ push(@sentenceStorage,{id=>$tokens{sentence}.$sentenceCounter.$tokens{endOfToken},value=>$middle.$end});
+ $replacementText = $beginning.$h_space.$tokens{sentence}.$sentenceCounter.$tokens{endOfToken}.$trailingComments.$trailing.($lineBreaksAtEnd ? q() : "\n");
+ };
+ $replacementText;
+ /xsge;
+
+ if(${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentenceIndent} !~ m/\h+/){
+ # loop back through the sentenceStorage and replace with the sentence, adjusting line breaks
+ # before and after appropriately
+ while( my $sentence = pop @sentenceStorage){
+ my $sentenceStorageID = ${$sentence}{id};
+ my $sentenceStorageValue = ${$sentence}{value};
+
+ # option to text wrap (and option to indent) sentences
+ if(${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{textWrapSentences}){
+ my $sentenceObj = LatexIndent::Document->new(body=>$sentenceStorageValue,
+ name=>"sentence",
+ modifyLineBreaksYamlName=>"sentence",
+ );
+
+ # text wrapping
+ $sentenceObj->yaml_get_columns;
+ $sentenceObj->text_wrap;
+
+ # indentation of sentences
+ if(${$sentenceObj}{body} =~ m/
+ (.*?) # content of first line
+ \R # first line break
+ (.*$) # rest of body
+ /sx){
+ my $bodyFirstLine = $1;
+ my $remainingBody = $2;
+ my $indentation = ${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentenceIndent};
+ $logger->trace("first line of sencent: $bodyFirstLine") if $is_tt_switch_active;
+ $logger->trace("remaining body (before indentation):\n'$remainingBody'") if($is_tt_switch_active);
+
+ # add the indentation to all the body except first line
+ $remainingBody =~ s/^/$indentation/mg unless($remainingBody eq ''); # add indentation
+ $logger->trace("remaining body (after indentation):\n$remainingBody'") if($is_tt_switch_active);
+
+ # put the body back together
+ ${$sentenceObj}{body} = $bodyFirstLine."\n".$remainingBody;
+ }
+ $sentenceStorageValue = ${$sentenceObj}{body};
+ };
+ # sentence at the very END
+ ${$self}{body} =~ s/\h*$sentenceStorageID\h*$/$sentenceStorageValue/s;
+ # sentence at the very BEGINNING
+ ${$self}{body} =~ s/^$sentenceStorageID\h*\R?/$sentenceStorageValue\n/s;
+ # all other sentences
+ ${$self}{body} =~ s/\R?\h*$sentenceStorageID\h*\R?/\n$sentenceStorageValue\n/s;
+ }
+ }
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $sentenceCounter++;
+ ${$self}{id} = "$tokens{sentence}$sentenceCounter";
+ return;
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ # option to text wrap (and option to indent) sentences
+ if(${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{textWrapSentences}){
+ $self->yaml_get_columns;
+ $self->text_wrap;
+ }
+
+ # search for environments
+ $logger->trace('looking for ENVIRONMENTS') if $is_t_switch_active;
+ $self->find_environments if ${$self}{body} =~ m/$environmentBasicRegExp/s;
+
+ # search for ifElseFi blocks
+ $logger->trace('looking for IFELSEFI') if $is_t_switch_active;
+ $self->find_ifelsefi if ${$self}{body} =~ m/$ifElseFiBasicRegExp/s;
+
+ # search for headings (part, chapter, section, setc)
+ $logger->trace('looking for HEADINGS (chapter, section, part, etc)') if $is_t_switch_active;
+ $self->find_heading if ${$self}{body} =~ m/$allHeadingsRegexp/s;
+
+ # the ordering of finding commands and special code blocks can change
+ $self->find_commands_or_key_equals_values_braces_and_special if ${$self}{body} =~ m/$specialBeginAndBracesBracketsBasicRegExp/s;
+}
+
+sub indent_body{
+ return unless ${$masterSettings{modifyLineBreaks}{oneSentencePerLine}}{sentenceIndent} =~ m/\h+/;
+
+ my $self = shift;
+
+ # indentation of sentences
+ if(${$self}{body} =~ m/
+ (.*?) # content of first line
+ \R # first line break
+ (.*$) # rest of body
+ /sx){
+ my $bodyFirstLine = $1;
+ my $remainingBody = $2;
+ my $indentation = ${$self}{indentation};
+ $logger->trace("first line of sentence $bodyFirstLine") if $is_tt_switch_active;
+ $logger->trace("remaining body (before indentation):\n'$remainingBody'") if($is_tt_switch_active);
+
+ # add the indentation to all the body except first line
+ $remainingBody =~ s/^/$indentation/mg unless($remainingBody eq ''); # add indentation
+ $logger->trace("remaining body (after indentation):\n$remainingBody'") if($is_tt_switch_active);
+
+ # put the body back together
+ ${$self}{body} = $bodyFirstLine."\n".$remainingBody;
+ }
+}
+
+sub yaml_get_indentation_settings_for_this_object{
+ return;
+}
+
+sub add_surrounding_indentation_to_begin_statement{
+ # specific method for sentences
+ my $self = shift;
+
+ my $surroundingIndentation = ${$self}{surroundingIndentation};
+ ${$self}{body} =~ s/^(\h*)?/$surroundingIndentation/s; # add indentation
+
+}
+
+
+1;
diff --git a/support/latexindent/LatexIndent/Special.pm b/support/latexindent/LatexIndent/Special.pm
new file mode 100644
index 0000000000..8898697d0f
--- /dev/null
+++ b/support/latexindent/LatexIndent/Special.pm
@@ -0,0 +1,272 @@
+package LatexIndent::Special;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use LatexIndent::IfElseFi qw/$ifElseFiBasicRegExp/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/find_special construct_special_begin $specialBeginAndBracesBracketsBasicRegExp $specialBeginBasicRegExp/;
+our $specialCounter;
+our $specialBegins = q();
+our $specialAllMatchesRegExp = q();
+our %individualSpecialRegExps;
+our $specialBeginAndBracesBracketsBasicRegExp;
+our $specialBeginBasicRegExp;
+
+sub construct_special_begin{
+ my $self = shift;
+
+ # put together a list of the begin terms in special
+ while( my ($specialName,$BeginEnd)= each %{$masterSettings{specialBeginEnd}}){
+ if(ref($BeginEnd) eq "HASH"){
+ # only append the regexps if lookForThis is 1
+ $specialBegins .= ($specialBegins eq ""?q():"|").${$BeginEnd}{begin} if(${$BeginEnd}{lookForThis}=~m/\d/s and ${$BeginEnd}{lookForThis} == 1);
+ }
+ }
+
+ # put together a list of the begin terms in special
+ while( my ($specialName,$BeginEnd)= each %{$masterSettings{specialBeginEnd}}){
+
+ # only append the regexps if lookForThis is 1
+ if( (ref($BeginEnd) eq "HASH") and ${$BeginEnd}{lookForThis}=~m/\d/s and ${$BeginEnd}{lookForThis} == 1){
+
+ # the overall regexp
+ $specialAllMatchesRegExp .= ($specialAllMatchesRegExp eq ""?q():"|")
+ .qr/
+ ${$BeginEnd}{begin}
+ (?: # cluster-only (), don't capture
+ (?!
+ (?:$specialBegins) # cluster-only (), don't capture
+ ). # any character, but not anything in $specialBegins
+ )*?
+ ${$BeginEnd}{end}
+ /sx;
+
+ # store the individual special regexp
+ $individualSpecialRegExps{$specialName} = qr/
+ (
+ ${$BeginEnd}{begin}
+ \h*
+ (\R*)?
+ )
+ (
+ (?: # cluster-only (), don't capture
+ (?!
+ (?:$specialBegins) # cluster-only (), don't capture
+ ). # any character, but not anything in $specialBegins
+ )*?
+ (\R*)?
+ )
+ (
+ ${$BeginEnd}{end}
+ )
+ (\h*)
+ (\R)?
+ /sx
+
+ } else {
+ $logger->trace("*The special regexps won't include anything from $specialName (see lookForThis)") if $is_t_switch_active ;
+ }
+ }
+
+ # move $$ to the beginning
+ if($specialBegins =~ m/\|\\\$\\\$/){
+ $specialBegins =~ s/\|(\\\$\\\$)//;
+ $specialBegins = $1."|".$specialBegins;
+ }
+
+ # info to the log file
+ $logger->trace("*The special beginnings regexp is: (see specialBeginEnd)") if $is_tt_switch_active;
+ $logger->trace($specialBegins) if $is_tt_switch_active;
+
+ # overall special regexp
+ $logger->trace("*The overall special regexp is: (see specialBeginEnd)") if $is_tt_switch_active;
+ $logger->trace($specialAllMatchesRegExp) if $is_tt_switch_active;
+
+ # basic special begin regexp
+ $specialBeginBasicRegExp = qr/$specialBegins/;
+ $specialBeginAndBracesBracketsBasicRegExp = $specialBegins."|\\{|\\[";
+ $specialBeginAndBracesBracketsBasicRegExp = qr/$specialBeginAndBracesBracketsBasicRegExp/;
+ }
+
+sub find_special{
+ my $self = shift;
+
+ # no point carrying on if the list of specials is empty
+ return if($specialBegins eq "");
+
+ # otherwise loop through the special begin/end
+ $logger->trace("*Searching ${$self}{name} for special begin/end (see specialBeginEnd)") if $is_t_switch_active ;
+ $logger->trace(Dumper(\%{$masterSettings{specialBeginEnd}})) if $is_tt_switch_active;
+
+ # keep looping as long as there is a special match of some kind
+ while(${$self}{body} =~ m/$specialAllMatchesRegExp/sx){
+
+ # loop through each special match
+ while( my ($specialName,$BeginEnd)= each %{$masterSettings{specialBeginEnd}}){
+
+ # log file
+ if((ref($BeginEnd) eq "HASH") and ${$BeginEnd}{lookForThis}=~m/\d/s and ${$BeginEnd}{lookForThis} == 1){
+ $logger->trace("Looking for $specialName") if $is_t_switch_active ;
+ } else {
+ $logger->trace("Not looking for $specialName (see lookForThis)") if ($is_t_switch_active and (ref($BeginEnd) eq "HASH"));
+ next;
+ }
+
+ # the regexp
+ my $specialRegExp = $individualSpecialRegExps{$specialName};
+ $logger->trace("$specialName regexp: \n$specialRegExp") if $is_tt_switch_active ;
+
+ while(${$self}{body} =~ m/$specialRegExp(\h*)($trailingCommentRegExp)?/){
+
+ # global substitution
+ ${$self}{body} =~ s/
+ $specialRegExp(\h*)($trailingCommentRegExp)?
+ /
+ # create a new special object
+ my $specialObject = LatexIndent::Special->new(begin=>$1,
+ body=>$3,
+ end=>$5,
+ name=>$specialName,
+ linebreaksAtEnd=>{
+ begin=>$2?1:0,
+ body=>$4?1:0,
+ end=>$7?1:0,
+ },
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"SpecialBeginStartsOnOwnLine",
+ # body statements
+ BodyStartsOnOwnLine=>"SpecialBodyStartsOnOwnLine",
+ # end statements
+ EndStartsOnOwnLine=>"SpecialEndStartsOnOwnLine",
+ # after end statements
+ EndFinishesWithLineBreak=>"SpecialEndFinishesWithLineBreak",
+ },
+ modifyLineBreaksYamlName=>"specialBeginEnd",
+ endImmediatelyFollowedByComment=>$7?0:($9?1:0),
+ horizontalTrailingSpace=>$6?$6:q(),
+ );
+
+ # log file output
+ $logger->trace("*Special found: $specialName") if $is_t_switch_active;
+
+ # the settings and storage of most objects has a lot in common
+ $self->get_settings_and_store_new_object($specialObject);
+ ${@{${$self}{children}}[-1]}{replacementText}.($8?$8:q()).($9?$9:q());
+ /xseg;
+
+ $self->wrap_up_tasks;
+ }
+ }
+ }
+}
+
+sub tasks_particular_to_each_object{
+ my $self = shift;
+
+ if( defined ${${$masterSettings{specialBeginEnd}}{${$self}{name}}}{middle}){
+ $logger->trace("middle specified for ${$self}{name} (see specialBeginEnd -> ${$self}{name} -> middle)") if $is_t_switch_active ;
+
+ # initiate the middle regexp
+ my $specialMiddle = q();
+
+ # we can specify middle as either an array or a hash
+ if(ref(${${$masterSettings{specialBeginEnd}}{${$self}{name}}}{middle}) eq "ARRAY"){
+ $logger->trace("looping through middle array for ${$self}{name}") if $is_t_switch_active ;
+ foreach(@{${${$masterSettings{specialBeginEnd}}{${$self}{name}}}{middle}}){
+ $specialMiddle .= ($specialMiddle eq ""?q():"|").$_;
+ }
+ $specialMiddle = qr/$specialMiddle/;
+ } else {
+ $specialMiddle = qr/${${$masterSettings{specialBeginEnd}}{${$self}{name}}}{middle}/;
+ }
+
+ $logger->trace("overall middle regexp for ${$self}{name}: $specialMiddle") if $is_t_switch_active ;
+
+ # store the middle regexp for later
+ ${$self}{middleRegExp} = $specialMiddle;
+
+ # check for existence of a 'middle' statement, and associated line break information
+ $self->check_for_else_statement(
+ # else name regexp
+ elseNameRegExp=>$specialMiddle,
+ # else statements name
+ ElseStartsOnOwnLine=>"SpecialMiddleStartsOnOwnLine",
+ # end statements
+ ElseFinishesWithLineBreak=>"SpecialMiddleFinishesWithLineBreak",
+ # for the YAML settings storage
+ storageNameAppend=>"middle",
+ # logfile information
+ logName=>"special middle",
+ );
+
+
+ }
+
+ return unless(${$masterSettings{specialBeginEnd}}{specialBeforeCommand});
+
+ # search for commands with arguments
+ $self->find_commands_or_key_equals_values_braces;
+
+ # search for arguments
+ $self->find_opt_mand_arguments;
+
+ # search for ifElseFi blocks
+ $self->find_ifelsefi;
+
+}
+
+sub post_indentation_check{
+ # needed to remove leading horizontal space before \else
+ my $self = shift;
+
+ return unless ( defined ${${$masterSettings{specialBeginEnd}}{${$self}{name}}}{middle});
+
+ $logger->trace("post indentation check for ${$self}{name} to account for middle") if $is_t_switch_active ;
+
+ # loop through \else and \or
+ foreach ({regExp=>${$self}{middleRegExp}}){
+ my %else = %{$_};
+ if(${$self}{body} =~ m/^\h*$else{regExp}/sm
+ and
+ !(${$self}{body} =~ m/^\h*$else{regExp}/s and ${$self}{linebreaksAtEnd}{begin}==0)
+ ){
+ $logger->trace("*Adding surrounding indentation to $else{regExp} statement(s) ('${$self}{surroundingIndentation}')") if $is_t_switch_active;
+ ${$self}{body} =~ s/^\h*($else{regExp})/${$self}{surroundingIndentation}$1/smg;
+ }
+ }
+ return;
+}
+
+
+sub create_unique_id{
+ my $self = shift;
+
+ $specialCounter++;
+
+ ${$self}{id} = "$tokens{specialBeginEnd}$specialCounter";
+ return;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Switches.pm b/support/latexindent/LatexIndent/Switches.pm
new file mode 100644
index 0000000000..d738a4b36b
--- /dev/null
+++ b/support/latexindent/LatexIndent/Switches.pm
@@ -0,0 +1,44 @@
+package LatexIndent::Switches;
+# 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/;
+our @EXPORT_OK = qw/%switches storeSwitches $is_m_switch_active $is_t_switch_active $is_tt_switch_active $is_r_switch_active $is_rr_switch_active $is_rv_switch_active/;
+our %switches;
+our $is_m_switch_active;
+our $is_t_switch_active;
+our $is_tt_switch_active;
+our $is_r_switch_active;
+our $is_rr_switch_active;
+our $is_rv_switch_active;
+
+sub storeSwitches{
+ my $self = shift;
+
+ # copy document switches into hash local to this module
+ %switches = %{${$self}{switches}};
+ $is_m_switch_active = defined $switches{modifyLineBreaks}?$switches{modifyLineBreaks}: 0;
+ $is_t_switch_active = defined $switches{trace}?$switches{trace}: 0;
+ $is_tt_switch_active = defined $switches{ttrace}?$switches{ttrace}: 0;
+ $is_t_switch_active = $is_tt_switch_active ? $is_tt_switch_active : $is_t_switch_active;
+ $is_r_switch_active = defined $switches{replacement}?$switches{replacement}: 0;
+ $is_rr_switch_active = defined $switches{onlyreplacement}?$switches{onlyreplacement}: 0;
+ $is_rv_switch_active = defined $switches{replacementRespectVerb}?$switches{replacementRespectVerb}: 0;
+ $is_r_switch_active = ($is_rr_switch_active|$is_rv_switch_active) ? ($is_rr_switch_active|$is_rv_switch_active) : $is_r_switch_active;
+ delete ${$self}{switches};
+ }
+1;
diff --git a/support/latexindent/LatexIndent/Tokens.pm b/support/latexindent/LatexIndent/Tokens.pm
new file mode 100644
index 0000000000..2e358e0b62
--- /dev/null
+++ b/support/latexindent/LatexIndent/Tokens.pm
@@ -0,0 +1,74 @@
+package LatexIndent::Tokens;
+# 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::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+our @EXPORT_OK = qw/token_check %tokens/;
+
+# each of the tokens begins the same way -- this is exploited during the hidden Children routine
+my $beginningToken = "LTXIN-TK-";
+my $ifelsefiSpecial = "!-!";
+
+# the %tokens hash is passed around many modules
+our %tokens = (
+ # user-facing naming convention
+ environments=>$beginningToken."ENVIRONMENT",
+ commands=>$beginningToken."COMMAND",
+ optionalArguments=>$beginningToken."OPTIONAL-ARGUMENT",
+ mandatoryArguments=>$beginningToken."MANDATORY-ARGUMENT",
+ ifElseFi=>$ifelsefiSpecial.$beginningToken."IFELSEFI",
+ else=>$beginningToken."ELSE",
+ items=>$beginningToken."ITEMS",
+ keyEqualsValuesBracesBrackets=>$beginningToken."KEY-VALUE-BRACES",
+ namedGroupingBracesBrackets=>$beginningToken."GROUPING-BRACES",
+ UnNamedGroupingBracesBrackets=>$beginningToken."UN-NAMED-GROUPING-BRACES",
+ specialBeginEnd=>$beginningToken."SPECIAL",
+ afterHeading=>$beginningToken."HEADING",
+ filecontents=>$beginningToken."FILECONTENTS",
+ # internal-facing naming convention
+ trailingComment=>"latexindenttrailingcomment",
+ ifelsefiSpecial=>$ifelsefiSpecial,
+ blanklines=>$beginningToken."blank-line",
+ arguments=>$beginningToken."ARGUMENTS",
+ roundBracket=>$beginningToken."ROUND-BRACKET",
+ verbatim=>$beginningToken."VERBATIM",
+ preamble=>$beginningToken."preamble",
+ beginOfToken=>$beginningToken,
+ doubleBackSlash=>$beginningToken."DOUBLEBACKSLASH",
+ alignmentBlock=>$beginningToken."ALIGNMENTBLOCK",
+ paragraph=>$beginningToken."PARA",
+ sentence=>$beginningToken."SENTENCE",
+ endOfToken=>"-END",
+ );
+
+sub token_check{
+ my $self = shift;
+
+ $logger->trace("*Token check") if $is_t_switch_active;
+ # we use tokens for trailing comments, environments, commands, etc, so check that they're not in the body
+ foreach( keys %tokens){
+ while(${$self}{body} =~ m/$tokens{$_}/si){
+ $logger->trace("Found $tokens{$_} within body, updating replacement token to $tokens{$_}-LIN") if($is_t_switch_active);
+ $tokens{$_} .= "-LIN";
+ }
+ }
+}
+
+
+1;
diff --git a/support/latexindent/LatexIndent/TrailingComments.pm b/support/latexindent/LatexIndent/TrailingComments.pm
new file mode 100644
index 0000000000..6ec052a0f3
--- /dev/null
+++ b/support/latexindent/LatexIndent/TrailingComments.pm
@@ -0,0 +1,132 @@
+package LatexIndent::TrailingComments;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_m_switch_active/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::LogFile qw/$logger/;
+use Data::Dumper;
+use Exporter qw/import/;
+our @EXPORT_OK = qw/remove_trailing_comments put_trailing_comments_back_in $trailingCommentRegExp add_comment_symbol construct_trailing_comment_regexp/;
+our @trailingComments;
+our $commentCounter = 0;
+our $trailingCommentRegExp;
+
+sub construct_trailing_comment_regexp{
+ $trailingCommentRegExp = qr/(?<!\\)%$tokens{trailingComment}\d+$tokens{endOfToken}/;
+}
+
+sub add_comment_symbol{
+ # add a trailing comment token after, for example, a square brace [
+ # or a curly brace { when, for example, BeginStartsOnOwnLine == 2
+ my $self = shift;
+
+ # increment the comment counter
+ $commentCounter++;
+
+ # store the comment -- without this, it won't get processed correctly at the end
+ push(@trailingComments,{id=>$tokens{trailingComment}.$commentCounter.$tokens{endOfToken},value=>q()});
+
+ # log file info
+ $logger->trace("*Updating trailing comment array")if $is_t_switch_active;
+ $logger->trace(Dumper(\@trailingComments),'ttrace') if($is_tt_switch_active);
+
+ # the returned value
+ return $tokens{trailingComment}.$commentCounter.$tokens{endOfToken};
+}
+
+sub remove_trailing_comments{
+ my $self = shift;
+ $logger->trace("*Storing trailing comments")if $is_t_switch_active;
+
+ # perform the substitution
+ ${$self}{body} =~ s/
+ (?<!\\) # not preceeded by a \
+ % # %
+ (
+ \h*? # followed by possible horizontal space
+ .*? # and anything else
+ )
+ $ # up to the end of a line
+ /
+ # increment comment counter and store comment
+ $commentCounter++;
+ push(@trailingComments,{id=>$tokens{trailingComment}.$commentCounter.$tokens{endOfToken},value=>$1});
+
+ # replace comment with dummy text
+ "%".$tokens{trailingComment}.$commentCounter.$tokens{endOfToken};
+ /xsmeg;
+ if(@trailingComments){
+ $logger->trace("Trailing comments stored in:") if($is_tt_switch_active);
+ $logger->trace(Dumper(\@trailingComments)) if($is_tt_switch_active);
+ } else {
+ $logger->trace("No trailing comments found") if($is_t_switch_active);
+ }
+ return;
+}
+
+sub put_trailing_comments_back_in{
+ my $self = shift;
+ return unless( @trailingComments > 0 );
+
+ $logger->trace("*Returning trailing comments to body")if $is_t_switch_active;
+
+ # loop through trailing comments in reverse so that, for example,
+ # latexindenttrailingcomment1 doesn't match the first
+ # part of latexindenttrailingcomment18, which would result in an 8 left over (bad)
+ while( my $comment = pop @trailingComments){
+ my $trailingcommentID = ${$comment}{id};
+ my $trailingcommentValue = ${$comment}{value};
+
+ # the -m switch can modify max characters per line, and trailing comment IDs can
+ # be split across lines
+ if($is_m_switch_active and ${$self}{body} !~ m/%$trailingcommentID/m){
+ $logger->trace("$trailingcommentID not found in body using /m matching, assuming it has been split across line (see modifyLineBreaks: textWrapOptions)") if($is_t_switch_active);
+ my $trailingcommentIDwithLineBreaks;
+
+ # construct a reg exp that contains possible line breaks in between each character
+ if(${$masterSettings{modifyLineBreaks}{textWrapOptions}}{separator} ne ''){
+ $trailingcommentIDwithLineBreaks = join("\\".${$masterSettings{modifyLineBreaks}{textWrapOptions}}{separator}."?",split(//,$trailingcommentID));
+ } else {
+ $trailingcommentIDwithLineBreaks = join("(?:\\h|\\R)*",split(//,$trailingcommentID));
+ }
+ my $trailingcommentIDwithLineBreaksRegExp = qr/$trailingcommentIDwithLineBreaks/s;
+
+ # replace the line-broken trailing comment ID with a non-broken trailing comment ID
+ ${$self}{body} =~ s/%\R?$trailingcommentIDwithLineBreaksRegExp/%$trailingcommentID/s;
+ }
+ if(${$self}{body} =~ m/%$trailingcommentID
+ (
+ (?! # not immediately preceeded by
+ (?<!\\) # \
+ % # %
+ ).*?
+ ) # captured into $1
+ (\h*)?$
+ /mx and $1 ne ''){
+ $logger->trace("Comment not at end of line $trailingcommentID, moving it to end of line")if $is_t_switch_active;
+ ${$self}{body} =~ s/%$trailingcommentID(.*)$/$1%$trailingcommentValue/m;
+ } else {
+ ${$self}{body} =~ s/%$trailingcommentID/%$trailingcommentValue/;
+ }
+ $logger->trace("replace %$trailingcommentID with %$trailingcommentValue") if($is_tt_switch_active);
+ }
+ return;
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/UnNamedGroupingBracesBrackets.pm b/support/latexindent/LatexIndent/UnNamedGroupingBracesBrackets.pm
new file mode 100644
index 0000000000..eea6ee6747
--- /dev/null
+++ b/support/latexindent/LatexIndent/UnNamedGroupingBracesBrackets.pm
@@ -0,0 +1,138 @@
+package LatexIndent::UnNamedGroupingBracesBrackets;
+# 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 LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+use Exporter qw/import/;
+our @ISA = "LatexIndent::Command"; # class inheritance, Programming Perl, pg 321
+our @EXPORT_OK = qw/construct_unnamed_grouping_braces_brackets_regexp $un_named_grouping_braces_RegExp $un_named_grouping_braces_RegExp_trailing_comment/;
+our $unNamedGroupingBracesCounter;
+our $un_named_grouping_braces_RegExp;
+our $un_named_grouping_braces_RegExp_trailing_comment;
+
+sub construct_unnamed_grouping_braces_brackets_regexp{
+ my $self = shift;
+
+ # grab the arguments regexp
+ my $optAndMandRegExp = $self->get_arguments_regexp;
+
+ # blank line token
+ my $blankLineToken = $tokens{blanklines};
+
+ # arguments Before, by default, includes beamer special and numbered arguments, for example #1 #2, etc
+ my $argumentsBefore = qr/${${$masterSettings{fineTuning}}{arguments}}{before}/;
+ my $UnNamedGroupingFollowRegExp = qr/${${$masterSettings{fineTuning}}{UnNamedGroupingBracesBrackets}}{follow}/;
+
+ # store the regular expresssion for matching and replacing
+ $un_named_grouping_braces_RegExp = qr/
+ # NOT
+ (?!
+ (?:
+ (?:(?<!\\)\])
+ |
+ (?:(?<!\\)\})
+ )
+ (?:\h|\R|$blankLineToken|$trailingCommentRegExp|$argumentsBefore)* # 0 or more h-space, blanklines, trailing comments
+ )
+ # END of NOT
+ (
+ (?:
+ $UnNamedGroupingFollowRegExp # starting with { OR [ OR , OR & OR ) OR ( OR $
+ )
+ \h*
+ ) # $1 into beginning bit
+ (\R*) # $2 linebreaksAtEnd of begin
+ ($optAndMandRegExp) # $3 mand|opt arguments (at least one) stored into body
+ (\R)? # $6 linebreak
+ /sx;
+
+ $un_named_grouping_braces_RegExp_trailing_comment = qr/$un_named_grouping_braces_RegExp(\h*)((?:$trailingCommentRegExp\h*)*)?/;
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $unNamedGroupingBracesCounter++;
+ ${$self}{id} = "$tokens{UnNamedGroupingBracesBrackets}$unNamedGroupingBracesCounter";
+ return;
+}
+
+sub get_replacement_text{
+ my $self = shift;
+
+ # the replacement text for a key = {value} needes to accomodate the leading [ OR { OR % OR , OR any combination thereof
+ $logger->trace("Custom replacement text routine for ${$self}{name}") if $is_t_switch_active;
+
+ # the un-named object is a little special, as it doesn't have a name; as such, if there are blank lines before
+ # the braces/brackets, we have to insert them
+ #
+ # also, the argument reg-exp can pick up a leading comment (with line break), which needs to be put
+ # into the replacement text (see documentation/demonstrations/pstricks.tex and test-cases/unnamed-braces/unnamed.tex for example)
+ ${$self}{body} =~ s/(.*?)(\{|\[)/$2/s;
+ ${$self}{replacementText} = ${$self}{beginningbit}.($1 ne ''?$1:q()).${$self}{id};
+
+ # but now turn off the switch for linebreaksAtEnd{begin}, otherwise the first brace gets too much indentation
+ # (see, for example, test-cases/namedGroupingBracesBrackets/special-characters-minimal.tex)
+ ${${$self}{linebreaksAtEnd}}{begin} = 0;
+ $logger->trace("Beginning bit is: ${$self}{beginningbit}") if($is_t_switch_active);
+ delete ${$self}{beginningbit};
+}
+
+sub check_for_blank_lines_at_beginning{
+ # some examples can have blank line tokens at the beginning of the body,
+ # which can confuse the routine below
+ # See, for example,
+ # test-cases/namedGroupingBracesBrackets/special-characters-minimal-blank-lines-m-switch.tex
+ # compared to
+ # test-cases/namedGroupingBracesBrackets/special-characters-minimal-blank-lines-default.tex
+ my $self = shift;
+
+ # blank line token
+ my $blankLineToken = $tokens{blanklines};
+
+ # if the body begins with 2 or more blank line tokens
+ if(${$self}{body} =~ m/^((?:$blankLineToken\R){2,})/s){
+
+ # remove them
+ ${$self}{body} =~ s/^((?:$blankLineToken\R)+)//s;
+
+ # store
+ my $blank_line_tokens_at_beginning_of_body = $1;
+
+ # and count them, for use after the indentation routine
+ ${$self}{blankLinesAtBeginning} = () = $blank_line_tokens_at_beginning_of_body =~ /$blankLineToken\R/sg
+ }
+ return;
+}
+
+sub put_blank_lines_back_in_at_beginning{
+ my $self = shift;
+
+ # some bodies have blank lines at the beginning
+ if(${$self}{blankLinesAtBeginning}){
+ for(my $i=0; $i<${$self}{blankLinesAtBeginning}; $i++){
+ ${$self}{body} = $tokens{blanklines}.${$self}{body};
+ }
+ }
+ return
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Verbatim.pm b/support/latexindent/LatexIndent/Verbatim.pm
new file mode 100644
index 0000000000..d115bf078f
--- /dev/null
+++ b/support/latexindent/LatexIndent/Verbatim.pm
@@ -0,0 +1,435 @@
+package LatexIndent::Verbatim;
+# 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 Data::Dumper;
+use Exporter qw/import/;
+use LatexIndent::Tokens qw/%tokens/;
+use LatexIndent::GetYamlSettings qw/%masterSettings/;
+use LatexIndent::Switches qw/$is_t_switch_active $is_tt_switch_active $is_m_switch_active/;
+use LatexIndent::LogFile qw/$logger/;
+our @EXPORT_OK = qw/put_verbatim_back_in find_verbatim_environments find_noindent_block find_verbatim_commands find_verbatim_special verbatim_common_tasks/;
+our @ISA = "LatexIndent::Document"; # class inheritance, Programming Perl, pg 321
+our $verbatimCounter;
+
+sub find_noindent_block{
+ my $self = shift;
+
+ # noindent block
+ $logger->trace('*Searching for NOINDENTBLOCk environments (see noIndentBlock)') if $is_t_switch_active;
+ $logger->trace(Dumper(\%{$masterSettings{noIndentBlock}})) if($is_tt_switch_active);
+ while( my ($noIndentBlock,$yesno)= each %{$masterSettings{noIndentBlock}}){
+ if($yesno){
+ $logger->trace("looking for $noIndentBlock:$yesno environments") if $is_t_switch_active;
+
+ (my $noIndentBlockSpec = $noIndentBlock) =~ s/\*/\\*/sg;
+ my $noIndentRegExp = qr/
+ (
+ (?!<\\)
+ %
+ \h* # possible horizontal spaces
+ \\begin\{
+ $noIndentBlockSpec # environment name captured into $2
+ \} # % \begin{noindentblock} statement
+ )
+ (
+ .*?
+ ) # non-greedy match (body)
+ (
+ (?!<\\)
+ % # %
+ \h* # possible horizontal spaces
+ \\end\{$noIndentBlockSpec\} # \end{noindentblock}
+ ) # % \end{<something>} statement
+ /sx;
+
+ while( ${$self}{body} =~ m/$noIndentRegExp/sx){
+
+ # create a new Verbatim object
+ my $noIndentBlockObj = LatexIndent::Verbatim->new( begin=>$1,
+ body=>$2,
+ end=>$3,
+ name=>$noIndentBlock,
+ type=>"noindentblock",
+ modifyLineBreaksYamlName=>"verbatim",
+ );
+
+ # give unique id
+ $noIndentBlockObj->create_unique_id;
+
+ # verbatim children go in special hash
+ ${$self}{verbatim}{${$noIndentBlockObj}{id}}=$noIndentBlockObj;
+
+ # log file output
+ $logger->trace("*NOINDENTBLOCK environment found: $noIndentBlock") if $is_t_switch_active;
+
+ # remove the environment block, and replace with unique ID
+ ${$self}{body} =~ s/$noIndentRegExp/${$noIndentBlockObj}{id}/sx;
+
+ $logger->trace("replaced with ID: ${$noIndentBlockObj}{id}") if $is_t_switch_active;
+
+ # possible decoration in log file
+ $logger->trace(${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace}) if ${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace};
+ }
+ } else {
+ $logger->trace("*not* looking for $noIndentBlock as $noIndentBlock:$yesno") if $is_t_switch_active;
+ }
+ }
+ return;
+}
+
+sub find_verbatim_environments{
+ my $self = shift;
+
+ # verbatim environments
+ $logger->trace('*Searching for VERBATIM environments (see verbatimEnvironments)') if $is_t_switch_active;
+ $logger->trace(Dumper(\%{$masterSettings{verbatimEnvironments}})) if($is_tt_switch_active);
+ while( my ($verbEnv,$yesno)= each %{$masterSettings{verbatimEnvironments}}){
+ if($yesno){
+ $logger->trace("looking for $verbEnv:$yesno environments") if $is_t_switch_active;
+
+ (my $verbEnvSpec = $verbEnv) =~ s/\*/\\*/sg;
+ my $verbatimRegExp = qr/
+ (
+ \\begin\{
+ $verbEnvSpec # environment name captured into $1
+ \} # \begin{<something>} statement
+ )
+ (
+ .*?
+ ) # any character, but not \\begin
+ (
+ \\end\{$verbEnvSpec\} # \end{<something>} statement
+ )
+ (\h*)? # possibly followed by horizontal space
+ (\R)? # possibly followed by a line break
+ /sx;
+
+ while( ${$self}{body} =~ m/$verbatimRegExp/sx){
+
+ # create a new Verbatim object
+ my $verbatimBlock = LatexIndent::Verbatim->new( begin=>$1,
+ body=>$2,
+ end=>$3,
+ name=>$verbEnv,
+ type=>"environment",
+ modifyLineBreaksYamlName=>"verbatim",
+ linebreaksAtEnd=>{
+ end=>$5?1:0,
+ },
+ horizontalTrailingSpace=>$4?$4:q(),
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"VerbatimBeginStartsOnOwnLine",
+ # after end statements
+ EndFinishesWithLineBreak=>"VerbatimEndFinishesWithLineBreak",
+ },
+ );
+
+ # there are common tasks for each of the verbatim objects
+ $verbatimBlock->verbatim_common_tasks;
+
+ # verbatim children go in special hash
+ ${$self}{verbatim}{${$verbatimBlock}{id}}=$verbatimBlock;
+
+ # log file output
+ $logger->trace("*VERBATIM environment found: $verbEnv") if $is_t_switch_active;
+
+ # remove the environment block, and replace with unique ID
+ ${$self}{body} =~ s/$verbatimRegExp/${$verbatimBlock}{replacementText}/sx;
+
+ $logger->trace("replaced with ID: ${$verbatimBlock}{id}") if $is_t_switch_active;
+
+ # possible decoration in log file
+ $logger->trace(${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace}) if ${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace};
+ }
+ } else {
+ $logger->trace("*not* looking for $verbEnv as $verbEnv:$yesno") if $is_t_switch_active;
+ }
+ }
+ return;
+}
+
+sub find_verbatim_commands{
+ my $self = shift;
+
+ # verbatim commands need to be treated separately to verbatim environments;
+ # note that, for example, we could quite reasonably have \lstinline!%!, which
+ # would need to be found *before* trailing comments have been removed. Similarly,
+ # verbatim commands need to be put back in *after* trailing comments have been put
+ # back in
+ $logger->trace('*Searching for VERBATIM commands (see verbatimCommands)') if $is_t_switch_active;
+ $logger->trace(Dumper(\%{$masterSettings{verbatimCommands}})) if($is_tt_switch_active);
+ while( my ($verbCommand,$yesno)= each %{$masterSettings{verbatimCommands}}){
+ if($yesno){
+ $logger->trace("looking for $verbCommand:$yesno Commands") if $is_t_switch_active;
+
+ my $verbatimRegExp = qr/
+ (
+ \\$verbCommand
+ \h*
+ ) # name of command into $1
+ (
+ \[
+ (?:
+ (?!
+ (?:(?<!\\)\[)
+ ).
+ )*? # not including [, but \[ ok
+ (?<!\\) # not immediately pre-ceeded by \
+ \] # [optional arguments]
+ \h*
+ )? # opt arg into $2
+ (
+ .
+ ) # delimiter into $3
+ (
+ .*?
+ ) # body into $4
+ \3
+ (\h*)? # possibly followed by horizontal space
+ (\R)? # possibly followed by a line break
+ /mx;
+
+ while( ${$self}{body} =~ m/$verbatimRegExp/){
+
+ # create a new Verbatim object
+ my $verbatimCommand = LatexIndent::Verbatim->new( begin=>$1.($2?$2:q()).$3,
+ body=>$4,
+ end=>$3,
+ name=>$verbCommand,
+ type=>"command",
+ modifyLineBreaksYamlName=>"verbatim",
+ linebreaksAtEnd=>{
+ end=>$6?1:0,
+ },
+ horizontalTrailingSpace=>$5?$5:q(),
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"VerbatimBeginStartsOnOwnLine",
+ # after end statements
+ EndFinishesWithLineBreak=>"VerbatimEndFinishesWithLineBreak",
+ },
+ optArg=>$2?$2:q(),
+ );
+ # there are common tasks for each of the verbatim objects
+ $verbatimCommand->verbatim_common_tasks;
+
+ # output, if desired
+ $logger->trace(Dumper($verbatimCommand),'ttrace') if($is_tt_switch_active);
+
+ # verbatim children go in special hash
+ ${$self}{verbatim}{${$verbatimCommand}{id}}=$verbatimCommand;
+
+ # log file output
+ $logger->trace("*VERBATIM command found: $verbCommand") if $is_t_switch_active;
+
+ # remove the environment block, and replace with unique ID
+ ${$self}{body} =~ s/$verbatimRegExp/${$verbatimCommand}{replacementText}/sx;
+
+ $logger->trace("replaced with ID: ${$verbatimCommand}{id}") if $is_t_switch_active;
+
+ # possible decoration in log file
+ $logger->trace(${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace}) if ${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace};
+ }
+ } else {
+ $logger->trace("*not* looking for $verbCommand as $verbCommand:$yesno") if $is_t_switch_active;
+ }
+ }
+ return;
+
+}
+
+sub find_verbatim_special{
+ my $self = shift;
+
+ # loop through specialBeginEnd
+ while( my ($specialName,$BeginEnd)= each %{$masterSettings{specialBeginEnd}}){
+
+ # only classify special Verbatim if lookForThis is 'verbatim'
+ if( (ref($BeginEnd) eq "HASH") and ${$BeginEnd}{lookForThis}=~m/v/s and ${$BeginEnd}{lookForThis} eq 'verbatim'){
+ $logger->trace('*Searching for VERBATIM special (see specialBeginEnd)') if $is_t_switch_active;
+
+ my $verbatimRegExp = qr/
+ (
+ ${$BeginEnd}{begin}
+ )
+ (
+ .*?
+ )
+ (
+ ${$BeginEnd}{end}
+ )
+ (\h*)? # possibly followed by horizontal space
+ (\R)? # possibly followed by a line break
+ /sx;
+
+ while( ${$self}{body} =~ m/$verbatimRegExp/sx){
+
+ # create a new Verbatim object
+ my $verbatimBlock = LatexIndent::Verbatim->new( begin=>$1,
+ body=>$2,
+ end=>$3,
+ name=>$specialName,
+ modifyLineBreaksYamlName=>"specialBeginEnd",
+ linebreaksAtEnd=>{
+ end=>$5?1:0,
+ },
+ horizontalTrailingSpace=>$4?$4:q(),
+ type=>"special",
+ aliases=>{
+ # begin statements
+ BeginStartsOnOwnLine=>"SpecialBeginStartsOnOwnLine",
+ # after end statements
+ EndFinishesWithLineBreak=>"SpecialEndFinishesWithLineBreak",
+ },
+ );
+ # there are common tasks for each of the verbatim objects
+ $verbatimBlock->verbatim_common_tasks;
+
+ # verbatim children go in special hash
+ ${$self}{verbatim}{${$verbatimBlock}{id}}=$verbatimBlock;
+
+ # log file output
+ $logger->trace("*VERBATIM special found: $specialName") if $is_t_switch_active;
+
+ # remove the special block, and replace with unique ID
+ ${$self}{body} =~ s/$verbatimRegExp/${$verbatimBlock}{replacementText}/sx;
+
+ $logger->trace("replaced with ID: ${$verbatimBlock}{id}") if $is_t_switch_active;
+
+ # possible decoration in log file
+ $logger->trace(${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace}) if ${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace};
+ }
+ }
+ }
+}
+
+sub put_verbatim_back_in {
+ my $self = shift;
+ my %input = @_;
+
+ # if there are no verbatim children, return
+ return unless(${$self}{verbatim});
+
+ my $verbatimCount=0;
+ my $toMatch = q();
+ if($input{match} eq "everything-except-commands"){
+ $toMatch = "noindentblockenvironmentspecial";
+
+ # count the number of non-command verbatim objects
+ while( my ($key,$child)= each %{${$self}{verbatim}}){
+ ${$child}{type} = "environment" if !(defined ${$child}{type});
+ $verbatimCount++ if($toMatch =~ m/${$child}{type}/);
+ }
+ return unless($verbatimCount>0);
+ } else {
+ $toMatch = "command";
+ # count the number of command verbatim objects
+ while( my ($key,$child)= each %{${$self}{verbatim}}){
+ ${$child}{type} = "environment" if !(defined ${$child}{type});
+ $verbatimCount++ if($toMatch =~ m/${$child}{type}/);
+ }
+ return unless($verbatimCount>0);
+ }
+
+ # search for environments/commands
+ $logger->trace('*Putting verbatim back in') if $is_t_switch_active;
+ $logger->trace('pre-processed body:') if $is_tt_switch_active;
+ $logger->trace(${$self}{body}) if($is_tt_switch_active);
+
+ # loop through document children hash
+ my $verbatimFound=0;
+ while($verbatimFound < $verbatimCount){
+ while( my ($key,$child)= each %{${$self}{verbatim}}){
+ if($toMatch =~ m/${$child}{type}/){
+ if(${$self}{body} =~ m/${$child}{id}/mx){
+ # possibly remove trailing line break
+ if(defined ${$child}{EndFinishesWithLineBreak}
+ and ${$child}{EndFinishesWithLineBreak}==-1
+ and ${$self}{body} =~ m/${$child}{id}\h*\R/s){
+ $logger->trace("m-switch active, removing trailing line breaks from ${$child}{name}") if $is_t_switch_active;
+ ${$self}{body} =~ s/${$child}{id}(\h*)?(\R|\h)*/${$child}{id} /s;
+ }
+ # replace ids with body
+ ${$self}{body} =~ s/${$child}{id}/${$child}{begin}${$child}{body}${$child}{end}/s;
+
+ # log file info
+ $logger->trace('Body now looks like:') if $is_tt_switch_active;
+ $logger->trace(${$self}{body},'ttrace') if($is_tt_switch_active);
+
+ # delete the child so it won't be operated upon again
+ delete ${$self}{verbatim}{${$child}{id}};
+ $verbatimFound++;
+ } elsif ($is_m_switch_active and ${$masterSettings{modifyLineBreaks}{textWrapOptions}}{columns}>1 and ${$self}{body} !~ m/${$child}{id}/){
+ $logger->trace("${$child}{id} not found in body using /m matching, it may have been split across line (see modifyLineBreaks: textWrapOptions)") if($is_t_switch_active);
+
+ # search for a version of the verbatim ID that may have line breaks
+ my $verbatimIDwithLineBreaks = join("\\R?",split(//,${$child}{id}));
+ my $verbatimIDwithLineBreaksRegExp = qr/$verbatimIDwithLineBreaks/s;
+
+ # replace the line-broken verbatim ID with a non-broken verbatim ID
+ ${$self}{body} =~ s/$verbatimIDwithLineBreaksRegExp/${$child}{id}/s;
+
+ # note: we do *not* label this as found, as we need to go back through
+ # and search for the newly modified ID
+ }
+ }
+
+ # logfile info
+ $logger->trace('*Post-processed body:') if $is_tt_switch_active;
+ $logger->trace(${$self}{body}) if($is_tt_switch_active);
+ }
+ }
+ return;
+}
+
+sub verbatim_common_tasks{
+
+ my $self = shift;
+
+ # get yaml settings
+ $self->yaml_modify_line_breaks_settings if $is_m_switch_active;
+
+ # give unique id
+ $self->create_unique_id;
+
+ # the replacement text can be just the ID, but the ID might have a line break at the end of it
+ $self->get_replacement_text;
+
+ # the above regexp, when used below, will remove the trailing linebreak in ${$self}{linebreaksAtEnd}{end}
+ # so we compensate for it here
+ $self->adjust_replacement_text_line_breaks_at_end;
+
+ # modify line breaks end statements
+ $self->modify_line_breaks_end if $is_m_switch_active;
+}
+
+sub create_unique_id{
+ my $self = shift;
+
+ $verbatimCounter++;
+ ${$self}{id} = "$tokens{verbatim}$verbatimCounter$tokens{endOfToken}";
+ return;
+}
+
+sub yaml_get_textwrap_removeparagraphline_breaks{
+ my $self = shift;
+ $logger->trace("No text wrap or remove paragraph line breaks for verbatim code blocks, ${$self}{name}") if ${$masterSettings{logFilePreferences}}{showDecorationFinishCodeBlockTrace};
+}
+
+1;
diff --git a/support/latexindent/LatexIndent/Version.pm b/support/latexindent/LatexIndent/Version.pm
new file mode 100644
index 0000000000..c0ecb8bb06
--- /dev/null
+++ b/support/latexindent/LatexIndent/Version.pm
@@ -0,0 +1,24 @@
+package LatexIndent::Version;
+# 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/;
+our @EXPORT_OK = qw/$versionNumber $versionDate/;
+
+our $versionNumber = '3.7';
+our $versionDate = '2019-07-13';
+1
diff --git a/support/latexindent/README b/support/latexindent/README
new file mode 100644
index 0000000000..86781a6af1
--- /dev/null
+++ b/support/latexindent/README
@@ -0,0 +1,57 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ latexindent.pl, version 3.7, 2019-07-13
+
+ PERL script to indent code within environments, and align delimited
+ environments in .tex files.
+
+ 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/
+
+ C. M. Hughes
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+
+
+FOR COMPLETE DETAILS, PLEASE SEE documentation/latexindent.pdf
+
+Note: latexindent.exe was created using
+
+ perl ppp.pl -u -o latexindent.exe latexindent.pl
+
+ using the Par::Packer perl module.
+
+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+
+
+USAGE
+ You'll need
+
+ latexindent.pl
+ LatexIndent/*.pm
+ defaultSettings.yaml
+
+ in the same directory. Windows users might prefer to grab latexindent.exe
+
+* IMPORTANT *
+
+This script may not work for your style of formatting; I highly
+recommend comparing the outputfile.tex to make sure that
+nothing has been changed (or removed) in a way that will damage
+your file.
+
+I recommend both using the following:
+ - a visual check, at the very least, make sure that
+ each file has the same number of lines
+ - a check using latexdiff inputfile.tex outputfile.tex
+ - git status myfile.tex
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/support/latexindent/defaultSettings.yaml b/support/latexindent/defaultSettings.yaml
new file mode 100644
index 0000000000..a706131365
--- /dev/null
+++ b/support/latexindent/defaultSettings.yaml
@@ -0,0 +1,603 @@
+# defaultSettings.yaml for latexindent.pl, version 3.7, 2019-07-13
+# a script that aims to
+# beautify .tex, .sty, .cls files
+#
+# (or latexindent.exe if you're on Windows)
+#
+# 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
+
+
+# You should feel encouraged to change anything you like in these settings, but
+# it would probably be better to have your own user settings
+# files somewhere else - remember that this file may be overwritten
+# when you update your tex distribution. Please see the manual linked from:
+#
+# https://github.com/cmhughes/latexindent.pl
+#
+# for details of how to create and configure your own settings files.
+#
+# Please read the manual (linked from above) first to understand what each switch does.
+
+# latexindent can be called to act on a file without using the file's extension,
+# e.g, simply
+# latexindent myfile
+# in which case the choice of file extension is chosen
+# according to the choices made in fileExtensionPreference
+# Other file extensions can be added.
+fileExtensionPreference:
+ .tex: 1
+ .sty: 2
+ .cls: 3
+ .bib: 4
+
+# default file extension of backup file (if -w switch is active)
+# for example, if your .tex file is called
+# myfile.tex
+# and you specify the backupExtension as BACKUP.bak then your
+# backup file will be
+# myfileBACKUP.bak
+backupExtension: .bak
+
+# only one backup per file:
+# - if onlyOneBackUp is 0 then, as a safety measure,
+# the number on the extension increments by 1 each time:
+#
+# myfile.bak0, myfile.bak1, myfile.bak2
+# - if you set onlyOnebackUp to 1, then the backup file will
+# be overwritten each time (not recommended until you trust the script)
+onlyOneBackUp: 0
+
+# some users may want a finite number of backup files,
+# say at most 3; in which case, they can change this maxNumberOfBackUps.
+#
+# If maxNumberOfBackUps is set to 0 (or less) then infinitely
+# many backups are possible, unless onlyOneBackUp is switched on
+maxNumberOfBackUps: 0
+
+# some users may wish to cycle through back up files.
+#
+# for example, with maxNumberOfBackUps: 4, they may
+# wish to delete the oldest back up file, and keep only the most recent.
+#
+# copy myfile.bak1 to myfile.bak0
+# copy myfile.bak2 to myfile.bak1
+# copy myfile.bak3 to myfile.bak2
+# copy myfile.bak4 to myfile.bak3
+#
+# the back up will be written to myfile.bak4
+cycleThroughBackUps: 0
+
+# preferences for information displayed in the log file
+logFilePreferences:
+ showEveryYamlRead: 1
+ showAmalgamatedSettings: 0
+ showDecorationStartCodeBlockTrace: 0
+ showDecorationFinishCodeBlockTrace: 0
+ endLogFileWith: '--------------'
+ showGitHubInfoFooter: 1
+ PatternLayout:
+ default: "%A%n"
+ trace: "%A%n"
+ ttrace: "%A%n"
+
+# verbatim environments specified
+# in this field will not be changed at all!
+verbatimEnvironments:
+ verbatim: 1
+ lstlisting: 1
+ minted: 1
+
+# verbatim commands such as \verb! body !, \lstinline$something else$
+verbatimCommands:
+ verb: 1
+ lstinline: 1
+
+# no indent blocks (not necessarily verbatim
+# environments) which are marked as %\begin{noindent}
+# or anything else that you detail in the following
+noIndentBlock:
+ noindent: 1
+ cmhtest: 1
+
+# remove trailing whitespace from all lines
+removeTrailingWhitespace:
+ beforeProcessing: 0
+ afterProcessing: 1
+
+# \begin{document} and \end{document} are treated differently
+# by latexindent within filecontents environments
+fileContentsEnvironments:
+ filecontents: 1
+ filecontents*: 1
+
+# indent preamble
+indentPreamble: 0
+
+# assume no preamble in cls, sty, by default
+lookForPreamble:
+ .tex: 1
+ .sty: 0
+ .cls: 0
+ .bib: 0
+
+# some preambles can contain \begin and \end statements
+# that are not in their 'standard environment block', for example,
+# consider the following key = values:
+# preheadhook={\begin{mdframed}[style=myframedstyle]},
+# postfoothook=\end{mdframed},
+preambleCommandsBeforeEnvironments: 0
+
+# default value of indentation
+defaultIndent: "\t"
+
+# name of code blocks that should have their body aligned at ampersand delimiters
+lookForAlignDelims:
+ tabular:
+ delims: 1
+ alignDoubleBackSlash: 1
+ spacesBeforeDoubleBackSlash: 1
+ multiColumnGrouping: 0
+ alignRowsWithoutMaxDelims: 1
+ spacesBeforeAmpersand: 1
+ spacesAfterAmpersand: 1
+ justification: "left"
+ tabularx:
+ delims: 1
+ longtable: 1
+ tabu: 1
+ array: 1
+ matrix: 1
+ bmatrix: 1
+ Bmatrix: 1
+ pmatrix: 1
+ vmatrix: 1
+ Vmatrix: 1
+ align: 1
+ align*: 1
+ alignat: 1
+ alignat*: 1
+ aligned: 1
+ cases: 1
+ dcases: 1
+ listabla: 1
+
+# if you want the script to look for \item commands
+# and format it, as follows (for example),
+# \begin{itemize}
+# \item content here
+# next line is indented
+# next line is indented
+# \item another item
+# \end{itemize}
+# then populate indentAfterItems. See also itemNames
+indentAfterItems:
+ itemize: 1
+ enumerate: 1
+ description: 1
+ list: 1
+
+# if you want to use other names for your items (for example, \part)
+# then populate them here; note that you can trick latexindent.pl
+# into indenting all kinds of commands (within environments specified in
+# indentAfterItems) using this technique.
+itemNames:
+ item: 1
+ myitem: 1
+
+# specialBeginEnd is, by default, mathmode focus, although
+# there's no restrictions
+specialBeginEnd:
+ displayMath:
+ begin: '\\\['
+ end: '\\\]'
+ lookForThis: 1
+ inlineMath:
+ begin: '(?<!\$)(?<!\\)\$(?!\$)'
+ end: '(?<!\\)\$(?!\$)'
+ lookForThis: 1
+ displayMathTeX:
+ begin: '\$\$'
+ end: '\$\$'
+ lookForThis: 1
+ specialBeforeCommand: 0
+
+# if you want to add indentation after
+# a heading, such as \part, \chapter, etc
+# then populate it in here - you can add
+# an indent rule to indentRules if you would
+# like something other than defaultIndent
+#
+# you can also change the level if you like,
+# or add your own title command
+indentAfterHeadings:
+ part:
+ indentAfterThisHeading: 0
+ level: 1
+ chapter:
+ indentAfterThisHeading: 0
+ level: 2
+ section:
+ indentAfterThisHeading: 0
+ level: 3
+ subsection:
+ indentAfterThisHeading: 0
+ level: 4
+ subsection*:
+ indentAfterThisHeading: 0
+ level: 4
+ subsubsection:
+ indentAfterThisHeading: 0
+ level: 5
+ paragraph:
+ indentAfterThisHeading: 0
+ level: 6
+ subparagraph:
+ indentAfterThisHeading: 0
+ level: 7
+
+# maximum indentation, off by default
+maximumIndentation: -1
+
+# if you don't want to have additional indentation
+# in a code block, then add it to noAdditionalIndent; note that
+# code blocks in this field will inherit
+# the *current* level of indentation they just won't
+# get any *additional* indentation
+noAdditionalIndent:
+ myexample: 1
+ mydefinition: 1
+ problem: 1
+ exercises: 1
+ mysolution: 1
+ foreach: 0
+ widepage: 1
+ comment: 1
+ document: 1
+ frame: 0
+
+# if you have indent rules for particular code blocks
+# then you can populate them in indentRules; for example, you might just want
+# to use a space " " or maybe a double tab "\t\t"
+indentRules:
+ myenvironment: "\t\t"
+ anotherenvironment: "\t\t\t\t"
+ chapter: " "
+ section: " "
+ item: " "
+ myitem: " "
+
+# set noAdditionalIndent globally for codeblocks
+noAdditionalIndentGlobal:
+ environments: 0
+ commands: 1
+ optionalArguments: 0
+ mandatoryArguments: 0
+ ifElseFi: 0
+ items: 0
+ keyEqualsValuesBracesBrackets: 0
+ namedGroupingBracesBrackets: 0
+ UnNamedGroupingBracesBrackets: 0
+ specialBeginEnd: 0
+ afterHeading: 0
+ filecontents: 0
+
+# set indentRules globally for codeblocks; these need
+# to be horizontal spaces, if they are to be used
+indentRulesGlobal:
+ environments: 0
+ commands: 0
+ optionalArguments: 0
+ mandatoryArguments: 0
+ ifElseFi: 0
+ items: 0
+ keyEqualsValuesBracesBrackets: 0
+ namedGroupingBracesBrackets: 0
+ UnNamedGroupingBracesBrackets: 0
+ specialBeginEnd: 0
+ afterHeading: 0
+ filecontents: 0
+
+# command code block details
+commandCodeBlocks:
+ roundParenthesesAllowed: 1
+ stringsAllowedBetweenArguments:
+ -
+ amalgamate: 1
+ - 'node'
+ - 'at'
+ - 'to'
+ - 'decoration'
+ - '\+\+'
+ - '\-\-'
+ commandNameSpecial:
+ -
+ amalgamate: 1
+ - '@ifnextchar\['
+
+# modifyLineBreaks will only be searched if the -m
+# switch is active
+#
+# poly-switch examples:
+#
+# BeginStartsOnOwnLine:
+# modify line breaks before a begin statement
+#
+# when set to -1, e.g
+# some text some text
+# \begin{myenvironment}
+# will be changed to
+# some text some text \begin{myenvironment}
+# when set to 0, the switch is ignored
+# when set to 1, e.g
+# some text some text \begin{myenvironment}
+# will be changed to
+# some text some text
+# \begin{myenvironment}
+# when set to 2, e.g
+# some text some text \begin{myenvironment}
+# will be changed to
+# some text some text%
+# \begin{myenvironment}
+# when set to 3, e.g
+# some text some text \begin{myenvironment}
+# will be changed to
+# some text some text
+#
+# \begin{myenvironment}
+#
+# BodyStartsOnOwnLine:
+# modify line breaks before the beginning of the body
+#
+# when set to -1, e.g
+# \begin{myenv}
+# body text body text
+# will be changed to
+# \begin{myenv}body text body text
+# when set to 0, the switch is ignored
+# when set to 1, e.g
+# \begin{myenv}body text body text
+# will be changed to
+# \begin{myenv}
+# body text body text
+# when set to 2, e.g
+# \begin{myenv}body text body text
+# will be changed to
+# \begin{myenv}%
+# body text body text
+# when set to 3, e.g
+# \begin{myenv}body text body text
+# will be changed to
+# \begin{myenv}
+#
+# body text body text
+#
+# EndStartsOnOwnLine:
+# modify line breaks before the end statement
+#
+# when set to -1, e.g
+# some text some text
+# \end{myenvironment}
+# will be changed to
+# some text some text \end{myenvironment}
+# when set to 0, the switch is ignored
+# when set to 1, e.g
+# some text some text \end{myenvironment}
+# will be changed to
+# some text some text
+# \end{myenvironment}
+# when set to 2, e.g
+# some text some text \end{myenvironment}
+# will be changed to
+# some text some text%
+# \end{myenvironment}
+# when set to 3, e.g
+# some text some text \end{myenvironment}
+# will be changed to
+# some text some text
+#
+# \end{myenvironment}
+#
+# EndFinishesWithLineBreak:
+# modify line breaks after the end statement
+#
+# when set to -1, e.g
+# \end{myenvironment}
+# some text some text
+# will be changed to
+# \end{myenvironment}some text some text
+# when set to 0, the switch is ignored
+# when set to 1, e.g
+# \end{myenvironment}some text some text
+# will be changed to
+# \end{myenvironment}
+# some text some text
+# when set to 2, e.g
+# \end{myenvironment}some text some text
+# will be changed to
+# \end{myenvironment}%
+# some text some text
+# when set to 3, e.g
+# \end{myenvironment}some text some text
+# will be changed to
+# \end{myenvironment}
+#
+# some text some text
+#
+# you can specify settings on a per-name basis
+modifyLineBreaks:
+ preserveBlankLines: 1
+ condenseMultipleBlankLinesInto: 1
+ oneSentencePerLine:
+ manipulateSentences: 0
+ removeSentenceLineBreaks: 1
+ textWrapSentences: 0
+ sentenceIndent: ""
+ sentencesFollow:
+ par: 1
+ blankLine: 1
+ fullStop: 1
+ exclamationMark: 1
+ questionMark: 1
+ rightBrace: 1
+ commentOnPreviousLine: 1
+ other: 0
+ sentencesBeginWith:
+ A-Z: 1
+ a-z: 0
+ other: 0
+ sentencesEndWith:
+ basicFullStop: 0
+ betterFullStop: 1
+ exclamationMark: 1
+ questionMark: 1
+ other: 0
+ textWrapOptions:
+ columns: 0
+ separator: ""
+ perCodeBlockBasis: 0
+ all: 0
+ alignAtAmpersandTakesPriority: 1
+ environments:
+ quotation: 0
+ ifElseFi: 0
+ optionalArguments: 0
+ mandatoryArguments: 0
+ items: 0
+ specialBeginEnd: 0
+ afterHeading: 0
+ preamble: 0
+ filecontents: 0
+ masterDocument: 0
+ removeParagraphLineBreaks:
+ all: 0
+ beforeTextWrap: 0
+ alignAtAmpersandTakesPriority: 1
+ environments:
+ quotation: 0
+ ifElseFi: 0
+ optionalArguments: 0
+ mandatoryArguments: 0
+ items: 0
+ specialBeginEnd: 0
+ afterHeading: 0
+ preamble: 0
+ filecontents: 0
+ masterDocument: 0
+ paragraphsStopAt:
+ environments: 1
+ verbatim: 1
+ commands: 0
+ ifElseFi: 0
+ items: 0
+ specialBeginEnd: 0
+ heading: 0
+ filecontents: 0
+ comments: 0
+ environments:
+ BeginStartsOnOwnLine: 0
+ BodyStartsOnOwnLine: 0
+ EndStartsOnOwnLine: 0
+ EndFinishesWithLineBreak: 0
+ equation*:
+ BeginStartsOnOwnLine: 0
+ BodyStartsOnOwnLine: 0
+ EndStartsOnOwnLine: 0
+ EndFinishesWithLineBreak: 0
+ ifElseFi:
+ IfStartsOnOwnLine: 0
+ BodyStartsOnOwnLine: 0
+ OrStartsOnOwnLine: 0
+ OrFinishesWithLineBreak: 0
+ ElseStartsOnOwnLine: 0
+ ElseFinishesWithLineBreak: 0
+ FiStartsOnOwnLine: 0
+ FiFinishesWithLineBreak: 0
+ ifnum:
+ IfStartsOnOwnLine: 0
+ BodyStartsOnOwnLine: 0
+ OrStartsOnOwnLine: 0
+ OrFinishesWithLineBreak: 0
+ ElseStartsOnOwnLine: 0
+ ElseFinishesWithLineBreak: 0
+ FiStartsOnOwnLine: 0
+ FiFinishesWithLineBreak: 0
+ commands:
+ CommandStartsOnOwnLine: 0
+ CommandNameFinishesWithLineBreak: 0
+ optionalArguments:
+ LSqBStartsOnOwnLine: 0
+ OptArgBodyStartsOnOwnLine: 0
+ RSqBStartsOnOwnLine: 0
+ RSqBFinishesWithLineBreak: 0
+ mandatoryArguments:
+ LCuBStartsOnOwnLine: 0
+ MandArgBodyStartsOnOwnLine: 0
+ RCuBStartsOnOwnLine: 0
+ RCuBFinishesWithLineBreak: 0
+ keyEqualsValuesBracesBrackets:
+ KeyStartsOnOwnLine: 0
+ EqualsStartsOnOwnLine: 0
+ EqualsFinishesWithLineBreak: 0
+ items:
+ ItemStartsOnOwnLine: 0
+ ItemFinishesWithLineBreak: 0
+ namedGroupingBracesBrackets:
+ NameStartsOnOwnLine: 0
+ NameFinishesWithLineBreak: 0
+ specialBeginEnd:
+ SpecialBeginStartsOnOwnLine: 0
+ SpecialBodyStartsOnOwnLine: 0
+ SpecialEndStartsOnOwnLine: 0
+ SpecialEndFinishesWithLineBreak: 0
+ verbatim:
+ VerbatimBeginStartsOnOwnLine: 0
+ VerbatimEndFinishesWithLineBreak: 0
+
+# replacements, only active when either -r or -rr switches are active
+replacements:
+ -
+ amalgamate: 1
+ -
+ this: 'latexindent.pl'
+ that: 'pl.latexindent'
+ lookForThis: 1
+ when: before
+
+# fineTuning allows you to tweak the internal pattern matching that
+# is central to latexindent.pl
+fineTuning:
+ environments:
+ name: '[a-zA-Z@\*0-9_\\]+'
+ ifElseFi:
+ name: '@?if[a-zA-Z@]*?'
+ commands:
+ name: '[+a-zA-Z@\*0-9_\:]+?'
+ keyEqualsValuesBracesBrackets:
+ name: '[a-zA-Z@\*0-9_\/.\h\{\}:\#-]+?'
+ follow: '(?:(?<!\\)\{)|,|(?:(?<!\\)\[)'
+ NamedGroupingBracesBrackets:
+ name: '[0-9\.a-zA-Z@\*><]+?'
+ follow: '\h|\R|\{|\[|\$|\)|\('
+ UnNamedGroupingBracesBrackets:
+ follow: '\{|\[|,|&|\)|\(|\$'
+ arguments:
+ before: '(?:#\d\h*;?,?\/?)+|\<.*?\>'
+ between: '_|\^|\*'
+ modifyLineBreaks:
+ betterFullStop: '(?:\.\)(?!\h*[a-z]))|(?:(?<!(?:(?:e\.g)|(?:i\.e)|(?:etc))))\.(?!(?:[a-z]|[A-Z]|\-|~|\,|[0-9]))'
+ doubleBackSlash: '\\\\(?:\h*\[\h*\d+\h*[a-zA-Z]+\h*\])?'
+ comma: ','
diff --git a/support/latexindent/documentation/appendices.tex b/support/latexindent/documentation/appendices.tex
new file mode 100644
index 0000000000..59037a5b24
--- /dev/null
+++ b/support/latexindent/documentation/appendices.tex
@@ -0,0 +1,247 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\appendix
+ \section{Required Perl modules}\label{sec:requiredmodules}
+ If you intend to use \texttt{latexindent.pl} and \emph{not} one of the
+ supplied standalone executable files, then you will need a few standard Perl modules --
+ if you can run the minimum code in \cref{lst:helloworld} (\texttt{perl helloworld.pl}) then you will be able to run
+ \texttt{latexindent.pl}, otherwise you may need to install the missing modules -- see
+ \cref{sec:module-installer,sec:manual-module-instal}.
+
+ \begin{cmhlistings}[style=tcblatex,language=Perl]{\texttt{helloworld.pl}}{lst:helloworld}
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use utf8;
+use PerlIO::encoding;
+use Unicode::GCString;
+use open ':std', ':encoding(UTF-8)';
+use Text::Wrap;
+use Text::Tabs;
+use FindBin;
+use YAML::Tiny;
+use File::Copy;
+use File::Basename;
+use File::HomeDir;
+use Getopt::Long;
+use Data::Dumper;
+use List::Util qw(max);
+use Log::Log4perl qw(get_logger :levels);
+
+print "hello world";
+exit;
+\end{cmhlistings}
+
+ \subsection{Module installer script}\label{sec:module-installer}
+ \announce{2018-01-13}{perl module helper script} \texttt{latexindent.pl} ships with a helper script that will
+ install any missing \texttt{perl} modules on your system; if you run
+ \begin{commandshell}
+perl latexindent-module-installer.pl
+\end{commandshell}
+ or
+ \begin{dosprompt}
+perl latexindent-module-installer.pl
+ \end{dosprompt}
+ then, once you have answered \texttt{Y}, the appropriate modules will be
+ installed onto your distribution.
+
+ \subsection{Manually installed modules}\label{sec:manual-module-instal}
+ Manually installing the modules given in \cref{lst:helloworld} will vary depending on
+ your operating system and \texttt{Perl} distribution. For example, Ubuntu users
+ might visit the software center, or else run
+ \begin{commandshell}
+sudo perl -MCPAN -e 'install "File::HomeDir"'
+\end{commandshell}
+
+ Linux users may be interested in exploring Perlbrew \cite{perlbrew}; possible
+ installation and setup options follow for Ubuntu (other distributions will need slightly
+ different commands).
+ \begin{commandshell}
+sudo apt-get install perlbrew
+perlbrew install perl-5.22.1
+perlbrew switch perl-5.22.1
+sudo apt-get install curl
+curl -L http://cpanmin.us | perl - App::cpanminus
+cpanm YAML::Tiny
+cpanm File::HomeDir
+cpanm Unicode::GCString
+cpanm Log::Log4perl
+cpanm Log::Dispatch
+\end{commandshell}
+
+ Users of the Macintosh operating system might like to explore the following commands, for
+ example:
+ \begin{commandshell}
+brew install perl
+brew install cpanm
+
+cpanm YAML::Tiny
+cpanm File::HomeDir
+cpanm Unicode::GCString
+cpanm Log::Log4perl
+cpanm Log::Dispatch
+\end{commandshell}
+
+ Strawberry Perl users on Windows might use \texttt{CPAN client}. All of the modules are
+ readily available on CPAN \cite{cpan}.
+
+ \texttt{indent.log} will contain details of the location
+ of the Perl modules on your system. \texttt{latexindent.exe} is a standalone executable
+ for Windows (and therefore does not require a Perl distribution) and caches copies of the
+ Perl modules onto your system; if you wish to see where they are cached, use the
+ \texttt{trace} option, e.g
+ \begin{dosprompt}
+latexindent.exe -t myfile.tex
+ \end{dosprompt}
+
+ \section{Updating the path variable}\label{sec:updating-path}
+ \texttt{latexindent.pl} has a few scripts (available at \cite{latexindent-home}) that can
+ update the \texttt{path} variables. Thank you to \cite{jasjuang} for this
+ feature. If you're on a Linux or Mac machine, then you'll want \texttt{CMakeLists.txt}
+ from \cite{latexindent-home}.
+ \subsection{Add to path for Linux}
+ To add \texttt{latexindent.pl} to the path for Linux, follow these steps:
+ \begin{enumerate}
+ \item download \texttt{latexindent.pl} and its associated modules, \texttt{defaultSettings.yaml}, to
+ your chosen directory from \cite{latexindent-home} ;
+ \item within your directory, create a directory called \texttt{path-helper-files} and download
+ \texttt{CMakeLists.txt} and \lstinline!cmake_uninstall.cmake.in! from
+ \cite{latexindent-home}/path-helper-files to this directory;
+ \item run
+ \begin{commandshell}
+ls /usr/local/bin
+\end{commandshell}
+ to see what is \emph{currently} in there;
+ \item run the following commands
+ \begin{commandshell}
+sudo apt-get install cmake
+sudo apt-get update && sudo apt-get install build-essential
+mkdir build && cd build
+cmake ../path-helper-files
+sudo make install
+\end{commandshell}
+ \item run
+ \begin{commandshell}
+ls /usr/local/bin
+\end{commandshell}
+ again to check that \texttt{latexindent.pl}, its modules and \texttt{defaultSettings.yaml} have
+ been added.
+ \end{enumerate}
+ To \emph{remove} the files, run
+ \begin{commandshell}
+sudo make uninstall
+\end{commandshell}
+ \subsection{Add to path for Windows}
+ To add \texttt{latexindent.exe} to the path for Windows, follow these steps:
+ \begin{enumerate}
+ \item download \texttt{latexindent.exe}, \texttt{defaultSettings.yaml}, \texttt{add-to-path.bat} from
+ \cite{latexindent-home} to your chosen directory;
+ \item open a command prompt and run the following command to see what is \emph{currently}
+ in your \lstinline!%path%! variable;
+ \begin{dosprompt}
+echo %path%
+ \end{dosprompt}
+ \item right click on \texttt{add-to-path.bat} and \emph{Run as administrator};
+ \item log out, and log back in;
+ \item open a command prompt and run
+ \begin{dosprompt}
+echo %path%
+ \end{dosprompt}
+ to check that the appropriate directory has been added to your \lstinline!%path%!.
+ \end{enumerate}
+ To \emph{remove} the directory from your \lstinline!%path%!, run
+ \texttt{remove-from-path.bat} as administrator.
+
+ \section{logFilePreferences}\label{app:logfile-demo}
+ \Vref{lst:logFilePreferences} describes the options for customising the information given
+ to the log file, and we provide a few demonstrations here. Let's say that we start with
+ the code given in \cref{lst:simple}, and the settings specified in
+ \cref{lst:logfile-prefs1-yaml}.
+
+ \begin{minipage}{.35\linewidth}
+ \cmhlistingsfromfile{demonstrations/simple.tex}{\texttt{simple.tex}}{lst:simple}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.6\linewidth}
+ \cmhlistingsfromfile{demonstrations/logfile-prefs1.yaml}[yaml-TCB]{\texttt{logfile-prefs1.yaml}}{lst:logfile-prefs1-yaml}
+ \end{minipage}
+
+ If we run the following command (noting that \texttt{-t} is active)
+ \begin{commandshell}
+latexindent.pl -t -l=logfile-prefs1.yaml simple.tex
+\end{commandshell}
+ then on inspection of \texttt{indent.log} we will find the snippet given in
+ \cref{lst:indentlog}.
+ \begin{cmhlistings}[style=tcblatex,morekeywords={TRACE}]{\texttt{indent.log}}{lst:indentlog}
+ +++++
+TRACE: environment found: myenv
+ No ancestors found for myenv
+ Storing settings for myenvenvironments
+ indentRulesGlobal specified (0) for environments, ...
+ Using defaultIndent for myenv
+ Putting linebreak after replacementText for myenv
+ looking for COMMANDS and key = {value}
+TRACE: Searching for commands with optional and/or mandatory arguments AND key = {value}
+ looking for SPECIAL begin/end
+TRACE: Searching myenv for special begin/end (see specialBeginEnd)
+TRACE: Searching myenv for optional and mandatory arguments
+ ... no arguments found
+ -----
+ \end{cmhlistings}
+ Notice that the information given about \texttt{myenv} is `framed' using
+ \texttt{+++++} and \lstinline!-----! respectively.
+
+ \section{Differences from Version 2.2 to 3.0}\label{app:differences}
+ There are a few (small) changes to the interface when comparing Version 2.2 to Version
+ 3.0. Explicitly, in previous versions you might have run, for example,
+ \begin{commandshell}
+latexindent.pl -o myfile.tex outputfile.tex
+\end{commandshell}
+ whereas in Version 3.0 you would run any of the following, for example,
+ \begin{commandshell}
+latexindent.pl -o=outputfile.tex myfile.tex
+latexindent.pl -o outputfile.tex myfile.tex
+latexindent.pl myfile.tex -o outputfile.tex
+latexindent.pl myfile.tex -o=outputfile.tex
+latexindent.pl myfile.tex -outputfile=outputfile.tex
+latexindent.pl myfile.tex -outputfile outputfile.tex
+\end{commandshell}
+ noting that the \emph{output} file is given \emph{next to} the
+ \texttt{-o} switch.
+
+ The fields given in \cref{lst:obsoleteYaml} are \emph{obsolete} from Version 3.0
+ onwards. \cmhlistingsfromfile{demonstrations/obsolete.yaml}[yaml-obsolete]{Obsolete YAML fields from Version 3.0}{lst:obsoleteYaml}
+
+ There is a slight difference when specifying indentation after headings; specifically, we
+ now write \texttt{indentAfterThisHeading} instead of \texttt{indent}. See
+ \cref{lst:indentAfterThisHeadingOld,lst:indentAfterThisHeadingNew}
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/indentAfterThisHeadingOld.yaml}[yaml-TCB]{\texttt{indentAfterThisHeading} in Version 2.2}{lst:indentAfterThisHeadingOld}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/indentAfterThisHeadingNew.yaml}[yaml-TCB]{\texttt{indentAfterThisHeading} in Version 3.0}{lst:indentAfterThisHeadingNew}
+ \end{minipage}%
+
+ To specify \texttt{noAdditionalIndent} for display-math environments in Version 2.2, you would
+ write YAML as in \cref{lst:noAdditionalIndentOld}; as of Version 3.0, you would write YAML as in
+ \cref{lst:indentAfterThisHeadingNew1} or, if you're using \texttt{-m} switch,
+ \cref{lst:indentAfterThisHeadingNew2}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/noAddtionalIndentOld.yaml}[yaml-TCB]{\texttt{noAdditionalIndent} in Version 2.2}{lst:noAdditionalIndentOld}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/noAddtionalIndentNew.yaml}[yaml-TCB]{\texttt{noAdditionalIndent} for \texttt{displayMath} in Version 3.0}{lst:indentAfterThisHeadingNew1}
+
+ \cmhlistingsfromfile{demonstrations/noAddtionalIndentNew1.yaml}[yaml-TCB]{\texttt{noAdditionalIndent} for \texttt{displayMath} in Version 3.0}{lst:indentAfterThisHeadingNew2}
+ \end{minipage}%
+
+ \mbox{}\hfill \begin{minipage}{.25\textwidth}
+ \hrule
+
+ \hfill\itshape End\\\mbox{}\hfill\mbox{}\rlap{\hfill\includegraphics{logo}}
+
+ \end{minipage}
diff --git a/support/latexindent/documentation/cmhlistings.tex b/support/latexindent/documentation/cmhlistings.tex
new file mode 100644
index 0000000000..1f058616d6
--- /dev/null
+++ b/support/latexindent/documentation/cmhlistings.tex
@@ -0,0 +1,28 @@
+\newcommand{\cmhlistingsfromfile}[4]{
+.. literalinclude:: #1^^J
+^^I:class: .#4^^J
+^^I:caption: #2^^J
+^^I:name: #3^^J
+}
+\newcommand{\cmhlistingsfromfilefour}[6]{
+.. literalinclude:: #3^^J
+^^I:class: .#6^^J
+^^I:caption: #4^^J
+^^I:name: #5^^J
+^^I:lines: #1-#2^^J
+^^I:linenos:^^J
+^^I:lineno-start: #1^^J
+}
+\newcommand{\cmhlabel}[1]{
+.. _#1:^^J
+}
+\newcommand{\warning}[1]{
+.. warning::^^J
+#1^^J
+.. endwarning::^^J
+}
+\newcommand{\example}[1]{
+.. proof:example::^^J
+#1^^J
+.. endproof:example::^^J
+}
diff --git a/support/latexindent/documentation/figure-schematic.tex b/support/latexindent/documentation/figure-schematic.tex
new file mode 100644
index 0000000000..911f85f6ad
--- /dev/null
+++ b/support/latexindent/documentation/figure-schematic.tex
@@ -0,0 +1,33 @@
+\documentclass{standalone}
+\usepackage{tikz}
+\usetikzlibrary{positioning}
+\begin{document}
+\begin{tikzpicture}[
+ needed/.style={very thick, draw=blue,fill=blue!20,
+ text centered, minimum height=2.5em,rounded corners=1ex},
+ optional/.style={draw=black, very thick,scale=0.8,
+ text centered, minimum height=2.5em,rounded corners=1ex},
+ optionalfill/.style={fill=black!10},
+ connections/.style={draw=black!30,dotted,line width=3pt,text=red},
+ ]
+ % Draw diagram elements
+ \node (latexindent) [needed,circle] {\texttt{latexindent.pl}};
+ \node (default) [needed,above right=.5cm of latexindent] {\texttt{defaultSettings.yaml}};
+ \node (indentconfig) [optional,right=of latexindent] {\texttt{indentconfig.yaml}};
+ \node (any) [optional,optionalfill,above right=of indentconfig] {\texttt{any.yaml}};
+ \node (name) [optional,optionalfill,right=of indentconfig] {\texttt{name.yaml}};
+ \node (you) [optional,optionalfill,below right=of indentconfig] {\texttt{you.yaml}};
+ \node (want) [optional,optionalfill,below=of indentconfig] {\texttt{want.yaml}};
+ \node (local) [optional,below=of latexindent] {\texttt{localSettings.yaml}};
+ \node (yamlswitch) [optional,left=of latexindent] {\texttt{-y switch}};
+ % Draw arrows between elements
+ \draw[connections,solid] (latexindent) to[in=-90]node[pos=0.5,anchor=north]{1} (default.south) ;
+ \draw[connections,optional] (latexindent) -- node[pos=0.5,anchor=north]{2} (indentconfig) ;
+ \draw[connections,optional] (indentconfig) to[in=-90] (any.south) ;
+ \draw[connections,optional] (indentconfig) -- (name) ;
+ \draw[connections,optional] (indentconfig) to[out=-45,in=90] (you) ;
+ \draw[connections,optional] (indentconfig) -- (want) ;
+ \draw[connections,optional] (latexindent) -- node[pos=0.5,anchor=west]{3} (local) ;
+ \draw[connections,optional] (latexindent) -- node[pos=0.5,anchor=north]{4} (yamlswitch) ;
+\end{tikzpicture}
+\end{document}
diff --git a/support/latexindent/documentation/latexindent.pdf b/support/latexindent/documentation/latexindent.pdf
new file mode 100644
index 0000000000..12a226e99d
--- /dev/null
+++ b/support/latexindent/documentation/latexindent.pdf
Binary files differ
diff --git a/support/latexindent/documentation/latexindent.tex b/support/latexindent/documentation/latexindent.tex
new file mode 100644
index 0000000000..775bd6a7d9
--- /dev/null
+++ b/support/latexindent/documentation/latexindent.tex
@@ -0,0 +1,777 @@
+% arara: pdflatex: {shell: yes}
+% arara: bibtex
+% arara: pdflatex: {shell: yes}
+% arara: pdflatex: {shell: yes}
+% arara: pdflatex: {shell: yes}
+\documentclass[10pt]{article}
+% 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/>.
+\usepackage[left=4.5cm,right=2.5cm,showframe=false,
+ top=2cm,bottom=1.5cm,marginparsep=2cm]{geometry} % page setup
+\usepackage{lmodern}
+\usepackage{parskip} % paragraph skips
+\usepackage{booktabs} % beautiful tables
+\usepackage{listings} % nice verbatim environments
+\usepackage{titlesec} % customize headings
+\usepackage{titletoc} % customize headings
+\usepackage{multicol}
+\usepackage{changepage} % adjust width of page
+\usepackage{fancyhdr} % headers & footers
+\usepackage{wrapfig}
+\usepackage{fontawesome}
+\usepackage[sc,format=hang,font=small]{caption} % captions
+\usepackage[backend=bibtex]{biblatex} % bibliography
+\usepackage{tcolorbox} % framed environments
+\usepackage{tikz}
+\usepackage{xparse}
+\usepackage[charter]{mathdesign} % changes font
+\usepackage[expansion=false,kerning=true]{microtype} % better kerning
+\usepackage{enumitem} % custom lists
+\usepackage{longtable}
+\usepackage{array}
+\usepackage{totalcount}
+\usepackage{standalone}
+% setup gitinfo2, as in the manual, details just above begin{document}
+\usepackage[mark,grumpy]{gitinfo2}
+% tikz, tcolorbox libraries
+\usetikzlibrary{positioning}
+\usetikzlibrary{decorations.pathmorphing}
+\usetikzlibrary{decorations,shapes}
+\usepackage{varioref} % the documentation library from tcolorbox loads hyperref
+\tcbuselibrary{breakable,minted,xparse,documentation,hooks,raster}
+\hypersetup{
+ pdfauthor={Chris Hughes},
+ pdftitle={latexindent.pl package},
+ pdfkeywords={perl;beautify;indentation},
+ bookmarksnumbered,
+ bookmarksopen,
+ linktocpage,
+ colorlinks=true,
+ linkcolor=blue,
+ citecolor=black,
+}
+\usepackage{cleveref}
+
+% create my own star style, for re-use at various points
+\tikzset{cmhstar/.style={star,star point ratio=2.25,fill=cmhgold,draw=orange,}}
+
+% shortcut command for displaying star in documentation
+\newcommand{\stardemo}[1][]{\begin{tikzpicture}
+ \node at (10:.1cm)[very thin,cmhstar,scale=0.25,rotate=20,#1]{};
+ \node at (120:.1cm)[very thin,cmhstar,scale=0.15,rotate=-10,#1]{};
+ \node at (235:.1cm)[very thin,cmhstar,scale=0.2,rotate=-20,#1]{};
+ \end{tikzpicture}}
+
+% totalcount
+\DeclareTotalCounter{lstlisting}
+
+% customise the \tcbdocnew command
+\tcbset{doclang/new={{\bfseries\color{green!50!black}N\normalfont\color{black}}}}
+\tcbset{doclang/updated={{\bfseries\color{green!50!black}U\normalfont\color{black}}}}
+\tcbset{doc marginnote={width=1.6cm}}
+\NewDocumentCommand{\announce}{ s m s m }{%
+ \IfBooleanTF{#1}%
+ {% \announce*
+ \tcbdocmarginnote[overlay={\node at ([yshift=0mm,xshift=1mm]frame.north east) {\stardemo}; }]{%
+ \IfBooleanTF{#3}%
+ {% \announce*{date}*[text] means *updated* as of <date>
+ \tcbdocupdated{#2}%
+ }%
+ {% \announce*{date}[text] means *new* as of <date>
+ \tcbdocnew{#2}%
+ }%
+ }%
+ \IfBooleanTF{#3}%
+ {%
+ \addcontentsline{new}{cmhtitle}{#4 (U)}%
+ }%
+ {%
+ \addcontentsline{new}{cmhtitle}{#4 (N)}%
+ }%
+ }%
+ {% \announce
+ \tcbdocmarginnote{%
+ \IfBooleanTF{#3}%
+ {% \announce{date}*[text] means *updated* as of <date>
+ \tcbdocupdated{#2}%
+ }%
+ {% \announce{date}[text] means *new* as of <date>
+ \tcbdocnew{#2}%
+ }%
+ }%
+ }}
+
+\reversemarginpar
+% bibliographies
+\addbibresource{latex-indent}
+\addbibresource{contributors}
+
+% http://tex.stackexchange.com/questions/122135/how-to-add-a-png-icon-on-the-right-side-of-a-tcolorbox-title
+\newtcolorbox{warning}{parbox=false,breakable,enhanced,arc=0mm,colback=red!5,colframe=red,leftrule=12mm,%
+ overlay={\node[anchor=north west,outer sep=2pt] at (frame.north west) {\includegraphics[width=8mm]{warning}}; }
+}
+
+\definecolor{harvestgold}{cmyk}{0.00, 0.05, 0.51, 0.07} %EDE275
+\definecolor{cmhgold}{cmyk}{0,0.178,0.909,0.008} %FDD017
+\colorlet{cmhgray}{gray!30!white}
+
+\makeatletter
+\tcbset{
+ addtolol/.style={list entry={\kvtcb@title},add to list={lol}{lstlisting}},
+ addtololstar/.style={list entry={\kvtcb@title},add to list={lol}{lstlistingstar}},
+ cmhlistings/.style={
+ % width=\linewidth,
+ %breakable,
+ colback=blue!5!white,
+ colframe=white!25!black,colback=white,
+ top=0cm,
+ bottom=0cm,
+ left=0mm,
+ listing only,
+ center title,
+ listing engine=minted,
+ minted style=colorful,
+ minted options={obeytabs=true,showtabs=true,tabsize=4,showspaces=true},
+ boxrule=0pt,
+ toprule=1pt,bottomrule=1pt,
+ titlerule=1pt,
+ colframe=white!40!black,
+ colback=white,
+ sharp corners,
+ colbacktitle=white!75!black
+ },
+ yaml-TCB/.style={
+ listing only,
+ listing engine=listings,
+ left=0cm,
+ boxrule=0pt,
+ sharp corners,
+ center title,
+ colbacktitle=white!75!blue,
+ colframe=white!25!blue,
+ colback=white!90!blue,
+ toprule=2pt,
+ titlerule=2pt,
+ },
+ MLB-TCB/.style={
+ yaml-TCB,
+ center title,
+ colframe=cmhgold,
+ colbacktitle=harvestgold,
+ colback=white!60!cmhgold,
+ width=0.9\linewidth,
+ before=\centering,
+ enhanced,
+ overlay={\node[anchor=north east,outer sep=2pt,draw=cmhgold,very thick,double,fill=harvestgold,font =\small] at ([yshift=-3mm]frame.north east) {\texttt{-m}}; }
+ },
+ replace-TCB/.style={
+ yaml-TCB,
+ center title,
+ colbacktitle=white!75!green,
+ colframe=white!25!green,
+ colback=white!90!green,
+ width=0.9\linewidth,
+ before=\centering,
+ enhanced,
+ overlay={\node[anchor=north east,outer sep=2pt,draw=white!25!green,very thick,circle,fill=white!75!green,font =\small] at ([yshift=-3mm]frame.north east) {\texttt{-r}}; }
+ },
+ yaml-obsolete/.style={
+ listing only,
+ listing engine=listings,
+ left=0cm,
+ boxrule=0pt,
+ sharp corners,
+ center title,
+ toprule=2pt,
+ titlerule=2pt,
+ colframe=white!25!red,
+ colbacktitle=white!75!red,
+ colback=white!90!red,
+ },
+ new-to-this-version/.style={
+ enhanced,
+ overlay app={\node at ([yshift=0mm,xshift=0mm]frame.north east) {\stardemo[scale=1.2]}; },
+ addtololstar,
+ },
+}
+
+\DeclareTCBListing[use counter=lstlisting]{cmhlistings}{s O{} m m}{%
+ cmhlistings,
+ IfBooleanTF={#1}{new-to-this-version}{addtolol},
+ center title,
+ title={\color{black}{\scshape Listing \thetcbcounter}: ~#3},label={#4},
+ listing engine=listings,
+ listing options={#2},
+}
+
+\DeclareDocumentEnvironment{cmhtcbraster}{O{}}{\begin{tcbraster}[
+ new-to-this-version/.style={
+ enhanced,
+ overlay app={\node[anchor=south east] at ([yshift=-3mm,xshift=3mm]frame.north east) {\stardemo[scale=1.2]}; },
+ addtololstar,
+ },
+ raster valign=top,raster columns=2,#1]}{\end{tcbraster}}
+
+% \cmhlistingsfromfile
+% * no star: not new, star: new
+% [ listing/minted options ]
+% * no star: uses minted library, star: uses listings library star:
+% {<name of listing file>}
+% [<options for tcolorbox>]
+% {<title>}
+% {<label>}
+%
+% for example,
+% \cmhlistingsfromfile*[listing options]... uses listings library and is NEW
+% \cmhlistingsfromfile[listing options]... uses listings library
+% \cmhlistingsfromfile[listing options]*... uses minted library
+% \cmhlistingsfromfile*[listing options]*... uses minted library and is NEW
+\DeclareTCBInputListing[use counter=lstlisting]{\cmhlistingsfromfile}{s O{} s m O{} m m}{%
+ cmhlistings,
+ listing file={#4},
+ IfBooleanTF={#3}{listing options={style=tcblatex,showspaces=false,#2}}{minted options={obeytabs=true,showtabs=false,tabsize=4,showspaces=false,#2}},
+ title={\color{black}{\scshape Listing \thetcbcounter}: ~#6},label={#7},
+ #5,
+ IfBooleanTF={#1}{new-to-this-version}{addtolol},
+}
+
+\makeatletter
+\@tempswafalse
+\def\@tempa{draft}
+\@for\next:=\@classoptionslist\do
+{\ifx\next\@tempa\@tempswatrue\fi}
+\if@tempswa % draft option is active
+ \RenewDocumentCommand{\cmhlistingsfromfile}{s O{} s m O{} m m}{\captionof{lstlisting}{#6}\label{#7}}
+ \renewcommand{\stardemo}[1][]{$\star$}
+\fi
+
+% command shell
+\newtcblisting{commandshell}{colback=black,colupper=white,colframe=yellow!75!black,
+ listing only,listing options={style=tcblatex,language=sh,
+ morekeywords={latexindent,pl},
+ keywordstyle=\color{blue!35!white}\bfseries,
+ },
+ listing engine=listings,
+ left=0cm,
+ every listing line={\textcolor{red}{\small\ttfamily\fontseries{b}\selectfont cmh:$\sim$\$ }}}
+
+% dosprompt
+\newtcblisting{dosprompt}{
+ colback=black,
+ colupper=white,
+ colframe=yellow!75!black,
+ listing only,
+ listing options={
+ language=command.com,
+ morekeywords={latexindent,pl},
+ keywordstyle=\color{blue!35!white}\bfseries,
+ basicstyle=\small\color{white}\ttfamily
+ },
+ listing engine=listings,
+ left=0cm,
+ every listing line={\textcolor{white}{\small\ttfamily\fontseries{b}\selectfont C:\textbackslash Users\textbackslash cmh$>$}}}
+
+\lstset{%
+ basicstyle=\small\ttfamily,language={[LaTeX]TeX},
+ numberstyle=\ttfamily%\small,
+ breaklines=true,
+ keywordstyle=\color{blue}, % keywords
+ commentstyle=\color{purple}, % comments
+ tabsize=3,
+}%
+\DeclareTCBListing[use counter=lstlisting]{yaml}{O{} m O{} m}{
+ yaml-TCB,
+ listing options={
+ style=tcblatex,
+ numbers=none,
+ numberstyle=\color{red},
+ #1,
+ },
+ title={\color{black}{\scshape Listing \thetcbcounter}: ~#2},label={#4},
+ #3,
+}
+
+\lstdefinestyle{yaml-LST}{
+ style=tcblatex,
+ numbers=none,
+ numberstyle=\color{red},
+}
+
+\lstdefinestyle{demo}{
+ numbers=none,
+ linewidth=1.25\textwidth,
+ columns=fullflexible,
+}
+
+\lstdefinestyle{fileExtensionPreference}{
+ style=yaml-LST,
+ firstnumber=41,linerange={41-45},
+ numbers=left,
+}
+
+\lstdefinestyle{logFilePreferences}{
+ style=yaml-LST,
+ firstnumber=85,linerange={85-95},
+ numbers=left,
+}
+
+\lstdefinestyle{verbatimEnvironments}{
+ style=yaml-LST,
+ firstnumber=99,linerange={99-102},
+ numbers=left,
+}
+
+\lstdefinestyle{verbatimCommands}{
+ style=yaml-LST,
+ firstnumber=105,linerange={105-107},
+ numbers=left,
+}
+
+\lstdefinestyle{noIndentBlock}{
+ style=yaml-LST,
+ firstnumber=112,linerange={112-114},
+ numbers=left,
+}
+
+\lstdefinestyle{removeTrailingWhitespace}{
+ style=yaml-LST,
+ firstnumber=117,linerange={117-119},
+ numbers=left,
+}
+
+\lstdefinestyle{fileContentsEnvironments}{
+ style=yaml-LST,
+ firstnumber=123,linerange={123-125},
+ numbers=left,
+}
+
+\lstdefinestyle{lookForPreamble}{
+ style=yaml-LST,
+ firstnumber=131,linerange={131-135},
+ numbers=left,
+}
+
+\lstdefinestyle{indentAfterItems}{
+ style=yaml-LST,
+ firstnumber=187,linerange={187-191},
+ numbers=left,
+}
+
+\lstdefinestyle{itemNames}{
+ style=yaml-LST,
+ firstnumber=197,linerange={197-199},
+ numbers=left,
+}
+
+\lstdefinestyle{specialBeginEnd}{
+ style=yaml-LST,
+ firstnumber=203,linerange={203-216},
+ numbers=left,
+}
+
+\lstdefinestyle{indentAfterHeadings}{
+ style=yaml-LST,
+ firstnumber=226,linerange={226-235},
+ numbers=left,
+}
+
+\lstdefinestyle{noAdditionalIndentGlobalEnv}{
+ style=yaml-LST,
+ firstnumber=284,linerange={284-285},
+ numbers=left,
+}
+
+\lstdefinestyle{noAdditionalIndentGlobal}{
+ style=yaml-LST,
+ firstnumber=284,linerange={284-296},
+ numbers=left,
+}
+
+\lstdefinestyle{indentRulesGlobalEnv}{
+ style=yaml-LST,
+ firstnumber=300,linerange={300-301},
+ numbers=left,
+}
+
+\lstdefinestyle{indentRulesGlobal}{
+ style=yaml-LST,
+ firstnumber=300,linerange={300-312},
+ numbers=left,
+}
+
+\lstdefinestyle{commandCodeBlocks}{
+ style=yaml-LST,
+ firstnumber=315,linerange={315-329},
+ numbers=left,
+}
+
+\lstdefinestyle{modifylinebreaks}{
+ style=yaml-LST,
+ firstnumber=441,linerange={441-443},
+ numbers=left,
+}
+
+\lstdefinestyle{textWrapOptions}{
+ style=yaml-LST,
+ firstnumber=468,linerange={468-469},
+ numbers=left,
+}
+
+\lstdefinestyle{textWrapOptionsAll}{
+ style=yaml-LST,
+ firstnumber=468,linerange={468-484},
+ numbers=left,
+}
+
+\lstdefinestyle{removeParagraphLineBreaks}{
+ style=yaml-LST,
+ firstnumber=485,linerange={485-499},
+ numbers=left,
+}
+
+\lstdefinestyle{paragraphsStopAt}{
+ style=yaml-LST,
+ firstnumber=500,linerange={500-509},
+ numbers=left,
+}
+
+\lstdefinestyle{oneSentencePerLine}{
+ style=yaml-LST,
+ firstnumber=444,linerange={444-467},
+ numbers=left,
+}
+
+\lstdefinestyle{sentencesFollow}{
+ style=yaml-LST,
+ firstnumber=449,linerange={449-457},
+ numbers=left,
+}
+
+\lstdefinestyle{sentencesBeginWith}{
+ style=yaml-LST,
+ firstnumber=458,linerange={458-461},
+ numbers=left,
+}
+
+\lstdefinestyle{sentencesEndWith}{
+ style=yaml-LST,
+ firstnumber=462,linerange={462-467},
+ numbers=left,
+}
+
+\lstdefinestyle{modifylinebreaksEnv}{
+ style=yaml-LST,
+ firstnumber=510,linerange={510-519},
+ numbers=left,
+}
+
+\lstdefinestyle{replacements}{
+ style=yaml-LST,
+ firstnumber=571,linerange={571-579},
+ numbers=left,
+}
+
+\lstdefinestyle{fineTuning}{
+ style=yaml-LST,
+ firstnumber=582,linerange={582-603},
+ numbers=left,
+}
+
+% stars around contributors
+\pgfdeclaredecoration{stars}{initial}{
+ \state{initial}[width=15pt]
+ {
+ \pgfmathparse{round(rnd*100)}
+ \pgfsetfillcolor{yellow!\pgfmathresult!orange}
+ \pgfsetstrokecolor{yellow!\pgfmathresult!red}
+ \pgfnode{star}{center}{}{}{\pgfusepath{stroke,fill}}
+ }
+ \state{final}
+ {
+ \pgfpathmoveto{\pgfpointdecoratedpathlast}
+ }
+}
+
+\newtcolorbox{stars}{%
+ enhanced jigsaw,
+ breakable, % allow page breaks
+ left=0cm,
+ top=0cm,
+ before skip=0.2cm,
+ boxsep=0cm,
+ frame style={draw=none,fill=none}, % hide the default frame
+ colback=white,
+ overlay={
+ \draw[inner sep=0,minimum size=rnd*15pt+2pt]
+ decorate[decoration={stars,segment length=2cm}] {
+ decorate[decoration={zigzag,segment length=2cm,amplitude=0.3cm}] {
+ ([xshift=-.5cm,yshift=0.1cm]frame.south west) -- ([xshift=-.5cm,yshift=0.4cm]frame.north west)
+ }};
+ \draw[inner sep=0,minimum size=rnd*15pt+2pt]
+ decorate[decoration={stars,segment length=2cm}] {
+ decorate[decoration={zigzag,segment length=2cm,amplitude=0.3cm}] {
+ ([xshift=.75cm,yshift=0.1cm]frame.south east) -- ([xshift=.75cm,yshift=0.6cm]frame.north east)
+ }};
+ \node[anchor=north west,outer sep=2pt,opacity=0.25] at ([xshift=-4.25cm]frame.north west) {\resizebox{3cm}{!}{\faGithub}};
+ },
+ % paragraph skips obeyed within tcolorbox
+ parbox=false,
+}
+
+\newtcolorbox[auto counter]{example}{breakable,
+ enhanced jigsaw,
+ before skip=6pt,after skip=6pt,
+ frame hidden,
+ title={\llap{Example~\thetcbcounter\hspace{3mm}}},
+ fonttitle=\bfseries,
+ coltitle=black,
+ attach title to upper,
+ grow to left by=5mm,
+ top=3mm,
+ overlay unbroken={%
+ \draw[thick,cmhgray] ([xshift=3mm]interior.north east)--([xshift=3mm]interior.south east);
+ \path [fill=cmhgray] ([xshift=3mm]interior.north east) circle (.5mm);
+ \path [fill=cmhgray] ([xshift=3mm]interior.south east) circle (1mm);
+ },
+ overlay first={%
+ \draw[thick,cmhgray] ([xshift=3mm]interior.north east)--([xshift=3mm]interior.south east);
+ \path [fill=cmhgray] ([xshift=3mm]interior.north east) circle (.5mm);
+ %\path [draw=cmhgray,fill=white] ([xshift=3mm]interior.south east) circle (.5mm);
+ },
+ overlay last={%
+ \draw[thick,cmhgray] ([xshift=3mm]interior.north east)--([xshift=3mm]interior.south east);
+ %\path [fill=white,draw=cmhgray] ([xshift=3mm]interior.north east) circle (.5mm);
+ \path [fill=cmhgray] ([xshift=3mm]interior.south east) circle (1mm);
+ },
+ parbox=false,
+}
+
+% copied from /usr/local/texlive/2013/texmf-dist/tex/latex/biblatex/bbx/numeric.bbx
+% the only modification is the \stars and \endstars
+\defbibenvironment{specialbib}
+{\stars\list
+ {\printtext[labelnumberwidth]{%
+ \printfield{prefixnumber}%
+ \printfield{labelnumber}}}
+ {\setlength{\labelwidth}{\labelnumberwidth}%
+ \setlength{\leftmargin}{\labelwidth}%
+ \setlength{\labelsep}{\biblabelsep}%
+ \addtolength{\leftmargin}{\labelsep}%
+ \setlength{\itemsep}{\bibitemsep}%
+ \setlength{\parsep}{\bibparsep}}%
+ \renewcommand*{\makelabel}[1]{\hss##1}}
+{\endlist\endstars}
+{\item}
+
+\newtcbox{yamltitlebox}[1][]{colframe=black!50!white,boxrule=.5pt,sharp corners,#1}
+
+\newcommand{\flagbox}[1]{%
+ \par
+ \makebox[30pt][l]{%
+ \hspace{-1cm}%
+ \ttfamily\fontseries{b}\selectfont #1
+ }%
+}
+
+\NewDocumentCommand{\yamltitle}{O{} m s m}{%
+ \par
+ \makebox[30pt][l]{%
+ \hspace{-2cm}%
+ \yamltitlebox[#1]{%
+ {\ttfamily\fontseries{b}\selectfont{\color{blue!80!white}#2}}: %
+ \IfBooleanTF{#3}
+ {$\langle$\itshape #4$\rangle$}
+ {{\bfseries #4}}
+ }}
+ \par\nobreak%
+}
+
+\newcommand{\fixthis}[1]
+{%
+ \marginpar{\huge \color{red} \framebox{FIX}}%
+ \typeout{FIXTHIS: p\thepage : #1^^J}%
+}
+% custom section
+\titleformat{\section}
+{\normalfont\Large\bfseries}
+{\llap{\thesection\hskip.5cm}}
+{0pt}
+{}
+
+\newcommand*\ruleline[1]{%
+ \par\noindent\raisebox{.8ex}{\makebox[\linewidth]{\hrulefill\hspace{1ex}\raisebox{-1.8ex}{#1}\hspace{1ex}\hrulefill}}}
+
+\newcommand{\imagetouse}{logo-bw}
+
+\titleformat% Formatting the header
+{\section} % command
+[block] % shape - Only managed to get it working with block
+{\normalfont\bfseries\huge} % format - Change here as needed
+{\centering {\scshape Section \thesection}\\} % the section
+{0pt} % sep
+{\centering \ruleline{\includegraphics{\imagetouse}}\\ % The horizontal rule
+ \centering} % And the actual title
+
+% custom subsection
+\titleformat{\subsection}
+{\normalfont\bfseries}
+{\llap{\thesubsection\hskip.5cm}}
+{0pt}
+{}
+% custom subsubsection
+\titleformat{\subsubsection}
+{\normalfont\bfseries}
+{\llap{\thesubsubsection\hskip.5cm}}
+{0pt}
+{}
+
+\titlespacing\section{0pt}{12pt plus 4pt minus 2pt}{34pt plus 2pt minus 2pt}
+\titlespacing\subsection{0pt}{12pt plus 4pt minus 2pt}{4pt plus 2pt minus 2pt}
+\titlespacing\subsubsection{0pt}{12pt plus 4pt minus 2pt}{4pt plus 2pt minus 2pt}
+
+% list of listings
+\contentsuse{lstlisting}{lol}
+\titleclass{\lstlistingstar}{straight}[\section]
+\titleformat{\lstlistingstar}{}{}{}{}
+\titlecontents{lstlistingstar}[2em]
+ {\addvspace{0.25pc}}
+ {}
+ {\llap{\stardemo}\thecontentslabel}
+ {\titlerule*[0.5em]{$\cdot$}\contentspage}
+ []
+\titlecontents{lstlisting}[2em]
+ {\addvspace{0.25pc}}
+ {\thecontentslabel}
+ {\thecontentslabel}
+ {\titlerule*[0.5em]{$\cdot$}\contentspage}
+ []
+\AtBeginDocument{\addtocontents{lol}{\protect\begin{widepage}\protect\begin{multicols}{2}}}
+\AtEndDocument{\addtocontents{lol}{\protect\end{multicols}\protect\end{widepage}}}
+
+% cleveref settings
+\crefname{table}{Table}{Tables}
+\Crefname{table}{Table}{Tables}
+\crefname{figure}{Figure}{Figures}
+\Crefname{figure}{Figure}{Figures}
+\crefname{section}{Section}{Sections}
+\Crefname{section}{Section}{Sections}
+\crefname{listing}{Listing}{Listings}
+\Crefname{listing}{Listing}{Listings}
+
+% headers and footers
+\fancyhf{} % delete current header and footer
+\fancyhead[R]{\bfseries\thepage%
+ \tikz[remember picture,overlay] {
+ \node at (1,0){\includegraphics{logo-bw}}; }
+}
+\fancyhead[L]{\rightmark}
+\fancyheadoffset[L]{3cm}
+\pagestyle{fancy}
+
+% renew plain style
+\fancypagestyle{plain}{%
+ \fancyhf{} % clear all header and footer fields
+ \renewcommand{\headrulewidth}{0pt}
+ \renewcommand{\footrulewidth}{0pt}}
+
+% widepage environment
+\newenvironment{widepage}{\begin{adjustwidth}{-3cm}{0cm}}{\end{adjustwidth}}
+
+% symbols for the m switch
+\newcommand{\BeginStartsOnOwnLine}{\color{red}\spadesuit}
+\newcommand{\BodyStartsOnOwnLine}{\color{red}\heartsuit}
+\newcommand{\EndStartsOnOwnLine}{\color{red}\diamondsuit}
+\newcommand{\EndFinishesWithLineBreak}{\color{red}\clubsuit}
+\newcommand{\ElseStartsOnOwnLine}{\color{red}\bigstar}
+\newcommand{\ElseFinishesWithLineBreak}{\color{red}\square}
+\newcommand{\OrStartsOnOwnLine}{\color{red}\blacktriangle}
+\newcommand{\OrFinishesWithLineBreak}{\color{red}\blacktriangledown}
+\newcommand{\EqualsStartsOnOwnLine}{\color{red}\bullet}
+
+% table rules
+\setlength\heavyrulewidth{0.25ex}
+% gitinfo2 settings
+\renewcommand{\gitMark}{\gitBranch\,@\,\gitAbbrevHash{}\,\textbullet{}\,\gitAuthorDate\,\textbullet{}\faGithub\,\textbullet{}\gitRel}
+
+% setting up gitinfo2:
+% copy the file post-xxx-sample.txt from http://mirror.ctan.org/macros/latex/contrib/gitinfo2
+% and put it in .git/hooks/post-checkout
+% then
+% cd .git/hooks
+% chmod g+x post-checkout
+% chmod +x post-checkout
+% cp post-checkout post-commit
+% cp post-checkout post-merge
+% cd ../..
+% git checkout master
+% git checkout develop
+% ls .git
+% and you should see gitHeadInfo.gin
+%
+% Make sure that the 'V' is included in the below!
+%
+% RELTAG=$(git describe --tags --long --always --dirty='-*' --match 'V[0-9]*.*' 2>/dev/null)
+
+% http://tex.stackexchange.com/questions/233843/textasteriskcentered-invisible-with-garamondmathdesign
+% remove the definition of \textasteriskcentered for TS1 encoding
+\UndeclareTextCommand{\textasteriskcentered}{TS1}
+% reinstate a default encoding
+\DeclareTextSymbolDefault{\textasteriskcentered}{OT1}
+% suitably define the command
+\DeclareTextCommand{\textasteriskcentered}{OT1}{\raisebox{-.7ex}[1ex][0pt]{*}}
+
+% new features list
+\newcommand{\listOfNewFeatures}{\setcounter{tocdepth}{4}\@starttoc{new}}
+\contentsuse{cmhtitle}{new}
+% toc settings
+\titleclass{\cmhtitle}{straight}[\subsection]
+\titleformat{\cmhtitle}{}{}{}{}
+\titlecontents{cmhtitle}% <paragaph>
+ [2cm]% <left>
+ {\small\itshape}% <above-code>
+ {}% <numbered-entry-format>; you could also use {\thecontentslabel. } to show the numbers
+ {}% <numberless-entry-format>
+ {\titlerule*[0.5em]{$\cdot$}\contentspage}
+
+\setcounter{secnumdepth}{5}
+\begin{document}
+\renewcommand*{\thefootnote}{\arabic{footnote}}
+\input{title.tex}
+\tableofcontents
+{\small\lstlistoflistings}
+% start sections on new page
+\newcommand{\sectionbreak}{\clearpage\thispagestyle{plain}}
+ \input{sec-introduction}
+ \input{sec-demonstration}
+ \input{sec-how-to-use}
+ \input{sec-indent-config-and-settings.tex}
+ \input{sec-default-user-local}
+ \input{subsec-noAdditionalIndent-indentRules}
+ \input{subsubsec-environments-and-their-arguments}
+ \input{subsubsec-environments-with-items}
+ \input{subsubsec-commands-with-arguments}
+ \input{subsubsec-ifelsefi}
+ \input{subsubsec-special}
+ \input{subsubsec-headings}
+ \input{subsubsec-no-add-remaining-code-blocks}
+ \stopcontents[noAdditionalIndent]
+ \input{subsec-commands-and-their-options}
+ \input{sec-the-m-switch}
+ \stopcontents[the-m-switch]
+ \input{subsec-partnering-poly-switches}
+ \input{subsec-conflicting-poly-switches}
+ \input{sec-replacements}
+ \input{sec-fine-tuning}
+ \input{sec-conclusions-know-limitations}
+ \input{references}
+ \input{appendices}
+\end{document}
diff --git a/support/latexindent/documentation/logo.tex b/support/latexindent/documentation/logo.tex
new file mode 100644
index 0000000000..5bc31e0a4f
--- /dev/null
+++ b/support/latexindent/documentation/logo.tex
@@ -0,0 +1,33 @@
+% arara: pdflatex
+%
+% to create the black and white logo:
+% convert -density 1000 -colorspace GRAY logo.pdf logo-bw.pdf
+\documentclass[border=1mm]{standalone}
+
+\usepackage{tikz}
+\usetikzlibrary{matrix}
+\definecolor{harvestgold}{cmyk}{0.00, 0.05, 0.51, 0.07} %EDE275
+\definecolor{cmhgold}{cmyk}{0,0.178,0.909,0.008} %FDD017
+\definecolor{bakeoffblue}{cmyk}{0.24, 0.00, 0.02, 0.18} %9fd2cd
+\definecolor{bakeoffgreen}{cmyk}{0.30, 0.00, 0.20, 0.29} %80b692
+\definecolor{burntorange}{cmyk}{0.00, 0.41, 1.00, 0.04}
+\begin{document}
+\begin{tikzpicture}[logo/.style={draw=blue,circle,fill=white}]
+ \matrix{
+ \node[logo,dash pattern=on .5pt off 1.0pt,thick,draw=purple!75!white]{}; & \node[logo,draw=burntorange]{}; \\
+ \node[logo,fill,draw=bakeoffgreen,fill=bakeoffblue]{}; & \node[logo,double,draw=cmhgold,fill=harvestgold]{};\\};
+\end{tikzpicture}
+\end{document}
+
+% for reference, the following puts the GitHub logo in the background; also needs
+% \usetikzlibrary{backgrounds}
+\pagecolor{white}
+\begin{tikzpicture}[logo/.style={draw=blue,circle,fill=none,fill opacity=0.75}]
+ \matrix{%
+ \node[logo,dash pattern=on .5pt off 1.0pt,thick,draw=purple!75!white]{}; & \node[logo,draw=burntorange]{}; \\
+ \node[logo,fill,draw=bakeoffgreen,fill=bakeoffblue]{}; & \node[logo,double,draw=cmhgold,fill=harvestgold]{};\\};
+ \begin{scope}[on background layer]
+ %\node [yshift=0.01em,xshift=0.07em] {\resizebox{1cm}{!}{\color{gray!50!white}\faGithub}};
+ \node {\resizebox{1cm}{!}{\color{gray!25!white}\faGithub}};
+ \end{scope}
+\end{tikzpicture}
diff --git a/support/latexindent/documentation/references.tex b/support/latexindent/documentation/references.tex
new file mode 100644
index 0000000000..548b394578
--- /dev/null
+++ b/support/latexindent/documentation/references.tex
@@ -0,0 +1,4 @@
+\nocite{*}
+\section{References}
+ \printbibliography[heading=subbibnumbered,title={External links},notkeyword=contributor]
+ \printbibliography[env=specialbib,heading=subbibnumbered,title={Contributors\label{sec:contributors}},keyword=contributor]
diff --git a/support/latexindent/documentation/sec-conclusions-know-limitations.tex b/support/latexindent/documentation/sec-conclusions-know-limitations.tex
new file mode 100644
index 0000000000..1e865c9c84
--- /dev/null
+++ b/support/latexindent/documentation/sec-conclusions-know-limitations.tex
@@ -0,0 +1,38 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\section{Conclusions and known limitations}\label{sec:knownlimitations}
+ There are a number of known limitations of the script, and almost certainly quite a few
+ that are \emph{unknown}!
+
+ The main limitation is to do with the alignment routine discussed on
+ \cpageref{yaml:lookforaligndelims}; for example, consider the file given in \cref{lst:matrix2}.
+
+ \cmhlistingsfromfile{demonstrations/matrix2.tex}{\texttt{matrix2.tex}}{lst:matrix2}
+
+ The default output is given in \cref{lst:matrix2-default}, and it is clear that the alignment
+ routine has not worked as hoped, but it is \emph{expected}. \cmhlistingsfromfile{demonstrations/matrix2-default.tex}{\texttt{matrix2.tex} default output}{lst:matrix2-default}
+
+ The reason for the problem is that when \texttt{latexindent.pl} stores its code blocks
+ (see \vref{tab:code-blocks}) it uses replacement tokens. The alignment routine is using
+ the \emph{length of the replacement token} in its measuring -- I hope to be able to address this in the
+ future.
+
+ There are other limitations to do with the multicolumn alignment routine (see
+ \vref{lst:tabular2-mod2}); in particular, when working with code blocks in which
+ multicolumn commands overlap, the algorithm can fail.
+
+ Another limitation is to do with efficiency, particularly when the \texttt{-m}
+ switch is active, as this adds many checks and processes. The current implementation
+ relies upon finding and storing \emph{every} code block (see the discussion on
+ \cpageref{page:phases}); it is hoped that, in a future version, only
+ \emph{nested} code blocks will need to be stored in the `packing' phase, and
+ that this will improve the efficiency of the script.
+
+ You can run \texttt{latexindent} on any file;%
+ \announce*{2019-07-13}*{ability to call latexindent on any file} if you don't specify an extension, then the extensions that you
+ specify in \lstinline[breaklines=true]!fileExtensionPreference! (see \vref{lst:fileExtensionPreference}) will be consulted. If you
+ find a case in which the script struggles, please feel free to report it at
+ \cite{latexindent-home}, and in the meantime, consider using a \texttt{noIndentBlock} (see \cpageref{lst:noIndentBlockdemo}).
+
+ I hope that this script is useful to some; if you find an example where the script does
+ not behave as you think it should, the best way to contact me is to report an issue on
+ \cite{latexindent-home}; otherwise, feel free to find me on the \url{http://tex.stackexchange.com/users/6621/cmhughes}.
diff --git a/support/latexindent/documentation/sec-default-user-local.tex b/support/latexindent/documentation/sec-default-user-local.tex
new file mode 100644
index 0000000000..2a657fae8a
--- /dev/null
+++ b/support/latexindent/documentation/sec-default-user-local.tex
@@ -0,0 +1,737 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\section{defaultSettings.yaml}\label{sec:defuseloc}
+ \texttt{latexindent.pl} loads its settings from \texttt{defaultSettings.yaml}. The idea is to
+ separate the behaviour of the script from the internal working -- this is very similar to
+ the way that we separate content from form when writing our documents in \LaTeX.
+
+ If you look in \texttt{defaultSettings.yaml} you'll find the switches that govern the behaviour
+ of \texttt{latexindent.pl}. If you're not sure where \texttt{defaultSettings.yaml} resides on
+ your computer, don't worry as \texttt{indent.log} will tell you where to find it.
+ \texttt{defaultSettings.yaml} is commented, but here is a description of what each switch is
+ designed to do. The default value is given in each case; whenever you see
+ \emph{integer} in \emph{this} section, assume that it must be
+ greater than or equal to \texttt{0} unless otherwise stated.
+
+\yamltitle{fileExtensionPreference}*{fields}
+ \texttt{latexindent.pl} can be called to
+ act on a file without specifying the file extension. For example we can call
+ \begin{commandshell}
+latexindent.pl myfile
+\end{commandshell}
+ \begin{wrapfigure}[8]{r}[0pt]{6cm}
+ \cmhlistingsfromfile[style=fileExtensionPreference]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{fileExtensionPreference}}{lst:fileExtensionPreference}
+ \end{wrapfigure}
+
+ in which case the script will look for \texttt{myfile} with the extensions
+ specified in \texttt{fileExtensionPreference} in their numeric order. If no match is found, the
+ script will exit. As with all of the fields, you should change and/or add to this as
+ necessary.
+
+ Calling \texttt{latexindent.pl myfile} with the (default) settings specified in
+ \cref{lst:fileExtensionPreference} means that the script will first look for
+ \texttt{myfile.tex}, then \texttt{myfile.sty}, \texttt{myfile.cls}, and
+ finally \texttt{myfile.bib} in order\footnote{Throughout this manual, listings shown with line numbers represent code
+ taken directly from \texttt{defaultSettings.yaml}.}.
+
+\yamltitle{backupExtension}*{extension name}
+
+ If you call \texttt{latexindent.pl} with the \texttt{-w} switch (to overwrite
+ \texttt{myfile.tex}) then it will create a backup file before doing any indentation;
+ the default extension is \texttt{.bak}, so, for example,
+ \texttt{myfile.bak0} would be created when calling \texttt{latexindent.pl myfile.tex} for the
+ first time.
+
+ By default, every time you subsequently call \texttt{latexindent.pl} with the
+ \texttt{-w} to act upon \texttt{myfile.tex}, it will create successive
+ back up files: \texttt{myfile.bak1}, \texttt{myfile.bak2}, etc.
+
+\yamltitle{onlyOneBackUp}*{integer}
+ \label{page:onlyonebackup}
+ If you don't want a backup for every time that you call \texttt{latexindent.pl} (so
+ you don't want \texttt{myfile.bak1}, \texttt{myfile.bak2}, etc) and you
+ simply want \texttt{myfile.bak} (or whatever you chose \texttt{backupExtension} to be) then change \texttt{onlyOneBackUp} to
+ \texttt{1}; the default value of \texttt{onlyOneBackUp} is
+ \texttt{0}.
+
+\yamltitle{maxNumberOfBackUps}*{integer}
+ Some users may only want a finite number of backup files, say at most
+ $3$, in which case, they can change this switch. The smallest value of
+ \texttt{maxNumberOfBackUps} is $0$ which will \emph{not}
+ prevent backup files being made; in this case, the behaviour will be dictated entirely by
+ \texttt{onlyOneBackUp}. The default value of \texttt{maxNumberOfBackUps} is
+ \texttt{0}.
+
+\yamltitle{cycleThroughBackUps}*{integer}
+ Some users may wish to cycle through backup files, by deleting the oldest backup file and
+ keeping only the most recent; for example, with \texttt{maxNumberOfBackUps: 4}, and
+ \texttt{cycleThroughBackUps} set to \texttt{1} then the \texttt{copy}
+ procedure given below would be obeyed.
+
+ \begin{commandshell}
+copy myfile.bak1 to myfile.bak0
+copy myfile.bak2 to myfile.bak1
+copy myfile.bak3 to myfile.bak2
+copy myfile.bak4 to myfile.bak3
+\end{commandshell}
+ The default value of \texttt{cycleThroughBackUps} is \texttt{0}.
+
+\yamltitle{logFilePreferences}*{fields}
+ \texttt{latexindent.pl} writes information to \texttt{indent.log}, some
+ of which can be customized by changing \texttt{logFilePreferences}; see
+ \cref{lst:logFilePreferences}. If you load your own user settings (see \vref{sec:indentconfig})
+ then \texttt{latexindent.pl} will detail them in \texttt{indent.log}; you can choose
+ not to have the details logged by switching \texttt{showEveryYamlRead} to
+ \texttt{0}. Once all of your settings have been loaded, you can see the
+ amalgamated settings in the log file by switching \texttt{showAmalgamatedSettings} to
+ \texttt{1}, if you wish.
+
+ \cmhlistingsfromfile[style=logFilePreferences,]*{../defaultSettings.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{logFilePreferences}}{lst:logFilePreferences}
+
+ When%
+ \announce{2018-01-13}{showDecorationStartCodeBlockTrace feature for log file} either of the
+ \texttt{trace} modes (see \cpageref{page:traceswitch}) are active, you will receive
+ detailed information in \texttt{indent.log}. You can specify character strings to
+ appear before and after the notification of a found code block using, respectively,
+ \texttt{showDecorationStartCodeBlockTrace} and \texttt{showDecorationFinishCodeBlockTrace}. A demonstration is given in
+ \vref{app:logfile-demo}.
+
+ The log file will end with the characters given in \texttt{endLogFileWith}, and will
+ report the \texttt{GitHub} address of \texttt{latexindent.pl} to the log file if
+ \texttt{showGitHubInfoFooter} is set to \texttt{1}.
+
+ \texttt{latexindent.pl}%
+ \announce{2018-01-13}{log file pattern layout for log file} uses the \texttt{log4perl} module \cite{log4perl}
+ to handle the creation of the logfile. You can specify the layout of the information
+ given in the logfile using any of the \texttt{Log Layouts} detailed at
+ \cite{log4perl}.
+
+\yamltitle{verbatimEnvironments}*{fields}
+
+ A field that contains a list of environments that you would like left completely alone --
+ no indentation will be performed on environments that you have specified in this field,
+ see \cref{lst:verbatimEnvironments}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile[style=verbatimEnvironments]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{verbatimEnvironments}}{lst:verbatimEnvironments}
+ \cmhlistingsfromfile[style=verbatimCommands]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{verbatimCommands}}{lst:verbatimCommands}
+ \end{cmhtcbraster}
+
+ Note that if you put an environment in \texttt{verbatimEnvironments} and in other fields such
+ as \texttt{lookForAlignDelims} or \texttt{noAdditionalIndent} then \texttt{latexindent.pl} will
+ \emph{always} prioritize \texttt{verbatimEnvironments}.
+
+\yamltitle{verbatimCommands}*{fields}
+ A field that contains a list of commands that are verbatim commands, for example
+ \lstinline|\lstinline|; any commands populated in this field are protected from line
+ breaking routines (only relevant if the \texttt{-m} is active, see
+ \vref{sec:modifylinebreaks}).
+
+\yamltitle{noIndentBlock}*{fields}
+
+ \begin{wrapfigure}[8]{r}[0pt]{6cm}
+ \cmhlistingsfromfile[style=noIndentBlock]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{noIndentBlock}}{lst:noIndentBlock}
+ \end{wrapfigure}
+ If you have a block of code that you don't want \texttt{latexindent.pl} to touch (even if
+ it is \emph{not} a verbatim-like environment) then you can wrap it in an
+ environment from \texttt{noIndentBlock}; you can use any name you like for this,
+ provided you populate it as demonstrate in \cref{lst:noIndentBlock}.
+
+ Of course, you don't want to have to specify these as null environments in your code, so
+ you use them with a comment symbol, \lstinline!%!, followed by as many spaces
+ (possibly none) as you like; see \cref{lst:noIndentBlockdemo} for example.
+
+ \begin{cmhlistings}[style=demo,escapeinside={(*@}{@*)}]{\texttt{noIndentBlock} demonstration}{lst:noIndentBlockdemo}
+%(*@@*) \begin{noindent}
+ this code
+ won't
+ be touched
+ by
+ latexindent.pl!
+%(*@@*)\end{noindent}
+ \end{cmhlistings}
+
+\yamltitle{removeTrailingWhitespace}*{fields}\label{yaml:removeTrailingWhitespace}
+
+ \begin{wrapfigure}[10]{r}[0pt]{7cm}
+ \cmhlistingsfromfile[style=removeTrailingWhitespace]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{removeTrailingWhitespace}{lst:removeTrailingWhitespace}
+
+ \vspace{.1cm}
+ \begin{yaml}[numbers=none]{removeTrailingWhitespace (alt)}[width=.8\linewidth,before=\centering]{lst:removeTrailingWhitespace-alt}
+removeTrailingWhitespace: 1
+\end{yaml}
+ \end{wrapfigure}
+ Trailing white space can be removed both \emph{before} and
+ \emph{after} processing the document, as detailed in \cref{lst:removeTrailingWhitespace};
+ each of the fields can take the values \texttt{0} or
+ \texttt{1}. See \vref{lst:removeTWS-before,lst:env-mlb5-modAll,lst:env-mlb5-modAll-remove-WS} for before and after results. Thanks
+ to \cite{vosskuhle} for providing this feature.
+
+ You can specify \texttt{removeTrailingWhitespace} simply as \texttt{0} or
+ \texttt{1}, if you wish; in this case,%
+ \announce{2017-06-28}{removeTrailingWhitespace} \texttt{latexindent.pl} will set both \texttt{beforeProcessing} and
+ \texttt{afterProcessing} to the value you specify; see \cref{lst:removeTrailingWhitespace-alt}.
+\yamltitle{fileContentsEnvironments}*{field}
+
+ \begin{wrapfigure}[6]{r}[0pt]{6cm}
+ \cmhlistingsfromfile[style=fileContentsEnvironments]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{fileContentsEnvironments}}{lst:fileContentsEnvironments}
+ \end{wrapfigure}
+ Before \texttt{latexindent.pl} determines the difference between preamble (if any) and
+ the main document, it first searches for any of the environments specified in
+ \texttt{fileContentsEnvironments}, see \cref{lst:fileContentsEnvironments}. The behaviour of
+ \texttt{latexindent.pl} on these environments is determined by their location (preamble
+ or not), and the value \texttt{indentPreamble}, discussed next.
+
+\yamltitle{indentPreamble}{0|1}
+
+ The preamble of a document can sometimes contain some trickier code for
+ \texttt{latexindent.pl} to operate upon. By default, \texttt{latexindent.pl} won't try to
+ operate on the preamble (as \texttt{indentPreamble} is set to \texttt{0}, by
+ default), but if you'd like \texttt{latexindent.pl} to try then change
+ \texttt{indentPreamble} to \texttt{1}.
+
+\yamltitle{lookForPreamble}*{fields}
+
+ \begin{wrapfigure}[8]{r}[0pt]{5cm}
+ \cmhlistingsfromfile[style=lookForPreamble]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{lookForPreamble}{lst:lookForPreamble}
+ \end{wrapfigure}
+ Not all files contain preamble; for example, \texttt{sty},
+ \texttt{cls} and \texttt{bib} files typically do
+ \emph{not}. Referencing \cref{lst:lookForPreamble}, if you set, for example,
+ \texttt{.tex} to \texttt{0}, then regardless of the setting of the
+ value of \texttt{indentPreamble}, preamble will not be assumed when operating upon
+ \texttt{.tex} files.
+\yamltitle{preambleCommandsBeforeEnvironments}{0|1}
+ Assuming that \texttt{latexindent.pl} is asked to operate upon the preamble of a
+ document, when this switch is set to \texttt{0} then environment code blocks
+ will be sought first, and then command code blocks. When this switch is set to
+ \texttt{1}, commands will be sought first. The example that first motivated
+ this switch contained the code given in \cref{lst:motivatepreambleCommandsBeforeEnvironments}.
+
+ \begin{cmhlistings}{Motivating \texttt{preambleCommandsBeforeEnvironments}}{lst:motivatepreambleCommandsBeforeEnvironments}
+...
+preheadhook={\begin{mdframed}[style=myframedstyle]},
+postfoothook=\end{mdframed},
+...
+\end{cmhlistings}
+
+\yamltitle{defaultIndent}*{horizontal space}
+ This is the default indentation (\lstinline!\t! means a tab, and is the default
+ value) used in the absence of other details for the command or environment we are working
+ with; see \texttt{indentRules} in \vref{sec:noadd-indent-rules} for more details.
+
+ If you're interested in experimenting with \texttt{latexindent.pl} then you can
+ \emph{remove} all indentation by setting \texttt{defaultIndent: ""}.
+
+\yamltitle{lookForAlignDelims}*{fields}\label{yaml:lookforaligndelims}
+ \begin{wrapfigure}[12]{r}[0pt]{5cm}
+ \begin{yaml}[numbers=none]{\texttt{lookForAlignDelims} (basic)}[width=.8\linewidth,before=\centering]{lst:aligndelims:basic}
+lookForAlignDelims:
+ tabular: 1
+ tabularx: 1
+ longtable: 1
+ array: 1
+ matrix: 1
+ ...
+ \end{yaml}
+ \end{wrapfigure}
+ This contains a list of environments and/or commands that are operated upon in a special
+ way by \texttt{latexindent.pl} (see \cref{lst:aligndelims:basic}). In fact, the fields in \texttt{lookForAlignDelims} can
+ actually take two different forms: the \emph{basic} version is shown in
+ \cref{lst:aligndelims:basic} and the \emph{advanced} version in
+ \cref{lst:aligndelims:advanced}; we will discuss each in turn.
+
+ The environments specified in this field will be operated on in a special way by
+ \texttt{latexindent.pl}. In particular, it will try and align each column by its
+ alignment tabs. It does have some limitations (discussed further in
+ \cref{sec:knownlimitations}), but in many cases it will produce results such as those in
+ \cref{lst:tabularbefore:basic,lst:tabularafter:basic}.
+
+ If you find that \texttt{latexindent.pl} does not perform satisfactorily on such
+ environments then you can set the relevant key to \texttt{0}, for example
+ \texttt{tabular: 0}; alternatively, if you just want to ignore
+ \emph{specific} instances of the environment, you could wrap them in something
+ from \texttt{noIndentBlock} (see \vref{lst:noIndentBlock}).
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/tabular1.tex}{\texttt{tabular1.tex}}{lst:tabularbefore:basic}
+ \cmhlistingsfromfile{demonstrations/tabular1-default.tex}{\texttt{tabular1.tex} default output}{lst:tabularafter:basic}
+ \end{cmhtcbraster}
+
+ If, for example, you wish to remove the alignment of the \lstinline!\\! within a
+ delimiter-aligned block, then the advanced form of \texttt{lookForAlignDelims} shown in
+ \cref{lst:aligndelims:advanced} is for you.
+
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/tabular.yaml}[yaml-TCB]{\texttt{tabular.yaml}}{lst:aligndelims:advanced}
+
+ Note that you can use a mixture of the basic and advanced form: in
+ \cref{lst:aligndelims:advanced} \texttt{tabular} and \texttt{tabularx} are advanced
+ and \texttt{longtable} is basic. When using the advanced form, each field should
+ receive at least 1 sub-field, and \emph{can}
+ (but does not have to) receive any of the following
+ fields:
+ \begin{itemize}
+ \item \texttt{delims}: binary switch (0 or 1) equivalent to simply specifying, for
+ example, \texttt{tabular: 1} in the basic version shown in \cref{lst:aligndelims:basic}. If
+ \texttt{delims} is set to \texttt{0} then the align at ampersand
+ routine will not be called for this code block (default: 1);
+ \item \texttt{alignDoubleBackSlash}: binary switch (0 or 1) to determine if \lstinline!\\!
+ should be aligned (default: 1);
+ \item \texttt{spacesBeforeDoubleBackSlash}: optionally,%
+ \announce{2018-01-13}*{update to spacesBeforeDoubleBackSlash in ampersand alignment} specifies the number (integer $\geq$ 0) of spaces
+ to be inserted before \lstinline!\\! (default: 1). \footnote{Previously this only activated if \texttt{alignDoubleBackSlash} was set to \texttt{0}.}
+ \item \announce{2017-06-19}{multiColumnGrouping} \texttt{multiColumnGrouping}: binary switch (0 or 1) that details if
+ \texttt{latexindent.pl} should group columns
+ above and below a \lstinline!\multicolumn! command (default: 0);
+ \item \announce{2017-06-19}{alignRowsWithoutMaxDelims} \texttt{alignRowsWithoutMaxDelims}: binary switch (0 or 1) that details if
+ rows that do not contain the maximum number of delimeters should be formatted so as to
+ have the ampersands aligned (default: 1);
+ \item \announce{2018-01-13}{spacesBeforeAmpersand in ampersand alignment}\texttt{spacesBeforeAmpersand}: optionally specifies the number (integer
+ $\geq$ 0) of
+ spaces to be placed \emph{before} ampersands (default: 1);
+ \item \announce{2018-01-13}{spacesAfterAmpersand in ampersand alignment}\texttt{spacesAfterAmpersand}: optionally specifies the number (integer
+ $\geq$ 0) of
+ spaces to be placed \emph{After} ampersands (default: 1);
+ \item \announce{2018-01-13}{justification of cells in ampersand alignment}\texttt{justification}: optionally specifies the justification of
+ each cell as either \emph{left} or \emph{right} (default: left).
+ \end{itemize}
+
+ We will explore each of these features using the file \texttt{tabular2.tex} in
+ \cref{lst:tabular2} (which contains a \lstinline!\multicolumn! command), and the YAML files in \crefrange{lst:tabular2YAML}{lst:tabular8YAML}.
+
+ \cmhlistingsfromfile{demonstrations/tabular2.tex}{\texttt{tabular2.tex}}{lst:tabular2}
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/tabular2.yaml}[yaml-TCB]{\texttt{tabular2.yaml}}{lst:tabular2YAML}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.48\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/tabular3.yaml}[yaml-TCB]{\texttt{tabular3.yaml}}{lst:tabular3YAML}
+ \end{minipage}%
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/tabular4.yaml}[yaml-TCB]{\texttt{tabular4.yaml}}{lst:tabular4YAML}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.48\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/tabular5.yaml}[yaml-TCB]{\texttt{tabular5.yaml}}{lst:tabular5YAML}
+ \end{minipage}%
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/tabular6.yaml}[yaml-TCB]{\texttt{tabular6.yaml}}{lst:tabular6YAML}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.48\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/tabular7.yaml}[yaml-TCB]{\texttt{tabular7.yaml}}{lst:tabular7YAML}
+ \end{minipage}%
+
+ \begin{minipage}{.48\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/tabular8.yaml}[yaml-TCB]{\texttt{tabular8.yaml}}{lst:tabular8YAML}
+ \end{minipage}%
+
+ On running the commands
+ \begin{commandshell}
+latexindent.pl tabular2.tex
+latexindent.pl tabular2.tex -l tabular2.yaml
+latexindent.pl tabular2.tex -l tabular3.yaml
+latexindent.pl tabular2.tex -l tabular2.yaml,tabular4.yaml
+latexindent.pl tabular2.tex -l tabular2.yaml,tabular5.yaml
+latexindent.pl tabular2.tex -l tabular2.yaml,tabular6.yaml
+latexindent.pl tabular2.tex -l tabular2.yaml,tabular7.yaml
+latexindent.pl tabular2.tex -l tabular2.yaml,tabular8.yaml
+\end{commandshell}
+ we obtain the respective outputs given in \crefrange{lst:tabular2-default}{lst:tabular2-mod8}.
+
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/tabular2-default.tex}{\texttt{tabular2.tex} default output}{lst:tabular2-default}
+ \cmhlistingsfromfile{demonstrations/tabular2-mod2.tex}{\texttt{tabular2.tex} using \cref{lst:tabular2YAML}}{lst:tabular2-mod2}
+ \cmhlistingsfromfile{demonstrations/tabular2-mod3.tex}{\texttt{tabular2.tex} using \cref{lst:tabular3YAML}}{lst:tabular2-mod3}
+ \cmhlistingsfromfile{demonstrations/tabular2-mod4.tex}{\texttt{tabular2.tex} using \cref{lst:tabular2YAML,lst:tabular4YAML}}{lst:tabular2-mod4}
+ \cmhlistingsfromfile{demonstrations/tabular2-mod5.tex}{\texttt{tabular2.tex} using \cref{lst:tabular2YAML,lst:tabular5YAML}}{lst:tabular2-mod5}
+ \cmhlistingsfromfile{demonstrations/tabular2-mod6.tex}{\texttt{tabular2.tex} using \cref{lst:tabular2YAML,lst:tabular6YAML}}{lst:tabular2-mod6}
+ \cmhlistingsfromfile{demonstrations/tabular2-mod7.tex}{\texttt{tabular2.tex} using \cref{lst:tabular2YAML,lst:tabular7YAML}}{lst:tabular2-mod7}
+ \cmhlistingsfromfile{demonstrations/tabular2-mod8.tex}{\texttt{tabular2.tex} using \cref{lst:tabular2YAML,lst:tabular8YAML}}{lst:tabular2-mod8}
+ \end{widepage}
+
+ Notice in particular:
+ \begin{itemize}
+ \item in both \cref{lst:tabular2-default,lst:tabular2-mod2} all rows have been aligned at the ampersand, even those
+ that do not contain the maximum number of ampersands (3 ampersands, in this case);
+ \item in \cref{lst:tabular2-default} the columns have been aligned at the ampersand;
+ \item in \cref{lst:tabular2-mod2} the \lstinline!\multicolumn! command has grouped the
+ $2$ columns beneath \emph{and} above it, because
+ \texttt{multiColumnGrouping} is set to $1$ in \cref{lst:tabular2YAML};
+ \item in \cref{lst:tabular2-mod3} rows~3 and~6 have \emph{not} been aligned at the
+ ampersand, because \texttt{alignRowsWithoutMaxDelims} has been to set to $0$ in
+ \cref{lst:tabular3YAML}; however, the \lstinline!\\! \emph{have} still
+ been aligned;
+ \item in \cref{lst:tabular2-mod4} the columns beneath and above the \lstinline!\multicolumn!
+ commands have been grouped (because \texttt{multiColumnGrouping} is set to
+ $1$), and there are at least $4$ spaces
+ \emph{before} each aligned ampersand because \texttt{spacesBeforeAmpersand} is set to
+ $4$;
+ \item in \cref{lst:tabular2-mod5} the columns beneath and above the \lstinline!\multicolumn!
+ commands have been grouped (because \texttt{multiColumnGrouping} is set to
+ $1$), and there are at least $4$ spaces
+ \emph{after} each aligned ampersand because \texttt{spacesAfterAmpersand} is set to
+ $4$;
+ \item in \cref{lst:tabular2-mod6} the \lstinline!\\! have \emph{not} been
+ aligned, because \texttt{alignDoubleBackSlash} is set to \texttt{0}, otherwise the
+ output is the same as \cref{lst:tabular2-mod2};
+ \item in \cref{lst:tabular2-mod7} the \lstinline!\\! \emph{have} been
+ aligned, and because \texttt{spacesBeforeDoubleBackSlash} is set to \texttt{0}, there are
+ no spaces ahead of them; the output is otherwise the same as \cref{lst:tabular2-mod2}.
+ \item in \cref{lst:tabular2-mod8} the cells have been \emph{right}-justified; note
+ that cells above and below the \lstinline!\multicol! statements have still been group
+ correctly, because of the settings in \cref{lst:tabular2YAML}.
+ \end{itemize}
+
+ As of Version 3.0, the alignment routine works on mandatory and optional arguments within
+ commands, and also within `special' code blocks (see \texttt{specialBeginEnd} on
+ \cpageref{yaml:specialBeginEnd}); for example, assuming that you have a command called
+ \lstinline!\matrix! and that it is populated within \texttt{lookForAlignDelims} (which it is, by default), and that
+ you run the command
+ \begin{commandshell}
+latexindent.pl matrix1.tex
+\end{commandshell}
+ then the before-and-after results shown in \cref{lst:matrixbefore,lst:matrixafter} are achievable by
+ default.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/matrix1.tex}{\texttt{matrix1.tex}}{lst:matrixbefore}
+ \cmhlistingsfromfile{demonstrations/matrix1-default.tex}{\texttt{matrix1.tex} default output}{lst:matrixafter}
+ \end{cmhtcbraster}
+
+ If you have blocks of code that you wish to align at the \& character that are
+ \emph{not} wrapped in, for example, \lstinline!\begin{tabular}! \ldots
+ \lstinline!\end{tabular}!, then you can use the mark up illustrated in
+ \cref{lst:alignmentmarkup}; the default output is shown in \cref{lst:alignmentmarkup-default}. Note
+ that the \lstinline!%*! must be next to each other, but that there can be any
+ number of spaces (possibly none) between the
+ \lstinline!*! and \lstinline!\begin{tabular}!; note also that you may use any
+ environment name that you have specified in \texttt{lookForAlignDelims}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/align-block.tex}{\texttt{align-block.tex}}{lst:alignmentmarkup}
+ \cmhlistingsfromfile{demonstrations/align-block-default.tex}{\texttt{align-block.tex} default output}{lst:alignmentmarkup-default}
+ \end{cmhtcbraster}
+
+ With reference to \vref{tab:code-blocks} and the, yet undiscussed, fields of
+ \texttt{noAdditionalIndent} and \texttt{indentRules}
+ (see \vref{sec:noadd-indent-rules}), these comment-marked blocks are
+ considered \texttt{environments}.
+
+\yamltitle{indentAfterItems}*{fields}
+ The environment names specified in \texttt{indentAfterItems} tell \texttt{latexindent.pl}
+ to look for \lstinline!\item! commands; if these switches are set to
+ \texttt{1} then indentation will be performed so as indent the code after
+ each \texttt{item}. A demonstration is given in \cref{lst:itemsbefore,lst:itemsafter}
+
+ \begin{cmhtcbraster}[raster columns=3,
+ raster left skip=-3.5cm,
+ raster right skip=-2cm,
+ raster column skip=.03\linewidth]
+ \cmhlistingsfromfile[style=indentAfterItems]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{indentAfterItems}}{lst:indentafteritems}
+ \cmhlistingsfromfile{demonstrations/items1.tex}{\texttt{items1.tex}}{lst:itemsbefore}
+ \cmhlistingsfromfile{demonstrations/items1-default.tex}{\texttt{items1.tex} default output}{lst:itemsafter}
+ \end{cmhtcbraster}
+
+\yamltitle{itemNames}*{fields}
+ \begin{wrapfigure}[5]{r}[0pt]{5cm}
+ \cmhlistingsfromfile[style=itemNames]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{itemNames}}{lst:itemNames}
+ \end{wrapfigure}
+ If you have your own \texttt{item} commands (perhaps you prefer to use
+ \texttt{myitem}, for example) then you can put populate them in
+ \texttt{itemNames}. For example, users of the \texttt{exam} document class
+ might like to add \texttt{parts} to \texttt{indentAfterItems} and
+ \texttt{part} to \texttt{itemNames} to their user settings (see
+ \vref{sec:indentconfig} for details of how to configure user settings, and
+ \vref{lst:mysettings} \\ in particular \label{page:examsettings}.)
+
+\yamltitle{specialBeginEnd}*{fields}\label{yaml:specialBeginEnd}
+ The fields specified%
+ \announce{2017-08-21}*{specialBeginEnd} in
+ \texttt{specialBeginEnd} are, in their default state, focused on math mode begin and end
+ statements, but there is no requirement for this to be the case; \cref{lst:specialBeginEnd}
+ shows the default settings of \texttt{specialBeginEnd}.
+
+ \cmhlistingsfromfile[style=specialBeginEnd]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{specialBeginEnd}}{lst:specialBeginEnd}
+
+ The field \texttt{displayMath} represents \lstinline!\[...\]!,
+ \texttt{inlineMath} represents
+ \lstinline!$...$! and \texttt{displayMathTex} represents \lstinline!$$...$$!.
+ You can, of course, rename these in your own YAML files (see \vref{sec:localsettings});
+ indeed, you might like to set up your own special begin and end statements.
+
+ A demonstration of the before-and-after results are shown in \cref{lst:specialbefore,lst:specialafter}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/special1.tex}{\texttt{special1.tex} before}{lst:specialbefore}
+ \cmhlistingsfromfile{demonstrations/special1-default.tex}{\texttt{special1.tex} default output}{lst:specialafter}
+ \end{cmhtcbraster}
+
+ For each field, \texttt{lookForThis} is set to \texttt{1} by default,
+ which means that \texttt{latexindent.pl} will look for this pattern; you can tell
+ \texttt{latexindent.pl} not to look for the pattern, by setting \texttt{lookForThis}
+ to \texttt{0}.
+
+ There are%
+ \announce{2017-08-21}{specialBeforeCommand} examples in which it
+ is advantageous to search for \texttt{specialBeginEnd} fields \emph{before}
+ searching for commands, and the \texttt{specialBeforeCommand} switch controls this behaviour.
+ For example, consider the file shown in \cref{lst:specialLRbefore}.
+
+ \cmhlistingsfromfile{demonstrations/specialLR.tex}{\texttt{specialLR.tex}}{lst:specialLRbefore}
+
+ Now consider the YAML files shown in \cref{lst:specialsLeftRight-yaml,lst:specialBeforeCommand-yaml}
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile[]*{demonstrations/specialsLeftRight.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{specialsLeftRight.yaml}}{lst:specialsLeftRight-yaml}
+ \cmhlistingsfromfile[]*{demonstrations/specialBeforeCommand.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{specialBeforeCommand.yaml}}{lst:specialBeforeCommand-yaml}
+ \end{cmhtcbraster}
+
+ Upon running the following commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl specialLR.tex -l=specialsLeftRight.yaml
+latexindent.pl specialLR.tex -l=specialsLeftRight.yaml,specialBeforeCommand.yaml
+\end{commandshell}
+ \end{widepage}
+ we receive the respective outputs in \cref{lst:specialLR-comm-first-tex,lst:specialLR-special-first-tex}.
+
+ \begin{minipage}{.49\linewidth}
+ \cmhlistingsfromfile{demonstrations/specialLR-comm-first.tex}{\texttt{specialLR.tex} using \cref{lst:specialsLeftRight-yaml}}{lst:specialLR-comm-first-tex}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\linewidth}
+ \cmhlistingsfromfile{demonstrations/specialLR-special-first.tex}{\texttt{specialLR.tex} using \cref{lst:specialsLeftRight-yaml,lst:specialBeforeCommand-yaml}}{lst:specialLR-special-first-tex}
+ \end{minipage}
+
+ Notice that in:
+ \begin{itemize}
+ \item \cref{lst:specialLR-comm-first-tex} the \lstinline!\left! has been treated as a
+ \emph{command}, with one optional argument;
+ \item \cref{lst:specialLR-special-first-tex} the \texttt{specialBeginEnd} pattern in \cref{lst:specialsLeftRight-yaml}
+ has been obeyed because \cref{lst:specialBeforeCommand-yaml} specifies that the
+ \texttt{specialBeginEnd} should be sought \emph{before} commands.
+ \end{itemize}
+
+ You can,optionally, specify%
+ \announce{2018-04-27}{update to specialBeginEnd} the
+ \texttt{middle} field for anything that you specify in \texttt{specialBeginEnd}.
+ For example, let's consider the \texttt{.tex} file in \cref{lst:special2}.
+
+ \cmhlistingsfromfile{demonstrations/special2.tex}{\texttt{special2.tex}}{lst:special2}
+
+ Upon saving the YAML settings in \cref{lst:middle-yaml,lst:middle1-yaml} and running the commands
+ \begin{commandshell}
+latexindent.pl special2.tex -l=middle
+latexindent.pl special2.tex -l=middle1
+\end{commandshell}
+ then we obtain the output given in \cref{lst:special2-mod1,lst:special2-mod2}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/middle.yaml}[yaml-TCB]{\texttt{middle.yaml}}{lst:middle-yaml}
+ \cmhlistingsfromfile{demonstrations/special2-mod1.tex}{\texttt{special2.tex} using \cref{lst:middle-yaml}}{lst:special2-mod1}
+ \end{cmhtcbraster}
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/middle1.yaml}[yaml-TCB]{\texttt{middle1.yaml}}{lst:middle1-yaml}
+ \cmhlistingsfromfile{demonstrations/special2-mod2.tex}{\texttt{special2.tex} using \cref{lst:middle1-yaml}}{lst:special2-mod2}
+ \end{cmhtcbraster}
+
+ We note that:
+ \begin{itemize}
+ \item in \cref{lst:special2-mod1} the bodies of each of the \texttt{Elsif} statements
+ have been indented appropriately;
+ \item the \texttt{Else} statement has \emph{not} been indented
+ appropriately in \cref{lst:special2-mod1} -- read on!
+ \item we have specified multiple settings for the \texttt{middle} field using the
+ syntax demonstrated in \cref{lst:middle1-yaml} so that the body of the
+ \texttt{Else} statement has been indented appropriately in
+ \cref{lst:special2-mod2}.
+ \end{itemize}
+
+ You may%
+ \announce{2018-08-13}{specialBeginEnd verbatim} specify fields in
+ \texttt{specialBeginEnd} to be treated as verbatim code blocks by changing
+ \texttt{lookForThis} to be \texttt{verbatim}.
+
+ For example, beginning with the code in \cref{lst:special3-mod1} and the YAML in
+ \cref{lst:special-verb1-yaml}, and running
+ \begin{commandshell}
+latexindent.pl special3.tex -l=special-verb1
+\end{commandshell}
+ then the output in \cref{lst:special3-mod1} is unchanged.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/special-verb1.yaml}[yaml-TCB]{\texttt{special-verb1.yaml}}{lst:special-verb1-yaml}
+ \cmhlistingsfromfile{demonstrations/special3-mod1.tex}{\texttt{special3.tex} and output using \cref{lst:special-verb1-yaml}}{lst:special3-mod1}
+ \end{cmhtcbraster}
+
+\yamltitle{indentAfterHeadings}*{fields}
+ \begin{wrapfigure}[17]{r}[0pt]{8cm}
+ \cmhlistingsfromfile[style=indentAfterHeadings]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{indentAfterHeadings}}{lst:indentAfterHeadings}
+ \end{wrapfigure}
+ This field enables the user to specify indentation rules that take effect after heading
+ commands such as \lstinline!\part!, \lstinline!\chapter!,
+ \lstinline!\section!, \lstinline!\subsection*!, or indeed any user-specified command
+ written in this field.\footnote{There is a slight
+ difference in interface for this field when comparing Version 2.2 to Version 3.0; see \vref{app:differences} for details.}
+
+ The default settings do \emph{not} place indentation after a heading, but
+ you can easily switch them on by changing \\ \texttt{indentAfterThisHeading: 0} to \\
+ \texttt{indentAfterThisHeading: 1}. The \texttt{level} field tells \texttt{latexindent.pl}
+ the hierarchy of the heading structure in your document. You might, for example, like to
+ have both \texttt{section} and \texttt{subsection} set with
+ \texttt{level: 3} because you do not want the indentation to go too deep.
+
+ You can add any of your own custom heading commands to this field, specifying the
+ \texttt{level} as appropriate. You can also specify your own indentation in
+ \texttt{indentRules} (see \vref{sec:noadd-indent-rules}); you will find the default \texttt{indentRules} contains
+ \lstinline!chapter: " "! which tells \texttt{latexindent.pl} simply to use a space
+ character after \texttt{\chapter} headings (once \texttt{indent} is set to
+ \texttt{1} for \texttt{chapter}).
+
+ For example, assuming that you have the code in \cref{lst:headings1yaml} saved into
+ \texttt{headings1.yaml}, and that you have the text from \cref{lst:headings1} saved
+ into \texttt{headings1.tex}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/headings1.yaml}[yaml-TCB]{\texttt{headings1.yaml}}{lst:headings1yaml}
+ \cmhlistingsfromfile{demonstrations/headings1.tex}{\texttt{headings1.tex}}{lst:headings1}
+ \end{cmhtcbraster}
+
+ If you run the command
+ \begin{commandshell}
+latexindent.pl headings1.tex -l=headings1.yaml
+\end{commandshell}
+ then you should receive the output given in \cref{lst:headings1-mod1}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/headings1-mod1.tex}{\texttt{headings1.tex} using \cref{lst:headings1yaml}}{lst:headings1-mod1}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/headings1-mod2.tex}{\texttt{headings1.tex} second modification}{lst:headings1-mod2}
+ \end{minipage}
+
+ Now say that you modify the \texttt{YAML} from \cref{lst:headings1yaml} so that
+ the \texttt{paragraph} \texttt{level} is \texttt{1}; after
+ running
+ \begin{commandshell}
+latexindent.pl headings1.tex -l=headings1.yaml
+\end{commandshell}
+ you should receive the code given in \cref{lst:headings1-mod2}; notice that the
+ \texttt{paragraph} and \texttt{subsection} are at the same indentation level.
+
+\yamltitle{maximumIndentation}*{horizontal space}
+ You can control the maximum indentation given to your file
+ by%
+ \announce{2017-08-21}{maximumIndentation} specifying the
+ \texttt{maximumIndentation} field as horizontal space (but \emph{not} including
+ tabs). This feature uses the \texttt{Text::Tabs} module \cite{texttabs}, and
+ is \emph{off} by default.
+
+ For example, consider the example shown in \cref{lst:mult-nested} together with the
+ default output shown in \cref{lst:mult-nested-default}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/mult-nested.tex}{\texttt{mult-nested.tex}}{lst:mult-nested}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/mult-nested-default.tex}{\texttt{mult-nested.tex} default output}{lst:mult-nested-default}
+ \end{cmhtcbraster}
+
+ Now say that, for example, you have the \texttt{max-indentation1.yaml} from
+ \cref{lst:max-indentation1yaml} and that you run the following command:
+ \begin{commandshell}
+latexindent.pl mult-nested.tex -l=max-indentation1
+\end{commandshell}
+ You should receive the output shown in \cref{lst:mult-nested-max-ind1}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/max-indentation1.yaml}[yaml-TCB]{\texttt{max-indentation1.yaml}}{lst:max-indentation1yaml}
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/mult-nested-max-ind1.tex}{\texttt{mult-nested.tex} using \cref{lst:max-indentation1yaml}}{lst:mult-nested-max-ind1}
+ \end{cmhtcbraster}
+
+ Comparing the output in \cref{lst:mult-nested-default,lst:mult-nested-max-ind1} we notice that the (default) tabs of
+ indentation have been replaced by a single space.
+
+ In general, when using the \texttt{maximumIndentation} feature, any leading tabs will be
+ replaced by equivalent spaces except, of course, those found in \texttt{verbatimEnvironments} (see \vref{lst:verbatimEnvironments})
+ or \texttt{noIndentBlock} (see \vref{lst:noIndentBlock}).
+
+\subsection{The code blocks known latexindent.pl}\label{subsubsec:code-blocks}
+ As of Version 3.0, \texttt{latexindent.pl} processes documents using code blocks; each of
+ these are shown in \cref{tab:code-blocks}.
+
+ \begin{table}[!htp]
+ \begin{widepage}
+ \centering
+ \caption{Code blocks known to \texttt{latexindent.pl}}\label{tab:code-blocks}
+ \begin{tabular}{m{.3\linewidth}@{\hspace{.25cm}}m{.4\linewidth}@{\hspace{.25cm}}m{.2\linewidth}}
+ \toprule
+ Code block & characters allowed in name & example \\
+ \midrule
+ environments & \lstinline!a-zA-Z@\*0-9_\\! &
+ \begin{lstlisting}[,nolol=true,]
+\begin{myenv}
+body of myenv
+\end{myenv}
+ \end{lstlisting}
+ \\\cmidrule{2-3}
+ optionalArguments & \emph{inherits} name from parent (e.g environment name) &
+ \begin{lstlisting}[,nolol=true,]
+[
+opt arg text
+]
+ \end{lstlisting}
+ \\\cmidrule{2-3}
+ mandatoryArguments & \emph{inherits} name from parent (e.g environment name) &
+ \begin{lstlisting}[,nolol=true,]
+{
+mand arg text
+}
+ \end{lstlisting}
+ \\\cmidrule{2-3}
+ commands & \lstinline!+a-zA-Z@\*0-9_\:! & \lstinline!\mycommand!$\langle$\itshape{arguments}$\rangle$ \\\cmidrule{2-3}
+ keyEqualsValuesBracesBrackets & \lstinline!a-zA-Z@\*0-9_\/.\h\{\}:\#-! & \lstinline!my key/.style=!$\langle$\itshape{arguments}$\rangle$ \\\cmidrule{2-3}
+ namedGroupingBracesBrackets & \lstinline!0-9\.a-zA-Z@\*><! & \lstinline!in!$\langle$\itshape{arguments}$\rangle$ \\\cmidrule{2-3}
+ UnNamedGroupingBracesBrackets & \centering\emph{No name!} & \lstinline!{! or \lstinline![! or \lstinline!,! or \lstinline!&! or \lstinline!)! or \lstinline!(! or \lstinline!$! followed by $\langle$\itshape{arguments}$\rangle$ \\\cmidrule{2-3}
+ ifElseFi & \lstinline!@a-zA-Z! but must begin with either \newline \lstinline!\if! of \lstinline!\@if! &
+ \begin{lstlisting}[,nolol=true,]
+\ifnum...
+...
+\else
+...
+\fi
+ \end{lstlisting} \\\cmidrule{2-3}
+ items & User specified, see \vref{lst:indentafteritems,lst:itemNames} &
+ \begin{lstlisting}[,nolol=true,]
+\begin{enumerate}
+ \item ...
+\end{enumerate}
+ \end{lstlisting} \\\cmidrule{2-3}
+ specialBeginEnd & User specified, see \vref{lst:specialBeginEnd} &
+ \begin{lstlisting}[,nolol=true,]
+\[
+ ...
+\]
+ \end{lstlisting} \\\cmidrule{2-3}
+ afterHeading & User specified, see \vref{lst:indentAfterHeadings} &
+ \begin{lstlisting}[,morekeywords={chapter},nolol=true,]
+\chapter{title}
+ ...
+\section{title}
+ \end{lstlisting} \\\cmidrule{2-3}
+ filecontents & User specified, see \vref{lst:fileContentsEnvironments} &
+ \begin{lstlisting}[,nolol=true,]
+\begin{filecontents}
+...
+\end{filecontents}
+ \end{lstlisting} \\
+ \bottomrule
+ \end{tabular}
+ \end{widepage}
+ \end{table}
+
+ We will refer to these code blocks in what follows.%
+ \announce*{2019-07-13}{fine tuning of code blocks} Note that the fine tuning of the definition of the code blocks
+ detailed in \cref{tab:code-blocks} is discussed in \vref{sec:finetuning}.
diff --git a/support/latexindent/documentation/sec-demonstration.tex b/support/latexindent/documentation/sec-demonstration.tex
new file mode 100644
index 0000000000..18459edcda
--- /dev/null
+++ b/support/latexindent/documentation/sec-demonstration.tex
@@ -0,0 +1,40 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\section{Demonstration: before and after}
+ Let's give a demonstration of some before and after code -- after all, you probably won't
+ want to try the script if you don't much like the results. You might also like to watch
+ the video demonstration I made on youtube \cite{cmh:videodemo}
+
+ As you look at \crefrange{lst:filecontentsbefore}{lst:pstricksafter}, remember that \texttt{latexindent.pl} is just
+ following its rules, and there is nothing particular about these code snippets. All of
+ the rules can be modified so that you can personalise your indentation scheme.
+
+ In each of the samples given in \crefrange{lst:filecontentsbefore}{lst:pstricksafter} the `before' case is a `worst case
+ scenario' with no effort to make indentation. The `after' result would be the same,
+ regardless of the leading white space at the beginning of each line which is stripped by
+ \texttt{latexindent.pl} (unless a \texttt{verbatim}-like
+ environment or \texttt{noIndentBlock} is specified -- more on this in \cref{sec:defuseloc}).
+
+ \begin{widepage}
+ \centering
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/filecontents1.tex}{\texttt{filecontents1.tex}}{lst:filecontentsbefore}
+ \end{minipage}\hfill
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/filecontents1-default.tex}{\texttt{filecontents1.tex} default output}{lst:filecontentsafter}
+ \end{minipage}%
+
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/tikzset.tex}{\texttt{tikzset.tex}}{lst:tikzsetbefore}
+ \end{minipage}\hfill
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/tikzset-default.tex}{\texttt{tikzset.tex} default output}{lst:tikzsetafter}
+ \end{minipage}%
+
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/pstricks.tex}{\texttt{pstricks.tex}}{lst:pstricksbefore}
+ \end{minipage}\hfill
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/pstricks-default.tex}{\texttt{pstricks.tex} default output}{lst:pstricksafter}
+ \end{minipage}%
+ \end{widepage}
+
diff --git a/support/latexindent/documentation/sec-fine-tuning.tex b/support/latexindent/documentation/sec-fine-tuning.tex
new file mode 100644
index 0000000000..9a2cbbb5c8
--- /dev/null
+++ b/support/latexindent/documentation/sec-fine-tuning.tex
@@ -0,0 +1,109 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\section{Fine tuning}\label{sec:finetuning}
+ \texttt{latexindent.pl} operates by looking for the code blocks detailed in
+ \vref{tab:code-blocks}.
+ \announce*{2019-07-13}{details of fine tuning of code blocks} The fine tuning of the details of such code blocks
+ is controlled by the \texttt{fineTuning} field, detailed in \cref{lst:fineTuning}.
+
+ This field is for those that would like to peek under the bonnet/hood and make some fine
+ tuning to \texttt{latexindent.pl}'s operating.
+
+ \begin{warning}
+ Making changes to the fine tuning may have significant consequences for your indentation scheme,
+ proceed with caution!
+ \end{warning}
+
+ \begin{widepage}
+ \cmhlistingsfromfile*[style=fineTuning]*{../defaultSettings.yaml}[width=0.95\linewidth,before=\centering,yaml-TCB]{\texttt{fineTuning}}{lst:fineTuning}
+ \end{widepage}
+
+ The fields given in \cref{lst:fineTuning} are all \emph{regular expressions}. This manual is
+ not intended to be a tutorial on regular expressions; you might like to read, for
+ example, \cite{masteringregexp} for a detailed covering of the topic.
+
+ We make the following comments with reference to \cref{lst:fineTuning}:
+ \begin{enumerate}
+ \item the \texttt{environments:name} field details that the \emph{name} of an
+ environment can contain:
+ \begin{enumerate}
+ \item \texttt{a-z} lower case letters
+ \item \texttt{A-Z} upper case letters
+ \item \texttt{@} the \texttt{@} 'letter'
+ \item \lstinline!\*! stars
+ \item \texttt{0-9} numbers
+ \item \lstinline!_! underscores
+ \item \lstinline!\! backslashes
+ \end{enumerate}
+ The \texttt{+} at the end means \emph{at least one} of the above
+ characters.
+ \item the \texttt{ifElseFi:name} field:
+ \begin{enumerate}
+ \item \lstinline^@?^ means that it \emph{can possibly} begin with
+ \lstinline^@^
+ \item followed by \texttt{if}
+ \item followed by 0 or more characters from \texttt{a-z}, \texttt{A-Z} and
+ \texttt{@}
+ \item the \texttt{?} the end means \emph{non-greedy}, which means `stop the
+ match as soon as possible'
+ \end{enumerate}
+ \item the \texttt{keyEqualsValuesBracesBrackets} contains some interesting syntax:
+ \begin{enumerate}
+ \item \lstinline!|! means `or'
+ \item \lstinline^(?:(?<!\\)\{)^ the \lstinline^(?:...)^ uses a \emph{non-capturing} group --
+ you don't necessarily need to worry about what this means, but just know that for the
+ \texttt{fineTuning} feature you should only ever use \emph{non}-capturing
+ groups, and \emph{not} capturing groups, which are simply
+ \lstinline!(...)!
+ \item \lstinline^(?<!\\)\{)^ means a \lstinline^{^ but it can \emph{not}
+ be immediately preceded by a \lstinline!\!
+ \end{enumerate}
+ \item in the \texttt{arguments:before} field
+ \begin{enumerate}
+ \item \lstinline^\d\h*^ means a digit (i.e. a number), followed by 0 or more horizontal
+ spaces
+ \item \lstinline^;?,?^ means \emph{possibly} a semi-colon, and possibly a comma
+ \item \lstinline^\<.*?\>^ is designed for 'beamer'-type commands; the
+ \lstinline^.*?^ means anything in between \lstinline^<...>^
+ \end{enumerate}
+ \item the \texttt{modifyLineBreaks} field refers to fine tuning settings detailed in
+ \vref{sec:modifylinebreaks}. In particular:
+ \begin{enumerate}
+ \item \texttt{betterFullStop} is in relation to the one sentence per line routine, detailed in
+ \vref{sec:onesentenceperline}
+ \item \texttt{doubleBackSlash} is in relation to the \texttt{DBSStartsOnOwnLine} and
+ \texttt{DBSFinishesWithLineBreak} polyswitches surrounding double back slashes, see
+ \vref{subsec:dbs}
+ \item \texttt{comma} is in relation to the \texttt{CommaStartsOnOwnLine} and
+ \texttt{CommaFinishesWithLineBreak} polyswitches surrounding commas in optional and mandatory
+ arguments; see \vref{tab:poly-switch-mapping}
+ \end{enumerate}
+ \end{enumerate}
+
+ It is not obvious from \cref{lst:fineTuning}, but each of the \texttt{follow},
+ \texttt{before} and \texttt{between} fields allow trailing comments, line
+ breaks, and horizontal spaces between each character.
+
+ As a demonstration, consider the file given in \cref{lst:finetuning1}, together with its
+ default output using the command
+ \begin{commandshell}
+latexindent.pl finetuning1.tex
+\end{commandshell}
+ is given in \cref{lst:finetuning1-default}.
+
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/finetuning1.tex}{\texttt{finetuning1.tex}}{lst:finetuning1}
+ \cmhlistingsfromfile*{demonstrations/finetuning1-default.tex}{\texttt{finetuning1.tex} default}{lst:finetuning1-default}
+ \end{cmhtcbraster}
+
+ It's clear from \cref{lst:finetuning1-default} that the indentation scheme has not worked as
+ expected. We can \emph{fine tune} the indentation scheme by employing the settings
+ given in \cref{lst:fine-tuning1} and running the command
+ \begin{commandshell}
+latexindent.pl finetuning1.tex -l=fine-tuning1.yaml
+\end{commandshell}
+ and the associated (desired) output is given in \cref{lst:finetuning1-mod1}.
+
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/finetuning1-mod1.tex}{\texttt{finetuning1.tex} using \cref{lst:fine-tuning1}}{lst:finetuning1-mod1}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/fine-tuning1.yaml}[yaml-TCB]{\texttt{finetuning1.yaml}}{lst:fine-tuning1}
+ \end{cmhtcbraster}
diff --git a/support/latexindent/documentation/sec-how-to-use.tex b/support/latexindent/documentation/sec-how-to-use.tex
new file mode 100644
index 0000000000..bdae2b428e
--- /dev/null
+++ b/support/latexindent/documentation/sec-how-to-use.tex
@@ -0,0 +1,391 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\section{How to use the script}
+ \texttt{latexindent.pl} ships as part of the \TeX Live distribution for
+ Linux and Mac users; \texttt{latexindent.exe} ships as part of the \TeX Live and
+ MiK\TeX{} distributions for Windows users. These files are also available
+ from github \cite{latexindent-home} should you wish to use them without a
+ \TeX{} distribution; in this case, you may like to read
+ \vref{sec:updating-path} which details how the \texttt{path} variable can be
+ updated.
+
+ In what follows, we will always refer to \texttt{latexindent.pl}, but depending on your
+ operating system and preference, you might substitute \texttt{latexindent.exe} or simply
+ \texttt{latexindent}.
+
+ There are two ways to use \texttt{latexindent.pl}: from the command line, and using
+ \texttt{arara}; we discuss these in \cref{sec:commandline} and
+ \cref{sec:arara} respectively. We will discuss how to change the settings and
+ behaviour of the script in \vref{sec:defuseloc}.
+
+ \texttt{latexindent.pl} ships with \texttt{latexindent.exe} for Windows
+ users, so that you can use the script with or without a Perl distribution. If you plan to
+ use \texttt{latexindent.pl} (i.e, the original Perl script) then you will need a few standard Perl modules -- see
+ \vref{sec:requiredmodules} for details;%
+ \announce{2018-01-13}{perl module installer helper script} in particular, note that a module installer helper script is
+ shipped with \texttt{latexindent.pl}.
+
+\subsection{From the command line}\label{sec:commandline}
+ \texttt{latexindent.pl} has a number of different switches/flags/options, which
+ can be combined in any way that you like, either in short or long form as detailed below.
+ \texttt{latexindent.pl} produces a \texttt{.log} file, \texttt{indent.log},
+ every time it is run; the name of the log file can be customised, but we will refer to
+ the log file as \texttt{indent.log} throughout this document. There is a base of
+ information that is written to \texttt{indent.log}, but other additional information
+ will be written depending on which of the following options are used.
+
+\flagbox{-v, --version}
+ \announce{2017-06-25}{version}
+ \begin{commandshell}
+latexindent.pl -v
+\end{commandshell}
+ This will output only the version number to the terminal.
+
+\flagbox{-h, --help}
+
+ \begin{commandshell}
+latexindent.pl -h
+\end{commandshell}
+
+ As above this will output a welcome message to the terminal, including the version number
+ and available options.
+ \begin{commandshell}
+latexindent.pl myfile.tex
+\end{commandshell}
+
+ This will operate on \texttt{myfile.tex}, but will simply output to your terminal;
+ \texttt{myfile.tex} will not be changed by \texttt{latexindent.pl} in any way using
+ this command.
+
+\flagbox{-w, --overwrite}
+ \begin{commandshell}
+latexindent.pl -w myfile.tex
+latexindent.pl --overwrite myfile.tex
+latexindent.pl myfile.tex --overwrite
+\end{commandshell}
+
+ This \emph{will} overwrite \texttt{myfile.tex}, but it will make a copy of
+ \texttt{myfile.tex} first. You can control the name of the extension (default is
+ \texttt{.bak}), and how many different backups are made -- more on this in
+ \cref{sec:defuseloc}, and in particular see \texttt{backupExtension} and
+ \texttt{onlyOneBackUp}.
+
+ Note that if \texttt{latexindent.pl} can not create the backup, then it will exit without
+ touching your original file; an error message will be given asking you to check the
+ permissions of the backup file.
+
+\flagbox{-o=output.tex,--outputfile=output.tex}
+ \begin{commandshell}
+latexindent.pl -o=output.tex myfile.tex
+latexindent.pl myfile.tex -o=output.tex
+latexindent.pl --outputfile=output.tex myfile.tex
+latexindent.pl --outputfile output.tex myfile.tex
+\end{commandshell}
+
+ This will indent \texttt{myfile.tex} and output it to \texttt{output.tex},
+ overwriting it (\texttt{output.tex}) if it already exists\footnote{Users of version 2.* should
+ note the subtle change in syntax}. Note
+ that if \texttt{latexindent.pl} is called with both the \texttt{-w} and
+ \texttt{-o} switches, then \texttt{-w} will be ignored and
+ \texttt{-o} will take priority (this seems safer than the other way round).
+
+ Note that using \texttt{-o} as above is equivalent to using
+ \begin{commandshell}
+latexindent.pl myfile.tex > output.tex
+\end{commandshell}
+
+ You can call the \texttt{-o} switch with the name of the output file
+ \emph{without} an extension; in%
+ \announce{2017-06-25}{upgrade to -o switch} this case, \texttt{latexindent.pl} will use the extension from the
+ original file. For example, the following two calls to \texttt{latexindent.pl} are
+ equivalent:
+ \begin{commandshell}
+latexindent.pl myfile.tex -o=output
+latexindent.pl myfile.tex -o=output.tex
+\end{commandshell}
+
+ You can call the \texttt{-o} switch using a \texttt{+} symbol at
+ the beginning; this will%
+ \announce{2017-06-25}{+ sign in o switch}
+ concatenate the name of the input file and the text given to the \texttt{-o}
+ switch. For example, the following two calls to \texttt{latexindent.pl} are equivalent:
+ \begin{commandshell}
+latexindent.pl myfile.tex -o=+new
+latexindent.pl myfile.tex -o=myfilenew.tex
+\end{commandshell}
+
+ You can call the \texttt{-o} switch using a \texttt{++} symbol at
+ the end of the name%
+ \announce{2017-06-25}{++ in o switch} of your output
+ file; this tells \texttt{latexindent.pl} to search successively for the name of your
+ output file concatenated with $0, 1, \ldots$ while the name of the output file
+ exists. For example,
+ \begin{commandshell}
+latexindent.pl myfile.tex -o=output++
+\end{commandshell}
+ tells \texttt{latexindent.pl} to output to \texttt{output0.tex}, but if it exists then
+ output to \texttt{output1.tex}, and so on.
+
+ Calling \texttt{latexindent.pl} with simply
+ \begin{commandshell}
+latexindent.pl myfile.tex -o=++
+\end{commandshell}
+ tells it to output to \texttt{myfile0.tex}, but if it exists then output to
+ \texttt{myfile1.tex} and so on.
+
+ The \texttt{+} and \texttt{++} feature of the
+ \texttt{-o} switch can be combined; for example, calling
+ \begin{commandshell}
+latexindent.pl myfile.tex -o=+out++
+\end{commandshell}
+ tells \texttt{latexindent.pl} to output to \texttt{myfileout0.tex}, but if it exists, then
+ try \texttt{myfileout1.tex}, and so on.
+
+ There is no need to specify a file extension when using the \texttt{++}
+ feature, but if you wish to, then you should include it \emph{after} the
+ \texttt{++} symbols, for example
+ \begin{commandshell}
+latexindent.pl myfile.tex -o=+out++.tex
+\end{commandshell}
+
+ See \vref{app:differences} for details of how the interface has changed from Version 2.2
+ to Version 3.0 for this flag.
+\flagbox{-s, --silent}
+ \begin{commandshell}
+latexindent.pl -s myfile.tex
+latexindent.pl myfile.tex -s
+\end{commandshell}
+
+ Silent mode: no output will be given to the terminal.
+
+\flagbox{-t, --trace}
+ \begin{commandshell}
+latexindent.pl -t myfile.tex
+latexindent.pl myfile.tex -t
+\end{commandshell}
+
+ \label{page:traceswitch}
+ Tracing mode: verbose output will be given to \texttt{indent.log}. This is useful if
+ \texttt{latexindent.pl} has made a mistake and you're trying to find out where and why.
+ You might also be interested in learning about \texttt{latexindent.pl}'s thought process
+ -- if so, this switch is for you, although it should be noted that, especially for large
+ files, this does affect performance of the script.
+
+\flagbox{-tt, --ttrace}
+ \begin{commandshell}
+latexindent.pl -tt myfile.tex
+latexindent.pl myfile.tex -tt
+\end{commandshell}
+
+ \emph{More detailed} tracing mode: this option gives more details to
+ \texttt{indent.log}
+ than the standard \texttt{trace} option (note that, even more so than with
+ \texttt{-t}, especially for large files, performance of the script will be
+ affected).
+
+\flagbox{-l, --local[=myyaml.yaml,other.yaml,...]}
+ \begin{commandshell}
+latexindent.pl -l myfile.tex
+latexindent.pl -l=myyaml.yaml myfile.tex
+latexindent.pl -l myyaml.yaml myfile.tex
+latexindent.pl -l first.yaml,second.yaml,third.yaml myfile.tex
+latexindent.pl -l=first.yaml,second.yaml,third.yaml myfile.tex
+latexindent.pl myfile.tex -l=first.yaml,second.yaml,third.yaml
+\end{commandshell}
+
+ \label{page:localswitch}
+ \texttt{latexindent.pl} will always load \texttt{defaultSettings.yaml} (rhymes with camel)
+ and if it is called with the \texttt{-l} switch and it finds
+ \texttt{localSettings.yaml} in the same directory as \texttt{myfile.tex} then these
+ settings will be added to the indentation scheme. Information will be given in
+ \texttt{indent.log} on the success or failure of loading \texttt{localSettings.yaml}.
+
+ The \texttt{-l} flag can take an \emph{optional} parameter which
+ details the name (or names separated by commas) of a YAML file(s) that resides in the
+ same directory as \texttt{myfile.tex}; you can use this option if you would like to
+ load a settings file in the current working directory that is \emph{not}
+ called \texttt{localSettings.yaml}.%
+ \announce{2017-08-21}*{-l switch absolute paths}
+ In fact, you can specify both \emph{relative} and \emph{absolute paths} for
+ your YAML files; for example
+ \begin{commandshell}
+latexindent.pl -l=../../myyaml.yaml myfile.tex
+latexindent.pl -l=/home/cmhughes/Desktop/myyaml.yaml myfile.tex
+latexindent.pl -l=C:\Users\cmhughes\Desktop\myyaml.yaml myfile.tex
+\end{commandshell}
+ You will find a lot of other explicit demonstrations of how to use the
+ \texttt{-l} switch throughout this documentation,
+
+ You can call the \texttt{-l} switch with a `+' symbol either before or after
+ \announce{2017-06-25}{+ sign with -l switch} another YAML file; for example:
+ \begin{commandshell}
+latexindent.pl -l=+myyaml.yaml myfile.tex
+latexindent.pl -l "+ myyaml.yaml" myfile.tex
+latexindent.pl -l=myyaml.yaml+ myfile.tex
+\end{commandshell}
+ which translate, respectively, to
+ \begin{commandshell}
+latexindent.pl -l=localSettings.yaml,myyaml.yaml myfile.tex
+latexindent.pl -l=localSettings.yaml,myyaml.yaml myfile.tex
+latexindent.pl -l=myyaml.yaml,localSettings.yaml myfile.tex
+\end{commandshell}
+ Note that the following is \emph{not} allowed:
+ \begin{commandshell}
+latexindent.pl -l+myyaml.yaml myfile.tex
+\end{commandshell}
+ and
+ \begin{commandshell}
+latexindent.pl -l + myyaml.yaml myfile.tex
+\end{commandshell}
+ will \emph{only} load \texttt{localSettings.yaml}, and \texttt{myyaml.yaml}
+ will be ignored. If you wish to use spaces between any of the YAML settings, then you
+ must wrap the entire list of YAML files in quotes, as demonstrated above.
+
+ You may also choose to omit the \texttt{yaml} extension, such as
+ \announce{2017-06-25}{no extension for -l switch}
+ \begin{commandshell}
+latexindent.pl -l=localSettings,myyaml myfile.tex
+\end{commandshell}
+\flagbox{-y, --yaml=yaml settings}
+ \begin{commandshell}
+latexindent.pl myfile.tex -y="defaultIndent: ' '"
+latexindent.pl myfile.tex -y="defaultIndent: ' ',maximumIndentation:' '"
+latexindent.pl myfile.tex -y="indentRules: one: '\t\t\t\t'"
+latexindent.pl myfile.tex -y='modifyLineBreaks:environments:EndStartsOnOwnLine:3' -m
+latexindent.pl myfile.tex -y='modifyLineBreaks:environments:one:EndStartsOnOwnLine:3' -m
+\end{commandshell}
+ \label{page:yamlswitch}You%
+ \announce{2017-08-21}{the -y switch} can specify YAML settings from the command line using the
+ \texttt{-y} or \texttt{--yaml} switch;
+ sample demonstrations are given above. Note, in particular, that multiple settings can
+ be specified by separating them via commas. There is a further option to use a
+ \texttt{;} to separate fields, which is demonstrated in
+ \vref{sec:yamlswitch}.
+
+ Any settings specified via this switch will be loaded \emph{after} any
+ specified using the \texttt{-l} switch. This is discussed further in
+ \vref{sec:loadorder}.
+\flagbox{-d, --onlydefault}
+ \begin{commandshell}
+latexindent.pl -d myfile.tex
+\end{commandshell}
+
+ Only \texttt{defaultSettings.yaml}: you might like to read \cref{sec:defuseloc} before using
+ this switch. By default, \texttt{latexindent.pl} will always search for
+ \texttt{indentconfig.yaml} or \texttt{.indentconfig.yaml} in your home directory. If you would
+ prefer it not to do so then (instead of deleting or renaming \texttt{indentconfig.yaml} or
+ \texttt{.indentconfig.yaml}) you can simply call the script with the \texttt{-d}
+ switch; note that this will also tell the script to ignore \texttt{localSettings.yaml} even
+ if it has been called with the \texttt{-l} switch; \texttt{latexindent.pl}%
+ \announce{2017-08-21}*{updated -d switch} will also ignore any settings specified from the
+ \texttt{-y} switch.
+
+\flagbox{-c, --cruft=<directory>}
+ \begin{commandshell}
+latexindent.pl -c=/path/to/directory/ myfile.tex
+\end{commandshell}
+
+ If you wish to have backup files and \texttt{indent.log} written to a directory other
+ than the current working directory, then you can send these `cruft' files to another
+ directory. % this switch was made as a result of http://tex.stackexchange.com/questions/142652/output-latexindent-auxiliary-files-to-a-different-directory
+
+\flagbox{-g, --logfile=<name of log file>}
+ \begin{commandshell}
+latexindent.pl -g=other.log myfile.tex
+latexindent.pl -g other.log myfile.tex
+latexindent.pl --logfile other.log myfile.tex
+latexindent.pl myfile.tex -g other.log
+\end{commandshell}
+
+ By default, \texttt{latexindent.pl} reports information to \texttt{indent.log}, but
+ if you wish to change the name of this file, simply call the script with your chosen name
+ after the \texttt{-g} switch as demonstrated above.
+
+\flagbox{-sl, --screenlog}
+ \begin{commandshell}
+latexindent.pl -sl myfile.tex
+latexindent.pl -screenlog myfile.tex
+\end{commandshell}
+ Using this%
+ \announce{2018-01-13}{screenlog switch created} option tells
+ \texttt{latexindent.pl} to output the log file to the screen, as well as to your chosen
+ log file.
+
+\flagbox{-m, --modifylinebreaks}
+ \begin{commandshell}
+latexindent.pl -m myfile.tex
+latexindent.pl -modifylinebreaks myfile.tex
+\end{commandshell}
+
+ One of the most exciting developments in Version~3.0 is the ability to modify line
+ breaks; for full details see \vref{sec:modifylinebreaks}
+
+ \texttt{latexindent.pl} can also be called on a file without the file extension, for
+ example
+ \begin{commandshell}
+latexindent.pl myfile
+\end{commandshell}
+ and in which case, you can specify the order in which extensions are searched for; see
+ \vref{lst:fileExtensionPreference} for full details.
+\flagbox{STDIN}
+ \begin{commandshell}
+cat myfile.tex | latexindent.pl
+\end{commandshell}
+ \texttt{latexindent.pl} will%
+ \announce{2018-01-13}{STDIN allowed} allow input from STDIN, which means that you can pipe output from
+ other commands directly into the script. For example assuming that you have content in
+ \texttt{myfile.tex}, then the above command will output the results of operating upon
+ \texttt{myfile.tex}
+
+ Similarly, if you%
+ \announce{2018-01-13}*{no options/filename updated} simply type
+ \texttt{latexindent.pl} at the command line, then it will expect (STDIN) input from the
+ command line.
+ \begin{commandshell}
+latexindent.pl
+\end{commandshell}
+
+ Once you have finished typing your input, you can press
+ \begin{itemize}
+ \item \texttt{CTRL+D} on Linux
+ \item \texttt{CTRL+Z} followed by \texttt{ENTER} on Windows
+ \end{itemize}
+ to signify that your input has finished. Thanks to \cite{xu-cheng} for an update
+ to this feature.
+\flagbox{-r, --replacement}
+ \begin{commandshell}
+latexindent.pl -r myfile.tex
+latexindent.pl -replacement myfile.tex
+\end{commandshell}
+ You can%
+ \announce*{2019-07-13}{replacement mode switch} call
+ \texttt{latexindent.pl} with the \texttt{-r} switch to instruct it to perform
+ replacements/substitutions on your file; full details and examples are given in
+ \vref{sec:replacements}.
+
+\flagbox{-rv, --replacementrespectverb}
+ \begin{commandshell}
+latexindent.pl -rv myfile.tex
+latexindent.pl -replacementrespectverb myfile.tex
+\end{commandshell}
+ You can%
+ \announce*{2019-07-13}{replacement mode switch, respecting verbatim} instruct
+ \texttt{latexindent.pl} to perform replacements/substitutions by using the
+ \texttt{-rv} switch, but will \emph{respect verbatim code blocks}; full details and
+ examples are given in \vref{sec:replacements}.
+
+\flagbox{-rr, --onlyreplacement}
+ \begin{commandshell}
+latexindent.pl -rr myfile.tex
+latexindent.pl -onlyreplacement myfile.tex
+\end{commandshell}
+ You can%
+ \announce*{2019-07-13}{replacement (only) mode switch} instruct
+ \texttt{latexindent.pl} to skip all of its other indentation operations and
+ \emph{only} perform replacements/substitutions by using the
+ \texttt{-rr} switch; full details and examples are given in
+ \vref{sec:replacements}.
+
+\subsection{From arara}\label{sec:arara}
+ Using \texttt{latexindent.pl} from the command line is fine for some folks, but others
+ may find it easier to use from \texttt{arara}; you can find the arara rule for
+ \texttt{latexindent.pl} and its associated documentation at \cite{paulo}.
diff --git a/support/latexindent/documentation/sec-indent-config-and-settings.tex b/support/latexindent/documentation/sec-indent-config-and-settings.tex
new file mode 100644
index 0000000000..cb551194c0
--- /dev/null
+++ b/support/latexindent/documentation/sec-indent-config-and-settings.tex
@@ -0,0 +1,179 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\section{indentconfig.yaml, local settings and the -y switch }\label{sec:indentconfig}
+ The behaviour of \texttt{latexindent.pl} is controlled from the settings specified in any
+ of the YAML files that you tell it to load. By default, \texttt{latexindent.pl} will only
+ load \texttt{defaultSettings.yaml}, but there are a few ways that you can tell it to load your
+ own settings files.
+
+\subsection{indentconfig.yaml and .indentconfig.yaml}
+ \texttt{latexindent.pl} will always check your home directory for \texttt{indentconfig.yaml}
+ and \texttt{.indentconfig.yaml} (unless
+ it is called with the \texttt{-d} switch), which is a plain text file you can create that contains the
+ \emph{absolute} paths for any settings files that you wish \texttt{latexindent.pl}
+ to load. There is no difference between \texttt{indentconfig.yaml} and
+ \texttt{.indentconfig.yaml}, other than the fact that \texttt{.indentconfig.yaml} is a `hidden'
+ file; thank you to \cite{jacobo-diaz-hidden-config} for providing this feature. In what follows, we
+ will use \texttt{indentconfig.yaml}, but it is understood that this could equally represent
+ \texttt{.indentconfig.yaml}. If you have both files in existence then \texttt{indentconfig.yaml}
+ takes priority.
+
+ For Mac and Linux users, their home directory is \texttt{~/username} while Windows
+ (Vista onwards) is \lstinline!C:\Users\username!\footnote{If you're not sure
+ where to put \texttt{indentconfig.yaml}, don't
+ worry \texttt{latexindent.pl} will tell you in the log file exactly where to
+ put it assuming it doesn't exist already.} \Cref{lst:indentconfig}
+ shows a sample \texttt{indentconfig.yaml} file.
+
+ \begin{yaml}{\texttt{indentconfig.yaml} (sample)}{lst:indentconfig}
+# Paths to user settings for latexindent.pl
+#
+# Note that the settings will be read in the order you
+# specify here- each successive settings file will overwrite
+# the variables that you specify
+
+paths:
+- /home/cmhughes/Documents/yamlfiles/mysettings.yaml
+- /home/cmhughes/folder/othersettings.yaml
+- /some/other/folder/anynameyouwant.yaml
+- C:\Users\chughes\Documents\mysettings.yaml
+- C:\Users\chughes\Desktop\test spaces\more spaces.yaml
+\end{yaml}
+
+ Note that the \texttt{.yaml} files you specify in \texttt{indentconfig.yaml} will be
+ loaded in the order in which you write them. Each file doesn't have to have every switch
+ from \texttt{defaultSettings.yaml}; in fact, I recommend that you only keep the switches that
+ you want to \emph{change} in these settings files.
+
+ To get started with your own settings file, you might like to save a copy of
+ \texttt{defaultSettings.yaml} in another directory and call it, for example,
+ \texttt{mysettings.yaml}. Once you have added the path to \texttt{indentconfig.yaml} you can
+ change the switches and add more code-block names to it as you see fit -- have a look at
+ \cref{lst:mysettings} for an example that uses four tabs for the default indent, adds
+ the \texttt{tabbing} environment/command to the list of environments that contains
+ alignment delimiters; you might also like to refer to the many YAML files detailed
+ throughout the rest of this documentation.
+
+ \begin{yaml}{\texttt{mysettings.yaml} (example)}{lst:mysettings}
+# Default value of indentation
+defaultIndent: "\t\t\t\t"
+
+# environments that have tab delimiters, add more
+# as needed
+lookForAlignDelims:
+ tabbing: 1
+\end{yaml}
+
+ You can make sure that your settings are loaded by checking \texttt{indent.log} for
+ details -- if you have specified a path that \texttt{latexindent.pl} doesn't recognise
+ then you'll get a warning, otherwise you'll get confirmation that \texttt{latexindent.pl}
+ has read your settings file \footnote{Windows users
+ may find that they have to end \texttt{.yaml} files with a blank line}.
+
+ \begin{warning}
+ When editing \texttt{.yaml} files it is \emph{extremely} important
+ to remember how sensitive they are to spaces. I highly recommend copying
+ and pasting from \texttt{defaultSettings.yaml} when you create your
+ first \texttt{whatevernameyoulike.yaml} file.
+
+ If \texttt{latexindent.pl} can not read your \texttt{.yaml} file it
+ will tell you so in \texttt{indent.log}.
+ \end{warning}
+
+\subsection{localSettings.yaml}\label{sec:localsettings}
+ The \texttt{-l} switch tells \texttt{latexindent.pl} to look for
+ \texttt{localSettings.yaml} in the \emph{same directory} as \texttt{myfile.tex}. For
+ example, if you use the following command
+ \begin{commandshell}
+latexindent.pl -l myfile.tex
+\end{commandshell}
+ then \texttt{latexindent.pl} will (assuming it exists) load \texttt{localSettings.yaml} from
+ the same directory as \texttt{myfile.tex}.
+
+ If you'd prefer to name your \texttt{localSettings.yaml} file something different, (say,
+ \texttt{mysettings.yaml} as in \cref{lst:mysettings}) then you can call
+ \texttt{latexindent.pl} using, for example,
+ \begin{commandshell}
+latexindent.pl -l=mysettings.yaml myfile.tex
+\end{commandshell}
+
+ Any settings file(s) specified using the \texttt{-l} switch will be read
+ \emph{after} \texttt{defaultSettings.yaml} and, assuming they exist, any user setting
+ files specified in \texttt{indentconfig.yaml}.
+
+ Your settings file can contain any switches that you'd like to change; a sample is shown
+ in \cref{lst:localSettings}, and you'll find plenty of further examples throughout this
+ manual.
+
+ \begin{yaml}{\texttt{localSettings.yaml} (example)}{lst:localSettings}
+# verbatim environments - environments specified
+# here will not be changed at all!
+verbatimEnvironments:
+ cmhenvironment: 0
+ myenv: 1
+\end{yaml}
+
+ You can make sure that your settings file has been loaded by checking
+ \texttt{indent.log} for details; if it can not be read then you receive a warning,
+ otherwise you'll get confirmation that \texttt{latexindent.pl} has read your settings
+ file.
+
+\subsection{The -y|yaml switch}\label{sec:yamlswitch}
+ You%
+ \announce{2017-08-21}{demonstration of the -y switch} may use the
+ \texttt{-y} switch to load your settings; for example, if you wished to
+ specify the settings from \cref{lst:localSettings} using the \texttt{-y} switch,
+ then you could use the following command:
+ \begin{commandshell}
+latexindent.pl -y="verbatimEnvironments:cmhenvironment:0;myenv:1" myfile.tex
+\end{commandshell}
+ Note the use of \texttt{;} to specify another field within
+ \texttt{verbatimEnvironments}. This is shorthand, and equivalent, to using the following
+ command:
+ \begin{commandshell}
+latexindent.pl -y="verbatimEnvironments:cmhenvironment:0,verbatimEnvironments:myenv:1" myfile.tex
+\end{commandshell}
+ You may, of course, specify settings using the \texttt{-y} switch as well as,
+ for example, settings loaded using the \texttt{-l} switch; for example,
+ \begin{commandshell}
+latexindent.pl -l=mysettings.yaml -y="verbatimEnvironments:cmhenvironment:0;myenv:1" myfile.tex
+\end{commandshell}
+ Any settings specified using the \texttt{-y} switch will be loaded
+ \emph{after} any specified using \texttt{indentconfig.yaml} and the
+ \texttt{-l} switch.
+
+ If you wish to specify any regex-based settings using the \texttt{-y} switch,
+ it is important not to use quotes surrounding the regex; for example, with reference to
+ the `one sentence per line' feature (\vref{sec:onesentenceperline}) and the listings within
+ \vref{lst:sentencesEndWith}, the following settings give the option to have sentences end
+ with a semicolon
+ \begin{commandshell}
+latexindent.pl -m --yaml='modifyLineBreaks:oneSentencePerLine:sentencesEndWith:other:\;'
+\end{commandshell}
+
+\subsection{Settings load order}\label{sec:loadorder}
+ \texttt{latexindent.pl} loads the settings files in the following order:
+ \begin{enumerate}
+ \item \texttt{defaultSettings.yaml} is always loaded, and can not be renamed;
+ \item \texttt{anyUserSettings.yaml} and any other arbitrarily-named files specified in
+ \texttt{indentconfig.yaml};
+ \item \texttt{localSettings.yaml} but only if found in the same directory as \texttt{myfile.tex}
+ and called with \texttt{-l} switch; this file can be renamed, provided that
+ the call to \texttt{latexindent.pl} is adjusted accordingly (see \cref{sec:localsettings}).
+ You may specify both relative and absolute%
+ \announce{2017-08-21}*{-l absolute paths} paths to other YAML files using the \texttt{-l} switch,
+ separating multiple files using commas;
+ \item any settings%
+ \announce{2017-08-21}{-y switch load order} specified in the
+ \texttt{-y} switch.
+ \end{enumerate}
+ A visual representation of this is given in \cref{fig:loadorder}.
+
+ \begin{figure}[!htb]
+ \centering
+ \input{figure-schematic}
+ \caption{Schematic of the load order described in \cref{sec:loadorder}; solid lines represent
+ mandatory files, dotted lines represent optional files. \texttt{indentconfig.yaml} can
+ contain as many files as you like. The files will be loaded in order; if you specify
+ settings for the same field in more than one file, the most recent takes priority. }
+ \label{fig:loadorder}
+ \end{figure}
diff --git a/support/latexindent/documentation/sec-introduction.tex b/support/latexindent/documentation/sec-introduction.tex
new file mode 100644
index 0000000000..c6fafd9269
--- /dev/null
+++ b/support/latexindent/documentation/sec-introduction.tex
@@ -0,0 +1,130 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\section{Introduction}
+\subsection{Thanks}
+ I first created \texttt{latexindent.pl} to help me format chapter files in a big project.
+ After I blogged about it on the \TeX{} stack exchange
+ \cite{cmhblog} I received some positive feedback and follow-up feature requests.
+ A big thank you to Harish Kumar \cite{harish} who helped to develop and test the
+ initial versions of the script.
+
+ The \texttt{YAML}-based interface of \texttt{latexindent.pl} was inspired by the
+ wonderful \texttt{arara} tool; any similarities are deliberate, and I hope that
+ it is perceived as the compliment that it is. Thank you to Paulo Cereda and the team for
+ releasing this awesome tool; I initially worried that I was going to have to make a GUI
+ for \texttt{latexindent.pl}, but the release of \texttt{arara} has meant there is
+ no need.
+
+ There have been several contributors to the project so far (and hopefully more in the
+ future!); thank you very much to the people detailed in \vref{sec:contributors} for their
+ valued contributions, and thank you to those who report bugs and request features at
+ \cite{latexindent-home}.
+
+\subsection{License}
+ \texttt{latexindent.pl} is free and open source, and it always will be; it
+ is released under the GNU General Public License v3.0.
+
+ Before you start using it on any important files, bear in mind that
+ \texttt{latexindent.pl} has the option to overwrite your \texttt{.tex} files. It
+ will always make at least one backup (you can choose how many it makes, see
+ \cpageref{page:onlyonebackup}) but you should still be careful when using it. The script has
+ been tested on many files, but there are some known limitations (see
+ \cref{sec:knownlimitations}). You, the user, are responsible for ensuring that you maintain
+ backups of your files before running \texttt{latexindent.pl} on them. I think it is
+ important at this stage to restate an important part of the license here:
+ \begin{quote}\itshape
+ 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.
+ \end{quote}
+ There is certainly no malicious intent in releasing this script, and I do hope that it
+ works as you expect it to; if it does not, please first of all make sure that you have
+ the correct settings, and then feel free to let me know at \cite{latexindent-home} with a
+ complete minimum working example as I would like to improve the code as much as possible.
+ \begin{warning}
+ Before you try the script on anything important (like your thesis), test it
+ out on the sample files in the \texttt{test-case} directory \cite{latexindent-home}.
+ \end{warning}
+
+ \emph{If you have used any version 2.* of \texttt{latexindent.pl}, there
+ are a few changes to the interface; see \vref{app:differences} and the comments
+ throughout this document for details}.
+
+\subsection{About this documentation}
+ As you read through this documentation, you will see many listings; in this version of
+ the documentation, there are a total of \totallstlistings. This may seem a lot, but I
+ deem it necessary in presenting the various different options of \texttt{latexindent.pl}
+ and the associated output that they are capable of producing.
+
+ The different listings are presented using different styles:
+
+ \begin{minipage}{.4\textwidth}
+ \cmhlistingsfromfile{demonstrations/demo-tex.tex}{\texttt{demo-tex.tex}}{lst:demo-tex}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.4\textwidth}
+ This type of listing is a \texttt{.tex} file.
+ \end{minipage}%
+
+ \begin{minipage}{.4\textwidth}
+ \cmhlistingsfromfile[style=fileExtensionPreference]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{fileExtensionPreference}}{lst:fileExtensionPreference-demo}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.4\textwidth}
+ This type of listing is a \texttt{.yaml} file; when you see line numbers given (as here)
+ it means that the snippet is taken directly from \texttt{defaultSettings.yaml}, discussed in
+ detail in \vref{sec:defuseloc}.
+ \end{minipage}%
+
+ \begin{minipage}{.55\textwidth}
+ \cmhlistingsfromfile[style=modifylinebreaks]*{../defaultSettings.yaml}[MLB-TCB,width=.85\linewidth,before=\centering]{\texttt{modifyLineBreaks}}{lst:modifylinebreaks-demo}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.4\textwidth}
+ This type of listing is a \texttt{.yaml} file, but it will only
+ be relevant when the \texttt{-m} switch is active; see \vref{sec:modifylinebreaks}
+ for more details.
+ \end{minipage}%
+
+ \begin{minipage}{.55\textwidth}
+ \cmhlistingsfromfile*[style=replacements]*{../defaultSettings.yaml}[replace-TCB,width=.85\linewidth,before=\centering]{\texttt{replacements}}{lst:replacements-demo}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.4\textwidth}
+ This type of listing is a \texttt{.yaml} file, but it will only
+ be relevant when the \texttt{-r} switch is active; see \vref{sec:replacements}
+ for more details.
+ \end{minipage}%
+
+ % \begin{latexonly}
+ You will occasionally see dates shown in the margin (for example, next to this
+ paragraph!)%
+ \announce{2017-06-25}{announce} which detail the date
+ of the version in which the feature was implemented; the `N' stands for `new as of the
+ date shown' and `U' stands for `updated as of the date shown'. If you see \stardemo, it
+ means that the feature is either new (N) or updated (U) as of the release of the current
+ version; if you see \stardemo\, attached to a listing, then it means that listing is new
+ (N) or updated (U) as of the current version. If you have not read this document before
+ (and even if you have!), then you can ignore every occurrence of the \stardemo; they are
+ simply there to highlight new and updated features. The new and updated features in this
+ documentation (\gitRel) are on the following pages: \listOfNewFeatures
+ % \end{latexonly}
+
+\subsection{Quick start}\label{sec:quickstart}
+ If you'd like to get started with \texttt{latexindent.pl} then simply type
+ \begin{commandshell}
+latexindent.pl myfile.tex
+\end{commandshell}
+ from the command line. If you receive an error message such as that given in
+ \cref{lst:poss-errors}, then you need to install the missing perl modules.
+ \begin{cmhlistings}[style=tcblatex,language=Perl]{Possible error messages}{lst:poss-errors}
+Can't locate File/HomeDir.pm in @INC (@INC contains: /Library/Perl/5.12/darwin-thread-multi-2level /Library/Perl/5.12 /Network/Library/Perl/5.12/darwin-thread-multi-2level /Network/Library/Perl/5.12 /Library/Perl/Updates/5.12.4/darwin-thread-multi-2level /Library/Perl/Updates/5.12.4 /System/Library/Perl/5.12/darwin-thread-multi-2level /System/Library/Perl/5.12 /System/Library/Perl/Extras/5.12/darwin-thread-multi-2level /System/Library/Perl/Extras/5.12 .) at helloworld.pl line 10.
+BEGIN failed--compilation aborted at helloworld.pl line 10.
+\end{cmhlistings}
+ \texttt{latexindent.pl} ships with a script to help with this process; if you run the
+ following script, you should be prompted to install the appropriate modules.
+ \begin{commandshell}
+perl latexindent-module-installer.pl
+\end{commandshell}
+ You might also like to see \href{https://stackoverflow.com/questions/19590042/error-cant-locate-file-homedir-pm-in-inc}{https://stackoverflow.com/questions/19590042/error-cant-locate-file-homedir-pm-in-inc}, for example, as well as
+ \vref{sec:requiredmodules}.
diff --git a/support/latexindent/documentation/sec-replacements.tex b/support/latexindent/documentation/sec-replacements.tex
new file mode 100644
index 0000000000..6bc7223d4d
--- /dev/null
+++ b/support/latexindent/documentation/sec-replacements.tex
@@ -0,0 +1,372 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\section{The -r, -rv and -rr switches}\label{sec:replacements}
+ \fancyhead[R]{\bfseries\thepage%
+ \tikz[remember picture,overlay] {
+ \node at (1,0){\includegraphics{logo-bw}}; }
+ }
+
+ You can instruct \texttt{latexindent.pl} to perform replacements/substitutions on your
+ \announce*{2019-07-13}{replacement mode switches}
+ file by using any of the \texttt{-r}, \texttt{-rv} or
+ \texttt{-rr} switches:
+ \begin{itemize}
+ \item the \texttt{-r} switch will perform indentation and replacements, not
+ respecting verbatim code blocks;
+ \item the \texttt{-rv} switch will perform indentation and replacements, and
+ \emph{will} respect verbatim code blocks;
+ \item the \texttt{-rr} switch will \emph{not} perform indentation, and
+ will perform replacements not respecting verbatim code blocks.
+ \end{itemize}
+
+ We will demonstrate each of the \texttt{-r}, \texttt{-rv} and
+ \texttt{-rr} switches, but a summary is given in \cref{tab:replacementswitches}.
+
+ \begin{table}[!htb]
+ \centering
+ \caption{The replacement mode switches}\label{tab:replacementswitches}
+ \begin{tabular}{rcc}
+ \toprule
+ switch & indentation? & respect verbatim? \\
+ \midrule
+ \texttt{-r} & \faCheck & \faClose \\
+ \texttt{-rv} & \faCheck & \faCheck \\
+ \texttt{-rr} & \faClose & \faClose \\
+ \bottomrule
+ \end{tabular}
+ \end{table}
+
+ The default value of the \texttt{replacements} field is shown in
+ \cref{lst:replacements}; as with all of the other fields, you are encouraged to customise
+ and change this as you see fit. The options in this field will \emph{only} be
+ considered if the \texttt{-r}, \texttt{-rv} or
+ \texttt{-rr} switches are active; when discussing YAML settings related to the
+ replacement-mode switches, we will use the style given in \cref{lst:replacements}.
+
+ \cmhlistingsfromfile*[style=replacements]*{../defaultSettings.yaml}[width=0.95\linewidth,before=\centering,replace-TCB]{\texttt{replacements}}{lst:replacements}
+
+ The first entry within the \texttt{replacements} field is \texttt{amalgamate}, and
+ is \emph{optional}; by default it is set to 1, so that replacements will be
+ amalgamated from each settings file that you specify. As you'll see in the demonstrations
+ that follow, there is no need to specify this field.
+
+ You'll notice that, by default, there is only \emph{one} entry in the
+ \texttt{replacements} field, but it can take as many entries as you would like; each
+ one needs to begin with a \texttt{-} on its own line.
+
+\subsection{Introduction to replacements}
+ Let's explore the action of the default settings, and then we'll demonstrate the feature
+ with further examples. With reference to \cref{lst:replacements}, the default action will
+ replace every instance of the text \texttt{latexindent.pl} with \texttt{pl.latexindent}.
+
+ Beginning with the code in \cref{lst:replace1} and running the command
+ \begin{commandshell}
+latexindent.pl -r replace1.tex
+\end{commandshell}
+ gives the output given in \cref{lst:replace1-r1}.
+
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/replace1.tex}{\texttt{replace1.tex}}{lst:replace1}
+ \cmhlistingsfromfile*{demonstrations/replace1-r1.tex}{\texttt{replace1.tex} default}{lst:replace1-r1}
+ \end{cmhtcbraster}
+
+ If we don't wish to perform this replacement, then we can tweak the default settings of
+ \vref{lst:replacements} by changing \texttt{lookForThis} to 0; we perform this action
+ in \cref{lst:replace1-yaml}, and run the command
+ \begin{commandshell}
+latexindent.pl -r replace1.tex -l=replace1.yaml
+\end{commandshell}
+ which gives the output in \cref{lst:replace1-mod1}.
+
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/replace1-mod1.tex}{\texttt{replace1.tex} using \cref{lst:replace1-yaml}}{lst:replace1-mod1}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/replace1.yaml}[replace-TCB]{\texttt{replace1.yaml}}{lst:replace1-yaml}
+ \end{cmhtcbraster}
+
+ Note that in \cref{lst:replace1-yaml} we have specified \texttt{amalgamate} as 0 so
+ that the default replacements are overwritten.
+
+ We haven't yet discussed the \texttt{when} field; don't worry, we'll get to it
+ as part of the discussion in what follows.
+
+\subsection{The two types of replacements}
+ There are two types of replacements:
+ \begin{enumerate}
+ \item \emph{string}-based replacements, which replace the string in
+ \emph{this} with the string in \emph{that}.
+ If you specify \texttt{this} and you do not specify \texttt{that}, then
+ the \texttt{that} field will be assumed to be empty.
+ \item \emph{regex}-based replacements, which use the \texttt{substitution} field.
+ \end{enumerate}
+ We will demonstrate both in the examples that follow.
+
+ \texttt{latexindent.pl} chooses which type of replacement to make based on which fields
+ have been specified; if the \texttt{this} field is specified, then it will make
+ \emph{string}-based replacements, regardless of if \texttt{substitution} is
+ present or not.
+
+\subsection{Examples of replacements}
+ \begin{example}
+ We begin with code given in \cref{lst:colsep}
+
+ \cmhlistingsfromfile*{demonstrations/colsep.tex}{\texttt{colsep.tex}}{lst:colsep}
+
+ Let's assume that our goal is to remove both of the \texttt{arraycolsep} statements; we can achieve this in
+ a few different ways.
+
+ Using the YAML in \cref{lst:colsep-yaml}, and running the command
+ \begin{commandshell}
+latexindent.pl -r colsep.tex -l=colsep.yaml
+\end{commandshell}
+ then we achieve the output in \cref{lst:colsep-mod0}.
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/colsep-mod0.tex}{\texttt{colsep.tex} using \cref{lst:colsep}}{lst:colsep-mod0}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/colsep.yaml}[replace-TCB]{\texttt{colsep.yaml}}{lst:colsep-yaml}
+ \end{cmhtcbraster}
+ Note that in \cref{lst:colsep-yaml}, we have specified \emph{two} separate fields, each with their own `\emph{this}' field;
+ furthermore, for both of the separate fields, we have not specified `\texttt{that}', so the \texttt{that} field
+ is assumed to be blank by \texttt{latexindent.pl};
+
+ We can make the YAML in \cref{lst:colsep-yaml} more concise by exploring the \texttt{substitution} field. Using
+ the settings in \cref{lst:colsep1} and running the command
+ \begin{commandshell}
+latexindent.pl -r colsep.tex -l=colsep1.yaml
+\end{commandshell}
+ then we achieve the output in \cref{lst:colsep-mod1}.
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth,
+ raster force size=false,
+ raster column 1/.style={add to width=-.1\textwidth}]
+ \cmhlistingsfromfile*{demonstrations/colsep-mod1.tex}{\texttt{colsep.tex} using \cref{lst:colsep1}}{lst:colsep-mod1}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/colsep1.yaml}[replace-TCB,width=0.6\textwidth]{\texttt{colsep1.yaml}}{lst:colsep1}
+ \end{cmhtcbraster}
+
+ The code given in \cref{lst:colsep1} is an example of a \emph{regular expression}, which we may abbreviate to \emph{regex}
+ in what follows. This manual is not intended to be
+ a tutorial on regular expressions; you might like to read, for example, \cite{masteringregexp} for a detailed
+ covering of the topic. With reference to \cref{lst:colsep1}, we do note the following:
+ \begin{itemize}
+ \item the general form of the \texttt{substitution} field is \lstinline!s/regex/replacement/modifiers!. You can
+ place any regular expression you like within this;
+ \item we have `escaped' the backslash by using \lstinline!\\!
+ \item we have used \lstinline!\d+! to represent \emph{at least} one digit
+ \item the \texttt{s} \emph{modifier} (in the \texttt{sg} at the end of the line) instructs \texttt{latexindent.pl} to
+ treat your file as one single line;
+ \item the \texttt{g} \emph{modifier} (in the \texttt{sg} at the end of the line) instructs \texttt{latexindent.pl} to
+ make the substitution \emph{globally} throughout your file; you might try removing
+ the \texttt{g} modifier from \cref{lst:colsep1} and observing the
+ difference in output.
+ \end{itemize}
+ You might like to see \href{https://perldoc.perl.org/perlre.html#Modifiers}{https://perldoc.perl.org/perlre.html\#Modifiers}
+ for details of modifiers; in general, I recommend starting with the \texttt{sg} modifiers for this feature.
+ \end{example}
+
+ \begin{example}
+ We'll keep working with the file in \vref{lst:colsep} for this example.
+
+ Using the YAML in \cref{lst:multi-line}, and running the command
+ \begin{commandshell}
+latexindent.pl -r colsep.tex -l=multi-line.yaml
+\end{commandshell}
+ then we achieve the output in \cref{lst:colsep-mod2}.
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/colsep-mod2.tex}{\texttt{colsep.tex} using \cref{lst:multi-line}}{lst:colsep-mod2}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/multi-line.yaml}[replace-TCB]{\texttt{multi-line.yaml}}{lst:multi-line}
+ \end{cmhtcbraster}
+ With reference to \cref{lst:multi-line}, we have specified a \emph{multi-line} version of \texttt{this} by employing the \emph{literal}
+ YAML style \lstinline!|-!. See, for example, \href{https://stackoverflow.com/questions/3790454/in-yaml-how-do-i-break-a-string-over-multiple-lines}{https://stackoverflow.com/questions/3790454/in-yaml-how-do-i-break-a-string-over-multiple-lines}
+ for further options, all of which can be used in your YAML file.
+
+ This is a natural point to explore the \texttt{when} field, specified in \vref{lst:replacements}. This field can take two values: \emph{before}
+ and \emph{after}, which respectively instruct \texttt{latexindent.pl} to perform the replacements \emph{before} indentation or \emph{after} it.
+ The default value is \texttt{before}.
+
+ Using the YAML in \cref{lst:multi-line1}, and running the command
+ \begin{commandshell}
+latexindent.pl -r colsep.tex -l=multi-line1.yaml
+\end{commandshell}
+ then we achieve the output in \cref{lst:colsep-mod3}.
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/colsep-mod3.tex}{\texttt{colsep.tex} using \cref{lst:multi-line1}}{lst:colsep-mod3}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/multi-line1.yaml}[replace-TCB]{\texttt{multi-line1.yaml}}{lst:multi-line1}
+ \end{cmhtcbraster}
+ We note that, because we have specified \texttt{when: after}, that \texttt{latexindent.pl} has not found the string specified
+ in \cref{lst:multi-line1} within the file in \vref{lst:colsep}. As it has looked for the string within \cref{lst:multi-line1} \emph{after} the indentation has been performed. After
+ indentation, the string as written in \cref{lst:multi-line1} is no longer part of the file, and has therefore not been replaced.
+
+ As a final note on this example, if you use the \texttt{-rr} switch, as follows,
+ \begin{commandshell}
+latexindent.pl -rr colsep.tex -l=multi-line1.yaml
+\end{commandshell}
+ then the \texttt{when} field is ignored, no indentation is done, and the output is as in \cref{lst:colsep-mod2}.
+ \end{example}
+
+ \begin{example}
+ An important part of the substitution routine is in \emph{capture groups}.
+
+ Assuming that we start with
+ the code in \cref{lst:displaymath}, let's assume that our goal is to replace each occurrence of \lstinline!$$...$$!
+ with \lstinline!\begin{equation*}...\end{equation*}!. This example is partly motivated by \href{https://tex.stackexchange.com/questions/242150/good-looking-latex-code}{tex stackexchange question 242150}.
+
+ \cmhlistingsfromfile*{demonstrations/displaymath.tex}{\texttt{displaymath.tex}}{lst:displaymath}
+
+ We use the settings in \cref{lst:displaymath1} and run the command
+ \begin{commandshell}
+latexindent.pl -r displaymath.tex -l=displaymath1.yaml
+\end{commandshell}
+ to receive the output given in \cref{lst:displaymath-mod1}.
+
+ \begin{cmhtcbraster}[raster left skip=-3.75cm,
+ raster right skip=-2cm,]
+ \cmhlistingsfromfile*{demonstrations/displaymath-mod1.tex}{\texttt{displaymath.tex} using \cref{lst:displaymath1}}{lst:displaymath-mod1}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/displaymath1.yaml}[replace-TCB]{\texttt{displaymath1.yaml}}{lst:displaymath1}
+ \end{cmhtcbraster}
+
+ A few notes about \cref{lst:displaymath1}:
+ \begin{enumerate}
+ \item we have used the \texttt{x} modifier, which allows us to have white space
+ within the regex;
+ \item we have used a capture group, \lstinline!(.*?)! which captures the content between
+ the \lstinline!$$...$$! into the special variable, \lstinline!$1!;
+ \item we have used the content of the capture group, \lstinline!$1!, in the
+ replacement text.
+ \end{enumerate}
+ See \href{https://perldoc.perl.org/perlre.html#Capture-groups}{https://perldoc.perl.org/perlre.html\#Capture-groups} for a discussion
+ of capture groups.
+
+ The features of the replacement switches can, of course, be combined with others from the toolkit of \texttt{latexindent.pl}. For example,
+ we can combine the poly-switches of \vref{sec:poly-switches}, which we do in \cref{lst:equation}; upon running the command
+ \begin{commandshell}
+latexindent.pl -r -m displaymath.tex -l=displaymath1.yaml,equation.yaml
+\end{commandshell}
+ then we receive the output in \cref{lst:displaymath-mod2}.
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=-.1\textwidth},
+ raster column skip=.06\linewidth]
+ \cmhlistingsfromfile*{demonstrations/displaymath-mod2.tex}{\texttt{displaymath.tex} using \cref{lst:displaymath1,lst:equation}}{lst:displaymath-mod2}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/equation.yaml}[MLB-TCB,width=0.55\textwidth]{\texttt{equation.yaml}}{lst:equation}
+ \end{cmhtcbraster}
+ \end{example}
+
+ \begin{example}
+ This example is motivated by \href{https://tex.stackexchange.com/questions/490086/bring-several-lines-together-to-fill-blank-spaces-in-texmaker}{tex stackexchange question 490086}.
+ We begin with the code in \cref{lst:phrase}.
+
+ \cmhlistingsfromfile*{demonstrations/phrase.tex}{\texttt{phrase.tex}}{lst:phrase}
+
+ Our goal is to make the spacing uniform between the phrases. To achieve this, we employ the settings in \cref{lst:hspace},
+ and run the command
+ \begin{commandshell}
+latexindent.pl -r phrase.tex -l=hspace.yaml
+\end{commandshell}
+ which gives the output in \cref{lst:phrase-mod1}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile*{demonstrations/phrase-mod1.tex}{\texttt{phrase.tex} using \cref{lst:hspace}}{lst:phrase-mod1}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/hspace.yaml}[replace-TCB]{\texttt{hspace.yaml}}{lst:hspace}
+ \end{cmhtcbraster}
+
+ The \lstinline!\h+! setting in \cref{lst:hspace} say to replace \emph{at least one horizontal space} with a single space.
+ \end{example}
+
+ \begin{example}
+ We begin with the code in \cref{lst:references}.
+
+ \cmhlistingsfromfile*{demonstrations/references.tex}{\texttt{references.tex}}{lst:references}
+
+ Our goal is to change each reference so that both the text and the reference are contained within one hyperlink. We
+ achieve this by employing \cref{lst:reference} and running the command
+ \begin{commandshell}
+latexindent.pl -r references.tex -l=reference.yaml
+\end{commandshell}
+ which gives the output in \cref{lst:references-mod1}.
+
+ \cmhlistingsfromfile*{demonstrations/references-mod1.tex}{\texttt{references.tex} using \cref{lst:reference}}{lst:references-mod1}
+
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/reference.yaml}[replace-TCB]{\texttt{reference.yaml}}{lst:reference}
+
+ Referencing \cref{lst:reference}, the \lstinline!|! means \emph{or}, we have used \emph{capture groups}, together with an example
+ of an \emph{optional} pattern, \lstinline!(?:eq)?!.
+ \end{example}
+
+ \begin{example}
+ Let's explore the three replacement mode switches (see \vref{tab:replacementswitches}) in the context of
+ an example that contains a verbatim code block, \cref{lst:verb1}; we will use the settings in \cref{lst:verbatim1-yaml}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile*{demonstrations/verb1.tex}{\texttt{verb1.tex}}{lst:verb1}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/verbatim1.yaml}[replace-TCB]{\texttt{verbatim1.yaml}}{lst:verbatim1-yaml}
+ \end{cmhtcbraster}
+
+ Upon running the following commands,
+ \begin{commandshell}
+latexindent.pl -r verb1.tex -l=verbatim1.yaml -o=+mod1
+latexindent.pl -rv verb1.tex -l=verbatim1.yaml -o=+-rv-mod1
+latexindent.pl -rr verb1.tex -l=verbatim1.yaml -o=+-rr-mod1
+\end{commandshell}
+ we receive the respective output in \crefrange{lst:verb1-mod1}{lst:verb1-rr-mod1}
+
+ \begin{cmhtcbraster}[raster columns=3,
+ raster left skip=-3.75cm,
+ raster right skip=-2cm,]
+ \cmhlistingsfromfile*{demonstrations/verb1-mod1.tex}{\texttt{verb1-mod1.tex}}{lst:verb1-mod1}
+ \cmhlistingsfromfile*{demonstrations/verb1-rv-mod1.tex}{\texttt{verb1-rv-mod1.tex}}{lst:verb1-rv-mod1}
+ \cmhlistingsfromfile*{demonstrations/verb1-rr-mod1.tex}{\texttt{verb1-rr-mod1.tex}}{lst:verb1-rr-mod1}
+ \end{cmhtcbraster}
+ \end{example}
+
+ We note that:
+ \begin{enumerate}
+ \item in \cref{lst:verb1-mod1} indentation has been performed, and that the replacements
+ specified in \cref{lst:verbatim1-yaml} have been performed, even within the verbatim code
+ block;
+ \item in \cref{lst:verb1-rv-mod1} indentation has been performed, but that the replacements have
+ \emph{not} been performed within the verbatim environment, because the
+ \texttt{rv} switch is active;
+ \item in \cref{lst:verb1-rr-mod1} indentation has \emph{not} been performed, but
+ that replacements have been performed, not respecting the verbatim code block.
+ \end{enumerate}
+ See the summary within \vref{tab:replacementswitches}.
+
+ \begin{example}
+ Let's explore the \texttt{amalgamate} field from \vref{lst:replacements} in the context of the file specified
+ in \cref{lst:amalg1}.
+
+ \cmhlistingsfromfile*{demonstrations/amalg1.tex}{\texttt{amalg1.tex}}{lst:amalg1}
+
+ Let's consider the YAML files given in \crefrange{lst:amalg1-yaml}{lst:amalg3-yaml}.
+
+ \begin{cmhtcbraster}[raster columns=3,
+ raster left skip=-3.75cm,
+ raster right skip=-2cm,]
+ \cmhlistingsfromfile*[style=yaml-LST]{demonstrations/amalg1-yaml.yaml}[replace-TCB]{\texttt{amalg1-yaml.yaml}}{lst:amalg1-yaml}
+ \cmhlistingsfromfile*[style=yaml-LST]{demonstrations/amalg2-yaml.yaml}[replace-TCB]{\texttt{amalg2-yaml.yaml}}{lst:amalg2-yaml}
+ \cmhlistingsfromfile*[style=yaml-LST]{demonstrations/amalg3-yaml.yaml}[replace-TCB]{\texttt{amalg3-yaml.yaml}}{lst:amalg3-yaml}
+ \end{cmhtcbraster}
+
+ Upon running the following commands,
+ \begin{commandshell}
+latexindent.pl -r amalg1.tex -l=amalg1-yaml
+latexindent.pl -r amalg1.tex -l=amalg1-yaml,amalg2-yaml
+latexindent.pl -r amalg1.tex -l=amalg1-yaml,amalg2-yaml,amalg3-yaml
+\end{commandshell}
+ we receive the respective output in \crefrange{lst:amalg1-mod1}{lst:amalg1-mod123}.
+
+ \begin{cmhtcbraster}[raster columns=3,
+ raster left skip=-3.75cm,
+ raster right skip=-2cm,]
+ \cmhlistingsfromfile*{demonstrations/amalg1-mod1.tex}{\texttt{amalg1.tex} using \cref{lst:amalg1-yaml}}{lst:amalg1-mod1}
+ \cmhlistingsfromfile*{demonstrations/amalg1-mod12.tex}{\texttt{amalg1.tex} using \cref{lst:amalg1-yaml,lst:amalg2-yaml}}{lst:amalg1-mod12}
+ \cmhlistingsfromfile*{demonstrations/amalg1-mod123.tex}{\texttt{amalg1.tex} using \cref{lst:amalg1-yaml,lst:amalg2-yaml,lst:amalg3-yaml}}{lst:amalg1-mod123}
+ \end{cmhtcbraster}
+ We note that:
+ \begin{enumerate}
+ \item in \cref{lst:amalg1-mod1} the replacements from \cref{lst:amalg1-yaml} have been used;
+ \item in \cref{lst:amalg1-mod12} the replacements from \cref{lst:amalg1-yaml,lst:amalg2-yaml} have
+ \emph{both} been used, because the default value of \texttt{amalgamate}
+ is 1;
+ \item in \cref{lst:amalg1-mod123} \emph{only} the replacements from
+ \cref{lst:amalg3-yaml} have been used, because the value of \texttt{amalgamate} has
+ been set to 0.
+ \end{enumerate}
+ \end{example}
diff --git a/support/latexindent/documentation/sec-the-m-switch.tex b/support/latexindent/documentation/sec-the-m-switch.tex
new file mode 100644
index 0000000000..ec3a86871d
--- /dev/null
+++ b/support/latexindent/documentation/sec-the-m-switch.tex
@@ -0,0 +1,1746 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\renewcommand{\imagetouse}{logo}
+\section{The -m (modifylinebreaks) switch}\label{sec:modifylinebreaks}
+ \fancyhead[R]{\bfseries\thepage%
+ \tikz[remember picture,overlay] {
+ \node at (1,0){\includegraphics{logo}};
+ }}
+ All features described in this section will only be relevant if the
+ \texttt{-m} switch is used.
+
+ \startcontents[the-m-switch]
+ \printcontents[the-m-switch]{}{0}{}
+
+\yamltitle{modifylinebreaks}*{fields}
+ \begin{wrapfigure}[7]{r}[0pt]{8cm}
+ \cmhlistingsfromfile[style=modifylinebreaks]*{../defaultSettings.yaml}[MLB-TCB,width=.85\linewidth,before=\centering]{\texttt{modifyLineBreaks}}{lst:modifylinebreaks}
+ \end{wrapfigure}
+ \makebox[0pt][r]{%
+ \raisebox{-\totalheight}[0pt][0pt]{%
+ \tikz\node[opacity=1] at (0,0) {\includegraphics[width=4cm]{logo}};}}%
+ As of Version 3.0, \texttt{latexindent.pl} has the \texttt{-m}
+ switch, which permits \texttt{latexindent.pl} to modify line breaks, according to the
+ specifications in the \texttt{modifyLineBreaks} field. \emph{The settings
+ in this field will only be considered if the \texttt{-m} switch has been used}. A
+ snippet of the default settings of this field is shown in \cref{lst:modifylinebreaks}.
+
+ Having read the previous paragraph, it should sound reasonable that, if you call
+ \texttt{latexindent.pl} using the \texttt{-m} switch, then you give
+ it permission to modify line breaks in your file, but let's be clear:
+
+ \begin{warning}
+ If you call \texttt{latexindent.pl} with the \texttt{-m} switch, then you
+ are giving it permission to modify line breaks. By default, the only
+ thing that will happen is that multiple blank lines will be condensed into
+ one blank line; many other settings are possible, discussed next.
+ \end{warning}
+
+\yamltitle{preserveBlankLines}{0|1}
+ This field is directly related to \emph{poly-switches}, discussed below. By
+ default, it is set to \texttt{1}, which means that blank lines will be
+ protected from removal; however, regardless of this setting, multiple blank lines can be
+ condensed if \texttt{condenseMultipleBlankLinesInto} is greater than \texttt{0},
+ discussed next.
+
+\yamltitle{condenseMultipleBlankLinesInto}*{positive integer}
+ Assuming that this switch takes an integer value greater than
+ \texttt{0}, \texttt{latexindent.pl} will condense multiple blank
+ lines into the number of blank lines illustrated by this switch. As an example,
+ \cref{lst:mlb-bl} shows a sample file with blank lines; upon running
+ \begin{commandshell}
+latexindent.pl myfile.tex -m
+\end{commandshell}
+ the output is shown in \cref{lst:mlb-bl-out}; note that the multiple blank lines
+ have been condensed into one blank line, and note also that we have used the
+ \texttt{-m} switch!
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/mlb1.tex}{\texttt{mlb1.tex}}{lst:mlb-bl}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/mlb1-out.tex}{\texttt{mlb1.tex} out output}{lst:mlb-bl-out}
+ \end{minipage}
+
+\subsection{textWrapOptions: modifying line breaks by text wrapping}\label{subsec:textwrapping}
+ When the \texttt{-m} switch is active \texttt{latexindent.pl} has the
+ ability to wrap text using the options%
+ \announce{2017-05-27}{textWrapOptions} specified in the \texttt{textWrapOptions} field, see
+ \cref{lst:textWrapOptions}. The value of \texttt{columns} specifies the
+ column at which the text should be wrapped. By default, the value of
+ \texttt{columns} is \texttt{0}, so
+ \texttt{latexindent.pl} will \emph{not} wrap text; if you change it
+ to a value of \texttt{2} or more, then text will be wrapped after the
+ character in the specified column.
+
+ \cmhlistingsfromfile[style=textWrapOptions]*{../defaultSettings.yaml}[MLB-TCB,width=.85\linewidth,before=\centering]{\texttt{textWrapOptions}}{lst:textWrapOptions}
+
+ For example, consider the file give in \cref{lst:textwrap1}.
+
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap1.tex}{\texttt{textwrap1.tex}}{lst:textwrap1}
+ \end{widepage}
+
+ Using the file \texttt{textwrap1.yaml} in \cref{lst:textwrap1-yaml}, and running
+ the command
+ \begin{commandshell}
+latexindent.pl -m textwrap1.tex -o textwrap1-mod1.tex -l textwrap1.yaml
+\end{commandshell}
+ we obtain the output in \cref{lst:textwrap1-mod1}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/textwrap1-mod1.tex}{\texttt{textwrap1-mod1.tex}}{lst:textwrap1-mod1}
+ \cmhlistingsfromfile{demonstrations/textwrap1.yaml}[MLB-TCB]{\texttt{textwrap1.yaml}}{lst:textwrap1-yaml}
+ \end{cmhtcbraster}
+
+ The text wrapping routine is performed \emph{after} verbatim environments
+ have been stored, so verbatim environments and verbatim commands are exempt from the
+ routine. For example, using the file in \cref{lst:textwrap2},
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap2.tex}{\texttt{textwrap2.tex}}{lst:textwrap2}
+ \end{widepage}
+ and running the following command and continuing to use \texttt{textwrap1.yaml} from
+ \cref{lst:textwrap1-yaml},
+ \begin{commandshell}
+latexindent.pl -m textwrap2.tex -o textwrap2-mod1.tex -l textwrap1.yaml
+\end{commandshell}
+ then the output is as in \cref{lst:textwrap2-mod1}.
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap2-mod1.tex}{\texttt{textwrap2-mod1.tex}}{lst:textwrap2-mod1}
+ \end{widepage}
+ Furthermore, the text wrapping routine is performed after the trailing comments have been
+ stored, and they are also exempt from text wrapping. For example, using the file in
+ \cref{lst:textwrap3}
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap3.tex}{\texttt{textwrap3.tex}}{lst:textwrap3}
+ \end{widepage}
+ and running the following command and continuing to use \texttt{textwrap1.yaml} from
+ \cref{lst:textwrap1-yaml},
+ \begin{commandshell}
+latexindent.pl -m textwrap3.tex -o textwrap3-mod1.tex -l textwrap1.yaml
+\end{commandshell}
+ then the output is as in \cref{lst:textwrap3-mod1}.
+
+ \cmhlistingsfromfile{demonstrations/textwrap3-mod1.tex}{\texttt{textwrap3-mod1.tex}}{lst:textwrap3-mod1}
+
+ The text wrapping routine of \texttt{latexindent.pl} is performed by the
+ \texttt{Text::Wrap} module, which provides a \texttt{separator} feature
+ to separate lines with characters other than a new line (see
+ \cite{textwrap}). By default, the separator is empty which means that a new
+ line token will be used, but you can change it as you see fit.
+
+ For example starting with the file in \cref{lst:textwrap4}
+
+ \cmhlistingsfromfile{demonstrations/textwrap4.tex}{\texttt{textwrap4.tex}}{lst:textwrap4}
+ and using \texttt{textwrap2.yaml} from \cref{lst:textwrap2-yaml} with the following
+ command
+ \begin{commandshell}
+latexindent.pl -m textwrap4.tex -o textwrap4-mod2.tex -l textwrap2.yaml
+\end{commandshell}
+ then we obtain the output in \cref{lst:textwrap4-mod2}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/textwrap4-mod2.tex}{\texttt{textwrap4-mod2.tex}}{lst:textwrap4-mod2}
+ \cmhlistingsfromfile{demonstrations/textwrap2.yaml}[MLB-TCB]{\texttt{textwrap2.yaml}}{lst:textwrap2-yaml}
+ \end{cmhtcbraster}
+
+\subsubsection{text wrapping on a per-code-block basis}
+ By default, if the value of \texttt{columns} is greater than 0 and the
+ \texttt{-m} switch is active, then%
+ \announce{2018-08-13}*{updates to textWrapOptions} the text wrapping routine will operate before the code blocks
+ have been searched for. This behaviour is customisable; in particular, you can instead
+ instruct \texttt{latexindent.pl} to apply \texttt{textWrap} on a
+ per-code-block basis. Thanks to \cite{zoehneto} for their help in testing and
+ shaping this feature.
+
+ The full details of \texttt{textWrapOptions} are shown in \cref{lst:textWrapOptionsAll}.
+ In particular, note the field \texttt{perCodeBlockBasis: 0}.
+
+ \cmhlistingsfromfile[style=textWrapOptionsAll]*{../defaultSettings.yaml}[MLB-TCB,width=.85\linewidth,before=\centering]{\texttt{textWrapOptions}}{lst:textWrapOptionsAll}
+
+ The code blocks detailed in \cref{lst:textWrapOptionsAll} are with direct reference to
+ those detailed in \vref{tab:code-blocks}. The only special case is the
+ \texttt{masterDocument} field; this is designed for `chapter'-type files that may
+ contain paragraphs that are not within any other code-blocks. The same notation is used
+ between this feature and the \texttt{removeParagraphLineBreaks} described in
+ \vref{lst:removeParagraphLineBreaks}; in fact, the two features can even be combined (this is
+ detailed in \vref{subsec:removeparagraphlinebreaks:and:textwrap}).
+
+ Let's explore these switches with reference to the code given in
+ \cref{lst:textwrap5}; the text outside of the environment is considered part of
+ the \texttt{masterDocument}.
+
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap5.tex}{\texttt{textwrap5.tex}}{lst:textwrap5}
+ \end{widepage}
+
+ With reference to this code block, the settings given in \cref{lst:textwrap3-yaml,lst:textwrap4-yaml,lst:textwrap5-yaml} each
+ give the same output.
+
+ \begin{cmhtcbraster}[raster columns=3,
+ raster left skip=-3.5cm,
+ raster right skip=-2cm,
+ raster column skip=.03\linewidth]
+ \cmhlistingsfromfile{demonstrations/textwrap3.yaml}[MLB-TCB]{\texttt{textwrap3.yaml}}{lst:textwrap3-yaml}
+ \cmhlistingsfromfile{demonstrations/textwrap4.yaml}[MLB-TCB]{\texttt{textwrap4.yaml}}{lst:textwrap4-yaml}
+ \cmhlistingsfromfile{demonstrations/textwrap5.yaml}[MLB-TCB]{\texttt{textwrap5.yaml}}{lst:textwrap5-yaml}
+ \end{cmhtcbraster}
+
+ Let's explore the similarities and differences in the equivalent (with respect to
+ \cref{lst:textwrap5}) syntax specified in \cref{lst:textwrap3-yaml,lst:textwrap4-yaml,lst:textwrap5-yaml}:
+ \begin{itemize}
+ \item in each of \cref{lst:textwrap3-yaml,lst:textwrap4-yaml,lst:textwrap5-yaml} notice that \texttt{columns: 30};
+ \item in each of \cref{lst:textwrap3-yaml,lst:textwrap4-yaml,lst:textwrap5-yaml} notice that \texttt{perCodeBlockBasis: 1};
+ \item in \cref{lst:textwrap3-yaml} we have specified \texttt{all: 1} so that the
+ text wrapping will operate upon \emph{all} code blocks;
+ \item in \cref{lst:textwrap4-yaml} we have \emph{not} specified
+ \texttt{all}, and instead, have specified that text wrapping should be
+ applied to each of \texttt{environments} and \texttt{masterDocument};
+ \item in \cref{lst:textwrap5-yaml} we have specified text wrapping for
+ \texttt{masterDocument} and on a \emph{per-name} basis for
+ \texttt{environments} code blocks.
+ \end{itemize}
+
+ Upon running the following commands
+ \begin{commandshell}
+latexindent.pl -s textwrap5.tex -l=textwrap3.yaml -m
+latexindent.pl -s textwrap5.tex -l=textwrap4.yaml -m
+latexindent.pl -s textwrap5.tex -l=textwrap5.yaml -m
+\end{commandshell}
+ we obtain the output shown in \cref{lst:textwrap5-mod3}.
+
+ \cmhlistingsfromfile{demonstrations/textwrap5-mod3.tex}{\texttt{textwrap5-mod3.tex}}{lst:textwrap5-mod3}
+
+ We can explore the idea of per-name text wrapping given in \cref{lst:textwrap5-yaml} by
+ using \cref{lst:textwrap6}.
+
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap6.tex}{\texttt{textwrap6.tex}}{lst:textwrap6}
+ \end{widepage}
+
+ In particular, upon running
+ \begin{commandshell}
+latexindent.pl -s textwrap6.tex -l=textwrap5.yaml -m
+\end{commandshell}
+ we obtain the output given in \cref{lst:textwrap6-mod5}.
+
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap6-mod5.tex}{\texttt{textwrap6.tex} using \cref{lst:textwrap5-yaml}}{lst:textwrap6-mod5}
+ \end{widepage}
+
+ Notice that, because \texttt{environments} has been specified only for
+ \texttt{myenv} (in \cref{lst:textwrap5-yaml}) that the environment named \texttt{another} has
+ \emph{not} had text wrapping applied to it.
+
+ The {all} field can be specified with exceptions which can either
+ be done on a per-code-block or per-name basis; we explore this in relation to
+ \cref{lst:textwrap6} in the settings given in \crefrange{lst:textwrap6-yaml}{lst:textwrap8-yaml}.
+
+ \begin{adjustwidth}{-3.5cm}{-2.5cm}
+ \begin{minipage}{.33\linewidth}
+ \cmhlistingsfromfile{demonstrations/textwrap6.yaml}[MLB-TCB]{\texttt{textwrap6.yaml}}{lst:textwrap6-yaml}
+ \end{minipage}%
+ \begin{minipage}{.33\linewidth}
+ \cmhlistingsfromfile{demonstrations/textwrap7.yaml}[MLB-TCB]{\texttt{textwrap7.yaml}}{lst:textwrap7-yaml}
+ \end{minipage}%
+ \begin{minipage}{.33\linewidth}
+ \cmhlistingsfromfile{demonstrations/textwrap8.yaml}[MLB-TCB]{\texttt{textwrap8.yaml}}{lst:textwrap8-yaml}
+ \end{minipage}
+ \end{adjustwidth}
+
+ Upon running the commands
+ \begin{commandshell}
+latexindent.pl -s textwrap6.tex -l=textwrap6.yaml -m
+latexindent.pl -s textwrap6.tex -l=textwrap7.yaml -m
+latexindent.pl -s textwrap6.tex -l=textwrap8.yaml -m
+\end{commandshell}
+ we receive the respective output given in \crefrange{lst:textwrap6-mod6}{lst:textwrap6-mod8}.
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap6-mod6.tex}{\texttt{textwrap6.tex} using \cref{lst:textwrap6-yaml}}{lst:textwrap6-mod6}
+
+ \cmhlistingsfromfile{demonstrations/textwrap6-mod7.tex}{\texttt{textwrap6.tex} using \cref{lst:textwrap7-yaml}}{lst:textwrap6-mod7}
+
+ \cmhlistingsfromfile{demonstrations/textwrap6-mod8.tex}{\texttt{textwrap6.tex} using \cref{lst:textwrap8-yaml}}{lst:textwrap6-mod8}
+ \end{widepage}
+
+ Notice that:
+ \begin{itemize}
+ \item in \cref{lst:textwrap6-mod6} the text wrapping routine has not been applied to any
+ \texttt{environments} because it has been switched off (per-code-block) in
+ \cref{lst:textwrap6-yaml};
+ \item in \cref{lst:textwrap6-mod7} the text wrapping routine has not been applied to
+ \texttt{myenv} because it has been switched off (per-name) in
+ \cref{lst:textwrap7-yaml};
+ \item in \cref{lst:textwrap6-mod8} the text wrapping routine has not been applied to
+ \texttt{masterDocument} because of the settings in \cref{lst:textwrap8-yaml}.
+ \end{itemize}
+
+ The \texttt{columns} field has a variety of different ways that it can be
+ specified; we've seen two basic ways already: the default (set to
+ \texttt{0}) and a positive integer (see \vref{lst:textwrap6}, for
+ example). We explore further options in \crefrange{lst:textwrap9-yaml}{lst:textwrap11-yaml}.
+
+ \begin{cmhtcbraster}[raster columns=3,
+ raster left skip=-3.5cm,
+ raster right skip=-2cm,
+ raster column skip=.03\linewidth]
+ \cmhlistingsfromfile{demonstrations/textwrap9.yaml}[MLB-TCB]{\texttt{textwrap9.yaml}}{lst:textwrap9-yaml}
+ \cmhlistingsfromfile{demonstrations/textwrap10.yaml}[MLB-TCB]{\texttt{textwrap10.yaml}}{lst:textwrap10-yaml}
+ \cmhlistingsfromfile{demonstrations/textwrap11.yaml}[MLB-TCB]{\texttt{textwrap11.yaml}}{lst:textwrap11-yaml}
+ \end{cmhtcbraster}
+
+ \Cref{lst:textwrap9-yaml} and \cref{lst:textwrap10-yaml} are equivalent. Upon running
+ the commands
+ \begin{commandshell}
+latexindent.pl -s textwrap6.tex -l=textwrap9.yaml -m
+latexindent.pl -s textwrap6.tex -l=textwrap11.yaml -m
+\end{commandshell}
+ we receive the respective output given in \cref{lst:textwrap6-mod9,lst:textwrap6-mod11}.
+
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/textwrap6-mod9.tex}{\texttt{textwrap6.tex} using \cref{lst:textwrap9-yaml}}{lst:textwrap6-mod9}
+
+ \cmhlistingsfromfile{demonstrations/textwrap6-mod11.tex}{\texttt{textwrap6.tex} using \cref{lst:textwrap11-yaml}}{lst:textwrap6-mod11}
+ \end{widepage}
+
+ Notice that:
+ \begin{itemize}
+ \item in \cref{lst:textwrap6-mod9} the text for the \texttt{masterDocument} has been
+ wrapped using \texttt{30} columns, while \texttt{environments} has
+ been wrapped using \texttt{50} columns;
+ \item in \cref{lst:textwrap6-mod11} the text for \texttt{myenv} has been wrapped
+ using \texttt{50} columns, the text for \texttt{another} has
+ been wrapped using \texttt{15} columns, and \texttt{masterDocument}
+ has been wrapped using \texttt{30} columns.
+ \end{itemize}
+ If you don't specify a \texttt{default} value on per-code-block basis, then
+ the \texttt{default} value from \texttt{columns} will be inherited;
+ if you don't specify a default value for \texttt{columns} then
+ \texttt{80} will be used.
+
+ \texttt{alignAtAmpersandTakesPriority} is set to \texttt{1} by default; assuming
+ that text wrapping is occurring on a per-code-block basis, and the current
+ environment/code block is specified within \vref{lst:aligndelims:basic} then text wrapping
+ will be disabled for this code block.
+
+ If you wish to specify \texttt{afterHeading} commands (see
+ \vref{lst:indentAfterHeadings}) on a per-name basis, then you need to append the name with
+ \texttt{:heading}, for example, you might use \texttt{section:heading}.
+
+\subsubsection{Summary of text wrapping}
+ It is important to note the following:
+ \begin{itemize}
+ \item Verbatim environments (\vref{lst:verbatimEnvironments}) and verbatim commands
+ (\vref{lst:verbatimCommands}) will \emph{not} be affected by the text
+ wrapping routine (see \vref{lst:textwrap2-mod1});
+ \item comments will \emph{not} be affected by the text wrapping routine (see
+ \vref{lst:textwrap3-mod1});
+ \item it is possible to wrap text on a per-code-block and a per-name basis;
+ \announce{2018-08-13}*{updates to textWrapOptions}
+ \item the text wrapping routine sets \texttt{preserveBlankLines} as
+ \texttt{1};
+ \item indentation is performed \emph{after} the text wrapping routine; as such,
+ indented code will likely exceed any maximum value set in the \texttt{columns}
+ field.
+ \end{itemize}
+
+\subsection{oneSentencePerLine: modifying line breaks for sentences}\label{sec:onesentenceperline}
+ You can instruct \texttt{latexindent.pl} to
+ format%
+ \announce{2018-01-13}{one sentence per line} your file so that
+ it puts one sentence per line. Thank you to \cite{mlep} for helping to
+ shape and test this feature. The behaviour of this part of the script is controlled by
+ the switches detailed in \cref{lst:oneSentencePerLine}, all of which we discuss next.
+
+ \cmhlistingsfromfile[style=oneSentencePerLine]*{../defaultSettings.yaml}[MLB-TCB,width=.85\linewidth,before=\centering]{\texttt{oneSentencePerLine}}{lst:oneSentencePerLine}
+
+\yamltitle{manipulateSentences}{0|1}
+ This is a binary switch that details if \texttt{latexindent.pl} should perform the
+ sentence manipulation routine; it is \emph{off} (set to \texttt{0}) by default, and you will
+ need to turn it on (by setting it to \texttt{1}) if you want the script
+ to modify line breaks surrounding and within sentences.
+
+\yamltitle{removeSentenceLineBreaks}{0|1}
+ When operating upon sentences \texttt{latexindent.pl} will, by default, remove
+ internal line breaks as \texttt{removeSentenceLineBreaks} is set to
+ \texttt{1}. Setting this switch to \texttt{0} instructs
+ \texttt{latexindent.pl} not to do so.
+
+ For example, consider \texttt{multiple-sentences.tex} shown in \cref{lst:multiple-sentences}.
+
+ \cmhlistingsfromfile{demonstrations/multiple-sentences.tex}{\texttt{multiple-sentences.tex}}{lst:multiple-sentences}
+
+ If we use the YAML files in \cref{lst:manipulate-sentences-yaml,lst:keep-sen-line-breaks-yaml}, and run the commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl multiple-sentences -m -l=manipulate-sentences.yaml
+latexindent.pl multiple-sentences -m -l=keep-sen-line-breaks.yaml
+\end{commandshell}
+ \end{widepage}
+ then we obtain the respective output given in \cref{lst:multiple-sentences-mod1,lst:multiple-sentences-mod2}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences-mod1.tex}{\texttt{multiple-sentences.tex} using \cref{lst:manipulate-sentences-yaml}}{lst:multiple-sentences-mod1}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/manipulate-sentences.yaml}[MLB-TCB]{\texttt{manipulate-sentences.yaml}}{lst:manipulate-sentences-yaml}
+ \end{cmhtcbraster}
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences-mod2.tex}{\texttt{multiple-sentences.tex} using \cref{lst:keep-sen-line-breaks-yaml}}{lst:multiple-sentences-mod2}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/keep-sen-line-breaks.yaml}[MLB-TCB]{\texttt{keep-sen-line-breaks.yaml}}{lst:keep-sen-line-breaks-yaml}
+ \end{cmhtcbraster}
+
+ Notice, in particular, that the `internal' sentence line breaks in
+ \cref{lst:multiple-sentences} have been removed in \cref{lst:multiple-sentences-mod1}, but have
+ not been removed in \cref{lst:multiple-sentences-mod2}.
+
+ The remainder of the settings displayed in \vref{lst:oneSentencePerLine} instruct
+ \texttt{latexindent.pl} on how to define a sentence. From the perspective of
+ \texttt{latexindent.pl} a sentence must:
+ \begin{itemize}
+ \item \emph{follow} a certain character or set of characters (see
+ \cref{lst:sentencesFollow}); by default, this is either \lstinline!\par!, a
+ blank line, a full stop/period (.), exclamation mark (!), question mark (?) right brace
+ (\}) or a comment on the previous line;
+ \item \emph{begin} with a character type (see \cref{lst:sentencesBeginWith}); by
+ default, this is only capital letters;
+ \item \emph{end} with a character (see \cref{lst:sentencesEndWith}); by
+ default, these are full stop/period (.), exclamation mark (!) and question mark (?).
+ \end{itemize}
+ In each case, you can specify the \texttt{other} field to include any
+ pattern that you would like; you can specify anything in this field using the language of
+ regular expressions.
+
+ \begin{cmhtcbraster}[raster columns=3,
+ raster left skip=-3.5cm,
+ raster right skip=-2cm,
+ raster column skip=.06\linewidth]
+ \cmhlistingsfromfile[style=sentencesFollow]*{../defaultSettings.yaml}[MLB-TCB,width=.9\linewidth,before=\centering]{\texttt{sentencesFollow}}{lst:sentencesFollow}
+ \cmhlistingsfromfile[style=sentencesBeginWith]*{../defaultSettings.yaml}[MLB-TCB,width=.9\linewidth,before=\centering]{\texttt{sentencesBeginWith}}{lst:sentencesBeginWith}
+ \cmhlistingsfromfile[style=sentencesEndWith]*{../defaultSettings.yaml}[MLB-TCB,width=.9\linewidth,before=\centering]{\texttt{sentencesEndWith}}{lst:sentencesEndWith}
+ \end{cmhtcbraster}
+
+\subsubsection{sentencesFollow}
+ Let's explore a few of the switches in \texttt{sentencesFollow}; let's start with
+ \vref{lst:multiple-sentences}, and use the YAML settings given in
+ \cref{lst:sentences-follow1-yaml}. Using the command
+ \begin{commandshell}
+latexindent.pl multiple-sentences -m -l=sentences-follow1.yaml
+\end{commandshell}
+ we obtain the output given in \cref{lst:multiple-sentences-mod3}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences-mod3.tex}{\texttt{multiple-sentences.tex} using \cref{lst:sentences-follow1-yaml}}{lst:multiple-sentences-mod3}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/sentences-follow1.yaml}[MLB-TCB]{\texttt{sentences-follow1.yaml}}{lst:sentences-follow1-yaml}
+ \end{cmhtcbraster}
+
+ Notice that, because \texttt{blankLine} is set to \texttt{0},
+ \texttt{latexindent.pl} will not seek sentences following a blank line, and so the
+ fourth sentence has not been accounted for.
+
+ We can explore the \texttt{other} field in \cref{lst:sentencesFollow} with
+ the \texttt{.tex} file detailed in \cref{lst:multiple-sentences1}.
+
+ \cmhlistingsfromfile{demonstrations/multiple-sentences1.tex}{\texttt{multiple-sentences1.tex}}{lst:multiple-sentences1}
+
+ Upon running the following commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl multiple-sentences1 -m -l=manipulate-sentences.yaml
+latexindent.pl multiple-sentences1 -m -l=manipulate-sentences.yaml,sentences-follow2.yaml
+\end{commandshell}
+ \end{widepage}
+ then we obtain the respective output given in \cref{lst:multiple-sentences1-mod1,lst:multiple-sentences1-mod2}.
+ \cmhlistingsfromfile{demonstrations/multiple-sentences1-mod1.tex}{\texttt{multiple-sentences1.tex} using \vref{lst:manipulate-sentences-yaml}}{lst:multiple-sentences1-mod1}
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=1cm},
+ ]
+ \cmhlistingsfromfile{demonstrations/multiple-sentences1-mod2.tex}{\texttt{multiple-sentences1.tex} using \cref{lst:sentences-follow2-yaml}}{lst:multiple-sentences1-mod2}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/sentences-follow2.yaml}[MLB-TCB,width=.45\textwidth]{\texttt{sentences-follow2.yaml}}{lst:sentences-follow2-yaml}
+ \end{cmhtcbraster}
+
+ Notice that in \cref{lst:multiple-sentences1-mod1} the first sentence after the
+ \texttt{)} has not been accounted for, but that following the inclusion
+ of \cref{lst:sentences-follow2-yaml}, the output given in \cref{lst:multiple-sentences1-mod2}
+ demonstrates that the sentence \emph{has} been accounted for correctly.
+
+\subsubsection{sentencesBeginWith}
+ By default, \texttt{latexindent.pl} will only assume that sentences begin with the
+ upper case letters \texttt{A-Z}; you can instruct the script to define
+ sentences to begin with lower case letters (see \cref{lst:sentencesBeginWith}), and we can
+ use the \texttt{other} field to define sentences to begin with other
+ characters.
+
+ \cmhlistingsfromfile{demonstrations/multiple-sentences2.tex}{\texttt{multiple-sentences2.tex}}{lst:multiple-sentences2}
+
+ Upon running the following commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl multiple-sentences2 -m -l=manipulate-sentences.yaml
+latexindent.pl multiple-sentences2 -m -l=manipulate-sentences.yaml,sentences-begin1.yaml
+\end{commandshell}
+ \end{widepage}
+ then we obtain the respective output given in \cref{lst:multiple-sentences2-mod1,lst:multiple-sentences2-mod2}.
+ \cmhlistingsfromfile{demonstrations/multiple-sentences2-mod1.tex}{\texttt{multiple-sentences2.tex} using \vref{lst:manipulate-sentences-yaml}}{lst:multiple-sentences2-mod1}
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=1cm},
+ ]
+ \cmhlistingsfromfile{demonstrations/multiple-sentences2-mod2.tex}{\texttt{multiple-sentences2.tex} using \cref{lst:sentences-begin1-yaml}}{lst:multiple-sentences2-mod2}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/sentences-begin1.yaml}[MLB-TCB,width=.45\textwidth]{\texttt{sentences-begin1.yaml}}{lst:sentences-begin1-yaml}
+ \end{cmhtcbraster}
+ Notice that in \cref{lst:multiple-sentences2-mod1}, the first sentence has been accounted for but
+ that the subsequent sentences have not. In \cref{lst:multiple-sentences2-mod2}, all of the
+ sentences have been accounted for, because the \texttt{other} field in
+ \cref{lst:sentences-begin1-yaml} has defined sentences to begin with either
+ \lstinline!$! or any numeric digit, \texttt{0} to
+ \texttt{9}.
+
+\subsubsection{sentencesEndWith}
+ Let's return to \vref{lst:multiple-sentences}; we have already seen the default way in
+ which \texttt{latexindent.pl} will operate on the sentences in this file in
+ \vref{lst:multiple-sentences-mod1}. We can populate the \texttt{other} field with
+ any character that we wish; for example, using the YAML specified in
+ \cref{lst:sentences-end1-yaml} and the command
+ \begin{commandshell}
+latexindent.pl multiple-sentences -m -l=sentences-end1.yaml
+latexindent.pl multiple-sentences -m -l=sentences-end2.yaml
+\end{commandshell}
+ then we obtain the output in \cref{lst:multiple-sentences-mod4}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences-mod4.tex}{\texttt{multiple-sentences.tex} using \cref{lst:sentences-end1-yaml}}{lst:multiple-sentences-mod4}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/sentences-end1.yaml}[MLB-TCB]{\texttt{sentences-end1.yaml}}{lst:sentences-end1-yaml}
+ \end{cmhtcbraster}
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences-mod5.tex}{\texttt{multiple-sentences.tex} using \cref{lst:sentences-end2-yaml}}{lst:multiple-sentences-mod5}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/sentences-end2.yaml}[MLB-TCB]{\texttt{sentences-end2.yaml}}{lst:sentences-end2-yaml}
+ \end{cmhtcbraster}
+
+ There is a subtle difference between the output in \cref{lst:multiple-sentences-mod4,lst:multiple-sentences-mod5}; in
+ particular, in \cref{lst:multiple-sentences-mod4} the word \texttt{sentence} has not
+ been defined as a sentence, because we have not instructed \texttt{latexindent.pl} to
+ begin sentences with lower case letters. We have changed this by using the settings in
+ \cref{lst:sentences-end2-yaml}, and the associated output in \cref{lst:multiple-sentences-mod5}
+ reflects this.
+
+ Referencing \vref{lst:sentencesEndWith}, you'll notice that there is a field called
+ \texttt{basicFullStop}, which is set to \texttt{0}, and that the
+ \texttt{betterFullStop} is set to \texttt{1} by default.
+
+ Let's consider the file shown in \cref{lst:url}.
+
+ \cmhlistingsfromfile{demonstrations/url.tex}{\texttt{url.tex}}{lst:url}
+
+ Upon running the following commands
+ \begin{commandshell}
+latexindent.pl url -m -l=manipulate-sentences.yaml
+\end{commandshell}
+ we obtain the output given in \cref{lst:url-mod1}.
+
+ \cmhlistingsfromfile{demonstrations/url-mod1.tex}{\texttt{url.tex} using \vref{lst:manipulate-sentences-yaml}}{lst:url-mod1}
+
+ Notice that the full stop within the url has been interpreted correctly. This is because,
+ within the \texttt{betterFullStop}, full stops at the end of sentences have the
+ following properties:
+ \begin{itemize}
+ \item they are ignored within \texttt{e.g.} and \texttt{i.e.};
+ \item they can not be immediately followed by a lower case or upper case letter;
+ \item they can not be immediately followed by a hyphen, comma, or number.
+ \end{itemize}
+ If you find that the \texttt{betterFullStop} does not work for your purposes, then
+ you can switch it off by setting it to \texttt{0}, and you can
+ experiment with the \texttt{other}
+ field.%
+ \announce*{2019-07-13}{fine tuning the betterFullStop} You can also seek
+ to customise the \texttt{betterFullStop} routine by using the
+ \emph{fine tuning}, detailed in \vref{lst:fineTuning}.
+
+ The \texttt{basicFullStop} routine should probably be avoided in most situations, as
+ it does not accommodate the specifications above. For example, using the following
+ command
+ \begin{commandshell}
+latexindent.pl url -m -l=alt-full-stop1.yaml
+\end{commandshell}
+ and the YAML in \cref{lst:alt-full-stop1-yaml} gives the output in
+ \cref{lst:url-mod2}.
+
+ \begin{cmhtcbraster}[ raster left skip=-3.5cm,
+ raster right skip=-2cm,
+ raster force size=false,
+ raster column 1/.style={add to width=.1\textwidth},
+ raster column skip=.06\linewidth]
+ \cmhlistingsfromfile{demonstrations/url-mod2.tex}{\texttt{url.tex} using \cref{lst:alt-full-stop1-yaml}}{lst:url-mod2}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/alt-full-stop1.yaml}[MLB-TCB,width=.5\textwidth]{\texttt{alt-full-stop1.yaml}}{lst:alt-full-stop1-yaml}
+ \end{cmhtcbraster}
+
+ Notice that the full stop within the URL has not been accommodated correctly because of
+ the non-default settings in \cref{lst:alt-full-stop1-yaml}.
+
+\subsubsection{Features of the oneSentencePerLine routine}
+ The sentence manipulation routine takes place \emph{after} verbatim
+ environments, preamble and trailing comments have been accounted for; this means that any
+ characters within these types of code blocks will not be part of the sentence
+ manipulation routine.
+
+ For example, if we begin with the \texttt{.tex} file in
+ \cref{lst:multiple-sentences3}, and run the command
+ \begin{commandshell}
+latexindent.pl multiple-sentences3 -m -l=manipulate-sentences.yaml
+\end{commandshell}
+ then we obtain the output in \cref{lst:multiple-sentences3-mod1}. \cmhlistingsfromfile{demonstrations/multiple-sentences3.tex}{\texttt{multiple-sentences3.tex}}{lst:multiple-sentences3}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences3-mod1.tex}{\texttt{multiple-sentences3.tex} using \vref{lst:manipulate-sentences-yaml}}{lst:multiple-sentences3-mod1}
+
+ Furthermore, if sentences run across environments then, by default, the line breaks
+ internal to the sentence will be removed. For example, if we use the
+ \texttt{.tex} file in \cref{lst:multiple-sentences4} and run the commands
+ \begin{commandshell}
+latexindent.pl multiple-sentences4 -m -l=manipulate-sentences.yaml
+latexindent.pl multiple-sentences4 -m -l=keep-sen-line-breaks.yaml
+\end{commandshell}
+ then we obtain the output in \cref{lst:multiple-sentences4-mod1,lst:multiple-sentences4-mod2}. \cmhlistingsfromfile{demonstrations/multiple-sentences4.tex}{\texttt{multiple-sentences4.tex}}{lst:multiple-sentences4}
+ \begin{widepage}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences4-mod1.tex}{\texttt{multiple-sentences4.tex} using \vref{lst:manipulate-sentences-yaml}}{lst:multiple-sentences4-mod1}
+ \end{widepage}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences4-mod2.tex}{\texttt{multiple-sentences4.tex} using \vref{lst:keep-sen-line-breaks-yaml}}{lst:multiple-sentences4-mod2}
+ Once you've read \cref{sec:poly-switches}, you will know that you can accommodate the
+ removal of internal sentence line breaks by using the YAML in \cref{lst:item-rules2-yaml}
+ and the command
+ \begin{commandshell}
+latexindent.pl multiple-sentences4 -m -l=item-rules2.yaml
+\end{commandshell}
+ the output of which is shown in \cref{lst:multiple-sentences4-mod3}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/multiple-sentences4-mod3.tex}{\texttt{multiple-sentences4.tex} using \cref{lst:item-rules2-yaml}}{lst:multiple-sentences4-mod3}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/item-rules2.yaml}[MLB-TCB]{\texttt{item-rules2.yaml}}{lst:item-rules2-yaml}
+ \end{cmhtcbraster}
+
+\subsubsection{text wrapping and indenting sentences}
+ The \texttt{oneSentencePerLine}%
+ \announce{2018-08-13}{oneSentencePerline text wrap and indent} can be instructed to perform
+ text wrapping and indentation upon sentences.
+
+ Let's use the code in \cref{lst:multiple-sentences5}.
+
+ \cmhlistingsfromfile{demonstrations/multiple-sentences5.tex}{\texttt{multiple-sentences5.tex}}{lst:multiple-sentences5}
+
+ Referencing \cref{lst:sentence-wrap1-yaml}, and running the following command
+ \begin{commandshell}
+latexindent.pl multiple-sentences5 -m -l=sentence-wrap1.yaml
+\end{commandshell}
+ we receive the output given in \cref{lst:multiple-sentences5-mod1}.
+
+ \begin{cmhtcbraster}[ raster left skip=-3.5cm,
+ raster right skip=-2cm,
+ raster force size=false,
+ raster column 1/.style={add to width=.1\textwidth},
+ raster column skip=.06\linewidth]
+ \cmhlistingsfromfile{demonstrations/multiple-sentences5-mod1.tex}{\texttt{multiple-sentences5.tex} using \cref{lst:sentence-wrap1-yaml}}{lst:multiple-sentences5-mod1}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/sentence-wrap1.yaml}[MLB-TCB,width=0.5\textwidth]{\texttt{sentence-wrap1.yaml}}{lst:sentence-wrap1-yaml}
+ \end{cmhtcbraster}
+
+ If you wish to specify the \texttt{columns} field on a per-code-block basis
+ for sentences, then you would use \texttt{sentence}; explicitly, starting with
+ \vref{lst:textwrap9-yaml}, for example, you would replace/append
+ \texttt{environments} with, for example, \texttt{sentence: 50}.
+
+ The indentation of sentences requires that sentences are stored as code blocks. This
+ means that you may need to tweak \vref{lst:sentencesEndWith}. Let's explore this in
+ relation to \cref{lst:multiple-sentences6}.
+
+ \cmhlistingsfromfile{demonstrations/multiple-sentences6.tex}{\texttt{multiple-sentences6.tex}}{lst:multiple-sentences6}
+
+ By default, \texttt{latexindent.pl} will find the full-stop within the first
+ \texttt{item}, which means that, upon running the following commands
+ \begin{commandshell}
+latexindent.pl multiple-sentences6 -m -l=sentence-wrap1.yaml
+latexindent.pl multiple-sentences6 -m -l=sentence-wrap1.yaml -y="modifyLineBreaks:oneSentencePerLine:sentenceIndent:''"
+\end{commandshell}
+ we receive the respective output in \cref{lst:multiple-sentences6-mod1} and
+ \cref{lst:multiple-sentences6-mod2}.
+
+ \cmhlistingsfromfile{demonstrations/multiple-sentences6-mod1.tex}{\texttt{multiple-sentences6-mod1.tex} using \cref{lst:sentence-wrap1-yaml}}{lst:multiple-sentences6-mod1}
+
+ \cmhlistingsfromfile{demonstrations/multiple-sentences6-mod2.tex}{\texttt{multiple-sentences6-mod2.tex} using \cref{lst:sentence-wrap1-yaml} and no sentence indentation}{lst:multiple-sentences6-mod2}
+
+ We note that \cref{lst:multiple-sentences6-mod1} the \texttt{itemize} code block has
+ \emph{not} been indented appropriately. This is because the
+ oneSentencePerLine has been instructed to store sentences (because
+ \cref{lst:sentence-wrap1-yaml}); each sentence is then searched for code blocks.
+
+ We can tweak the settings in \vref{lst:sentencesEndWith} to ensure that full stops are
+ not followed by \texttt{item} commands, and that the end of sentences
+ contains \lstinline!\end{itemize}! as in \cref{lst:itemize-yaml} (if you intend to use this, ensure that you
+ remove the line breaks from the \texttt{other} field).
+
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/itemized.yaml}[MLB-TCB]{\texttt{itemize.yaml}}{lst:itemize-yaml}
+
+ Upon running
+ \begin{commandshell}
+latexindent.pl multiple-sentences6 -m -l=sentence-wrap1.yaml,itemize.yaml
+\end{commandshell}
+ we receive the output in \cref{lst:multiple-sentences6-mod3}.
+
+ \cmhlistingsfromfile{demonstrations/multiple-sentences6-mod3.tex}{\texttt{multiple-sentences6-mod3.tex} using \cref{lst:sentence-wrap1-yaml} and \cref{lst:itemize-yaml}}{lst:multiple-sentences6-mod3}
+
+ Notice that the sentence has received indentation, and that the
+ \texttt{itemize} code block has been found and indented correctly.
+
+\subsection{removeParagraphLineBreaks: modifying line breaks for paragraphs}\label{subsec:removeparagraphlinebreaks}
+ When the \texttt{-m} switch is active \texttt{latexindent.pl} has the
+ ability to remove line breaks%
+ \announce{2017-05-27}{removeParagraphLineBreaks} from within paragraphs; the behaviour is controlled by the
+ \texttt{removeParagraphLineBreaks} field, detailed in \cref{lst:removeParagraphLineBreaks}. Thank you to
+ \cite{jowens} for shaping and assisting with the testing of this feature.
+\yamltitle{removeParagraphLineBreaks}*{fields}
+ This feature is considered complimentary to the \texttt{oneSentencePerLine} feature
+ described in \vref{sec:onesentenceperline}.
+
+ \cmhlistingsfromfile[style=removeParagraphLineBreaks]*{../defaultSettings.yaml}[MLB-TCB,width=.85\linewidth,before=\centering]{\texttt{removeParagraphLineBreaks}}{lst:removeParagraphLineBreaks}
+
+ This routine can be turned on \emph{globally} for \emph{every}
+ code block type known to \texttt{latexindent.pl}
+ (see \vref{tab:code-blocks}) by using the
+ \texttt{all} switch; by default, this switch is
+ \emph{off}. Assuming that the \texttt{all} switch is off,
+ then the routine can be controlled on a per-code-block-type basis, and within that, on a
+ per-name basis. We will consider examples of each of these in turn, but before we do,
+ let's specify what \texttt{latexindent.pl} considers as a paragraph:
+ \begin{itemize}
+ \item it must begin on its own line with either an alphabetic or numeric character, and not
+ with any of the code-block types detailed in \vref{tab:code-blocks};
+ \item it can include line breaks, but finishes when it meets either a blank line, a
+ \lstinline!\par! command, or any of the user-specified settings in the
+ \texttt{paragraphsStopAt} field, detailed in \vref{lst:paragraphsStopAt}.
+ \end{itemize}
+
+ Let's start with the \texttt{.tex} file in \cref{lst:shortlines},
+ together with the YAML settings in \cref{lst:remove-para1-yaml}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/shortlines.tex}{\texttt{shortlines.tex}}{lst:shortlines}
+ \cmhlistingsfromfile{demonstrations/remove-para1.yaml}[MLB-TCB]{\texttt{remove-para1.yaml}}{lst:remove-para1-yaml}
+ \end{cmhtcbraster}
+
+ Upon running the command
+ \begin{commandshell}
+latexindent.pl -m shortlines.tex -o shortlines1.tex -l remove-para1.yaml
+\end{commandshell}
+ then we obtain the output given in \cref{lst:shortlines1}.
+
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/shortlines1.tex}{\texttt{shortlines1.tex}}{lst:shortlines1}
+
+ Keen readers may notice that some trailing white space must be present in the file in
+ \cref{lst:shortlines} which has crept in to the output in
+ \cref{lst:shortlines1}. This can be fixed using the YAML file in
+ \vref{lst:removeTWS-before} and running, for example,
+ \begin{commandshell}
+latexindent.pl -m shortlines.tex -o shortlines1-tws.tex -l remove-para1.yaml,removeTWS-before.yaml
+\end{commandshell}
+ in which case the output is as in \cref{lst:shortlines1-tws}; notice that the double
+ spaces present in \cref{lst:shortlines1} have been addressed.
+
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/shortlines1-tws.tex}{\texttt{shortlines1-tws.tex}}{lst:shortlines1-tws}
+
+ Keeping with the settings in \cref{lst:remove-para1-yaml}, we note that the
+ \texttt{all} switch applies to \emph{all} code block
+ types. So, for example, let's consider the files in \cref{lst:shortlines-mand,lst:shortlines-opt}
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/shortlines-mand.tex}{\texttt{shortlines-mand.tex}}{lst:shortlines-mand}
+ \cmhlistingsfromfile{demonstrations/shortlines-opt.tex}{\texttt{shortlines-opt.tex}}{lst:shortlines-opt}
+ \end{cmhtcbraster}
+
+ Upon running the commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl -m shortlines-mand.tex -o shortlines-mand1.tex -l remove-para1.yaml
+latexindent.pl -m shortlines-opt.tex -o shortlines-opt1.tex -l remove-para1.yaml
+\end{commandshell}
+ \end{widepage}
+
+ then we obtain the respective output given in \cref{lst:shortlines-mand1,lst:shortlines-opt1}.
+
+ \cmhlistingsfromfile{demonstrations/shortlines-mand1.tex}{\texttt{shortlines-mand1.tex}}{lst:shortlines-mand1}
+ \cmhlistingsfromfile{demonstrations/shortlines-opt1.tex}{\texttt{shortlines-opt1.tex}}{lst:shortlines-opt1}
+
+ Assuming that we turn \emph{off} the \texttt{all} switch
+ (by setting it to \texttt{0}), then we can control the behaviour of
+ \texttt{removeParagraphLineBreaks} either on a per-code-block-type basis, or on a per-name
+ basis.
+
+ For example, let's use the code in \cref{lst:shortlines-envs}, and consider the settings
+ in \cref{lst:remove-para2-yaml,lst:remove-para3-yaml}; note that in \cref{lst:remove-para2-yaml} we specify that
+ \emph{every} environment should receive treatment from the routine, while
+ in \cref{lst:remove-para3-yaml} we specify that \emph{only} the
+ \texttt{one} environment should receive the treatment.
+
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/shortlines-envs.tex}{\texttt{shortlines-envs.tex}}{lst:shortlines-envs}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\linewidth}
+ \cmhlistingsfromfile{demonstrations/remove-para2.yaml}[MLB-TCB]{\texttt{remove-para2.yaml}}{lst:remove-para2-yaml}
+ \cmhlistingsfromfile{demonstrations/remove-para3.yaml}[MLB-TCB]{\texttt{remove-para3.yaml}}{lst:remove-para3-yaml}
+ \end{minipage}
+
+ Upon running the commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl -m shortlines-envs.tex -o shortlines-envs2.tex -l remove-para2.yaml
+latexindent.pl -m shortlines-envs.tex -o shortlines-envs3.tex -l remove-para3.yaml
+\end{commandshell}
+ \end{widepage}
+ then we obtain the respective output given in \cref{lst:shortlines-envs2,lst:shortlines-envs3}.
+
+ \cmhlistingsfromfile{demonstrations/shortlines-envs2.tex}{\texttt{shortlines-envs2.tex}}{lst:shortlines-envs2}
+ \cmhlistingsfromfile{demonstrations/shortlines-envs3.tex}{\texttt{shortlines-envs3.tex}}{lst:shortlines-envs3}
+
+ The remaining code-block types can be customised in analogous ways, although note that
+ \texttt{commands}, \texttt{keyEqualsValuesBracesBrackets}, \texttt{namedGroupingBracesBrackets},
+ \texttt{UnNamedGroupingBracesBrackets} are controlled by the \texttt{optionalArguments} and the
+ \texttt{mandatoryArguments}.
+
+ The only special case is the \texttt{masterDocument} field; this is designed for
+ `chapter'-type files that may contain paragraphs that are not within any other
+ code-blocks. For example, consider the file in \cref{lst:shortlines-md}, with the YAML
+ settings in \cref{lst:remove-para4-yaml}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/shortlines-md.tex}{\texttt{shortlines-md.tex}}{lst:shortlines-md}
+ \cmhlistingsfromfile{demonstrations/remove-para4.yaml}[MLB-TCB]{\texttt{remove-para4.yaml}}{lst:remove-para4-yaml}
+ \end{cmhtcbraster}
+
+ Upon running the following command
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl -m shortlines-md.tex -o shortlines-md4.tex -l remove-para4.yaml
+\end{commandshell}
+ \end{widepage}
+ then we obtain the output in \cref{lst:shortlines-md4}. \cmhlistingsfromfile{demonstrations/shortlines-md4.tex}{\texttt{shortlines-md4.tex}}{lst:shortlines-md4}
+
+ Note%
+ \announce{2018-08-13}*{updates to all in removeParagraphLineBreaks} that the
+ \texttt{all} field can take the same exceptions detailed in
+ \cref{lst:textwrap6-yaml}{lst:textwrap8-yaml}.
+
+\yamltitle{paragraphsStopAt}*{fields}
+ The paragraph line break routine considers blank lines and the
+ \lstinline|\par| command to be the end of a paragraph;
+ \announce{2017-05-27}{paragraphsStopAt} you can fine tune the behaviour of the routine further by
+ using the \texttt{paragraphsStopAt} fields, shown in \cref{lst:paragraphsStopAt}.
+
+ \cmhlistingsfromfile[style=paragraphsStopAt]*{../defaultSettings.yaml}[MLB-TCB,width=.85\linewidth,before=\centering]{\texttt{paragraphsStopAt}}{lst:paragraphsStopAt}
+
+ The fields specified in \texttt{paragraphsStopAt} tell \texttt{latexindent.pl} to
+ stop the current paragraph when it reaches a line that \emph{begins} with
+ any of the code-block types specified as \texttt{1} in
+ \cref{lst:paragraphsStopAt}. By default, you'll see that the paragraph line break routine
+ will stop when it reaches an environment or verbatim code block at the beginning of a
+ line. It is \emph{not} possible to specify these fields on a per-name
+ basis.
+
+ Let's use the \texttt{.tex} file in \cref{lst:sl-stop}; we will,
+ in turn, consider the settings in \cref{lst:stop-command-yaml,lst:stop-comment-yaml}.
+
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/sl-stop.tex}{\texttt{sl-stop.tex}}{lst:sl-stop}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\linewidth}
+ \cmhlistingsfromfile{demonstrations/stop-command.yaml}[MLB-TCB]{\texttt{stop-command.yaml}}{lst:stop-command-yaml}
+
+ \cmhlistingsfromfile{demonstrations/stop-comment.yaml}[MLB-TCB]{\texttt{stop-comment.yaml}}{lst:stop-comment-yaml}
+ \end{minipage}
+
+ Upon using the settings from \vref{lst:remove-para4-yaml} and running the commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl -m sl-stop.tex -o sl-stop4.tex -l remove-para4.yaml
+latexindent.pl -m sl-stop.tex -o sl-stop4-command.tex -l=remove-para4.yaml,stop-command.yaml
+latexindent.pl -m sl-stop.tex -o sl-stop4-comment.tex -l=remove-para4.yaml,stop-comment.yaml
+\end{commandshell}
+ \end{widepage}
+ we obtain the respective outputs in \crefrange{lst:sl-stop4}{lst:sl-stop4-comment}; notice in particular
+ that:
+ \begin{itemize}
+ \item in \cref{lst:sl-stop4} the paragraph line break routine has included commands and
+ comments;
+ \item in \cref{lst:sl-stop4-command} the paragraph line break routine has
+ \emph{stopped} at the \texttt{emph} command, because in
+ \cref{lst:stop-command-yaml} we have specified \texttt{commands} to be
+ \texttt{1}, and \texttt{emph} is at the beginning of a
+ line;
+ \item in \cref{lst:sl-stop4-comment} the paragraph line break routine has
+ \emph{stopped} at the comments, because in \cref{lst:stop-comment-yaml} we
+ have specified \texttt{comments} to be \texttt{1}, and the
+ comment is at the beginning of a line.
+ \end{itemize}
+ In all outputs in \crefrange{lst:sl-stop4}{lst:sl-stop4-comment} we notice that the paragraph line break
+ routine has stopped at \lstinline!\begin{myenv}! because, by default,
+ \texttt{environments} is set to \texttt{1} in
+ \vref{lst:paragraphsStopAt}.
+
+ \cmhlistingsfromfile{demonstrations/sl-stop4.tex}{\texttt{sl-stop4.tex}}{lst:sl-stop4}
+ \cmhlistingsfromfile{demonstrations/sl-stop4-command.tex}{\texttt{sl-stop4-command.tex}}{lst:sl-stop4-command}
+ \cmhlistingsfromfile{demonstrations/sl-stop4-comment.tex}{\texttt{sl-stop4-comment.tex}}{lst:sl-stop4-comment}
+
+\subsection{Combining removeParagraphLineBreaks and textWrapOptions}\label{subsec:removeparagraphlinebreaks:and:textwrap}
+
+ The%
+ \announce{2018-08-13}{combine text wrap and remove paragraph line breaks} text wrapping
+ routine (\vref{subsec:textwrapping}) and remove paragraph line breaks routine
+ (\vref{subsec:removeparagraphlinebreaks}) can be combined.
+
+ We motivate this feature with the code given in \cref{lst:textwrap7}.
+
+ \cmhlistingsfromfile{demonstrations/textwrap7.tex}{\texttt{textwrap7.tex}}{lst:textwrap7}
+
+ Applying the text wrap routine from \vref{subsec:textwrapping} with, for example,
+ \vref{lst:textwrap3-yaml} gives the output in \cref{lst:textwrap7-mod3}.
+
+ \cmhlistingsfromfile{demonstrations/textwrap7-mod3.tex}{\texttt{textwrap7.tex} using \cref{lst:textwrap3-yaml}}{lst:textwrap7-mod3}
+
+ The text wrapping routine has behaved as expected, but it may be desired to remove
+ paragraph line breaks \emph{before} performing the text wrapping routine.
+ The desired behaviour can be achieved by employing the \texttt{beforeTextWrap}
+ switch.
+
+ Explicitly, using the settings in \cref{lst:textwrap12-yaml} and running the command
+ \begin{commandshell}
+latexindent.pl -m textwrap7.tex -l=textwrap12.yaml -o=+-mod12
+\end{commandshell}
+ we obtain the output in \cref{lst:textwrap7-mod12}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/textwrap7-mod12.tex}{\texttt{textwrap7-mod12.tex}}{lst:textwrap7-mod12}
+ \cmhlistingsfromfile{demonstrations/textwrap12.yaml}[MLB-TCB]{\texttt{textwrap12.yaml}}{lst:textwrap12-yaml}
+ \end{cmhtcbraster}
+
+ In \cref{lst:textwrap7-mod12} the paragraph line breaks have first been removed from
+ \cref{lst:textwrap7}, and then the text wrapping routine has been applied. It is
+ envisaged that variants of \cref{lst:textwrap12-yaml} will be among the most useful
+ settings for these two features.
+
+\subsection{Poly-switches}\label{sec:poly-switches}
+ Every other field in the \texttt{modifyLineBreaks} field uses poly-switches, and can
+ take one of \emph{five}%
+ \announce{2017-08-21}*{blank line poly-switch} integer values:
+ \begin{itemize}[font=\bfseries]
+ \item[$-1$] \emph{remove mode}: line breaks before or after the
+ \emph{<part of thing>} can be removed (assuming that \texttt{preserveBlankLines} is
+ set to \texttt{0});
+ \item[0] \emph{off mode}: line breaks will not be modified for the
+ \emph{<part of thing>} under consideration;
+ \item[1] \emph{add mode}: a line break will be added before or after the
+ \emph{<part of thing>} under consideration, assuming that
+ there is not already a line break before or after the \emph{<part of thing>};
+ \item[2] \emph{comment then add mode}: a comment symbol will be added, followed by a line break
+ before or after the \emph{<part of thing>} under consideration, assuming that there
+ is not already a comment and line break before or after the \emph{<part of thing>};
+ \item[3] \emph{add then blank line mode}%
+ \announce{2017-08-21}{blank line poly-switch}: a line break will be added before or after the
+ \emph{<part of thing>} under consideration, assuming that
+ there is not already a line break before or after the \emph{<part of thing>},
+ followed by a blank line;
+ \item[4] \emph{add blank line mode}%
+ \announce*{2019-07-13}{blank line poly-switch}; a blank line will
+ be added before or after the \emph{<part of thing>} under consideration, even if the
+ \emph{<part of thing>} is already on its own line.
+ \end{itemize}
+ In the above, \emph{<part of thing>} refers to either the
+ \emph{begin statement}, \emph{body} or \emph{end statement}
+ of the code blocks detailed in \vref{tab:code-blocks}. All poly-switches are
+ \emph{off} by default; \texttt{latexindent.pl} searches first of all
+ for per-name settings, and then followed by global per-thing settings.
+
+\subsection{modifyLineBreaks for environments}\label{sec:modifylinebreaks-environments}
+ We start by viewing a snippet of \texttt{defaultSettings.yaml} in
+ \cref{lst:environments-mlb}; note that it contains \emph{global} settings
+ (immediately after the \texttt{environments} field) and that
+ \emph{per-name} settings are also allowed -- in the case of
+ \cref{lst:environments-mlb}, settings for \texttt{equation*} have been specified
+ for demonstration. Note that all poly-switches are \emph{off} (set to 0) by
+ default.
+
+ \cmhlistingsfromfile[style=modifylinebreaksEnv]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,MLB-TCB]{\texttt{environments}}{lst:environments-mlb}
+
+ Let's begin with the simple example given in \cref{lst:env-mlb1-tex}; note that we
+ have annotated key parts of the file using $\BeginStartsOnOwnLine$,
+ $\BodyStartsOnOwnLine$, $\EndStartsOnOwnLine$ and $\EndFinishesWithLineBreak$,
+ these will be related to fields specified in \cref{lst:environments-mlb}.
+
+ \begin{cmhlistings}[style=tcblatex,escapeinside={(*@}{@*)}]{\texttt{env-mlb1.tex}}{lst:env-mlb1-tex}
+before words(*@$\BeginStartsOnOwnLine$@*) \begin{myenv}(*@$\BodyStartsOnOwnLine$@*)body of myenv(*@$\EndStartsOnOwnLine$@*)\end{myenv}(*@$\EndFinishesWithLineBreak$@*) after words
+\end{cmhlistings}
+
+\subsubsection{Adding line breaks: BeginStartsOnOwnLine and BodyStartsOnOwnLine}
+ Let's explore \texttt{BeginStartsOnOwnLine} and \texttt{BodyStartsOnOwnLine} in
+ \cref{lst:env-mlb1,lst:env-mlb2}, and in particular, let's allow each of them in turn to take
+ a value of $1$.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb1.yaml}[MLB-TCB]{\texttt{env-mlb1.yaml}}{lst:env-mlb1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb2.yaml}[MLB-TCB]{\texttt{env-mlb2.yaml}}{lst:env-mlb2}
+ \end{minipage}
+
+ After running the following commands,
+ \begin{commandshell}
+latexindent.pl -m env-mlb.tex -l env-mlb1.yaml
+latexindent.pl -m env-mlb.tex -l env-mlb2.yaml
+\end{commandshell}
+ the output is as in \cref{lst:env-mlb-mod1,lst:env-mlb-mod2} respectively.
+
+ \begin{widepage}
+ \begin{minipage}{.56\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod1.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb1}}{lst:env-mlb-mod1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.43\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod2.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb2}}{lst:env-mlb-mod2}
+ \end{minipage}
+ \end{widepage}
+
+ There are a couple of points to note:
+ \begin{itemize}
+ \item in \cref{lst:env-mlb-mod1} a line break has been added at the point denoted by
+ $\BeginStartsOnOwnLine$ in \cref{lst:env-mlb1-tex}; no other line breaks have been
+ changed;
+ \item in \cref{lst:env-mlb-mod2} a line break has been added at the point denoted by
+ $\BodyStartsOnOwnLine$ in \cref{lst:env-mlb1-tex}; furthermore, note that the
+ \emph{body} of \texttt{myenv} has received the appropriate
+ (default) indentation.
+ \end{itemize}
+
+ Let's now change each of the \texttt{1} values in
+ \cref{lst:env-mlb1,lst:env-mlb2} so that they are $2$ and save them
+ into \texttt{env-mlb3.yaml} and \texttt{env-mlb4.yaml} respectively (see
+ \cref{lst:env-mlb3,lst:env-mlb4}).
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb3.yaml}[MLB-TCB]{\texttt{env-mlb3.yaml}}{lst:env-mlb3}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb4.yaml}[MLB-TCB]{\texttt{env-mlb4.yaml}}{lst:env-mlb4}
+ \end{minipage}
+
+ Upon running commands analogous to the above, we obtain \cref{lst:env-mlb-mod3,lst:env-mlb-mod4}.
+
+ \begin{widepage}
+ \begin{minipage}{.56\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod3.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb3}}{lst:env-mlb-mod3}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.43\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod4.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb4}}{lst:env-mlb-mod4}
+ \end{minipage}
+ \end{widepage}
+
+ Note that line breaks have been added as in \cref{lst:env-mlb-mod1,lst:env-mlb-mod2}, but this time a
+ comment symbol has been added before adding the line break; in both cases, trailing
+ horizontal space has been stripped before doing so.
+
+ Let's%
+ \announce{2017-08-21}{demonstration of blank line poly-switch (3)} now change each of
+ the \texttt{1} values in \cref{lst:env-mlb1,lst:env-mlb2} so that they are
+ $3$ and save them into \texttt{env-mlb5.yaml} and
+ \texttt{env-mlb6.yaml} respectively (see \cref{lst:env-mlb5,lst:env-mlb6}).
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb5.yaml}[MLB-TCB]{\texttt{env-mlb5.yaml}}{lst:env-mlb5}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb6.yaml}[MLB-TCB]{\texttt{env-mlb6.yaml}}{lst:env-mlb6}
+ \end{minipage}
+
+ Upon running commands analogous to the above, we obtain \cref{lst:env-mlb-mod5,lst:env-mlb-mod6}.
+
+ \begin{widepage}
+ \begin{minipage}{.56\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod5.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb5}}{lst:env-mlb-mod5}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.43\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod6.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb6}}{lst:env-mlb-mod6}
+ \end{minipage}
+ \end{widepage}
+
+ Note that line breaks have been added as in \cref{lst:env-mlb-mod1,lst:env-mlb-mod2}, but this time a
+ \emph{blank line} has been added after adding the line break.
+
+ Let's now change%
+ \announce*{2019-07-13}{demonstration of new blank line poly-switch} each of
+ the \texttt{1} values in \cref{lst:env-mlb5,lst:env-mlb6} so that they are
+ $4$ and save them into \texttt{env-beg4.yaml} and
+ \texttt{env-body4.yaml} respectively (see \cref{lst:env-beg4,lst:env-body4}).
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/env-beg4.yaml}[MLB-TCB]{\texttt{env-beg4.yaml}}{lst:env-beg4}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/env-body4.yaml}[MLB-TCB]{\texttt{env-body4.yaml}}{lst:env-body4}
+ \end{minipage}
+
+ We will demonstrate this poly-switch value using the code in \cref{lst:env-mlb1-text}.
+
+ \cmhlistingsfromfile*{demonstrations/env-mlb1.tex}{\texttt{env-mlb1.tex}}{lst:env-mlb1-text}
+
+ Upon running the commands
+ \begin{commandshell}
+latexindent.pl -m env-mlb1.tex -l env-beg4.yaml
+latexindent.pl -m env-mlb.1tex -l env-body4.yaml
+\end{commandshell}
+
+ then we receive the respective outputs in \cref{lst:env-mlb1-beg4,lst:env-mlb1-body4}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile*{demonstrations/env-mlb1-beg4.tex}{\texttt{env-mlb1.tex} using \cref{lst:env-beg4}}{lst:env-mlb1-beg4}
+ \cmhlistingsfromfile*{demonstrations/env-mlb1-body4.tex}{\texttt{env-mlb1.tex} using \cref{lst:env-body4}}{lst:env-mlb1-body4}
+ \end{cmhtcbraster}
+
+ We note in particular that, by design, for this value of the poly-switches:
+ \begin{enumerate}
+ \item in \cref{lst:env-mlb1-beg4} a blank line has been inserted before the
+ \lstinline!\begin! statement, even though the \lstinline!\begin!
+ statement was already on its own line;
+ \item in \cref{lst:env-mlb1-body4} a blank line has been inserted before the beginning of the
+ \emph{body}, even though it already began on its own line.
+ \end{enumerate}
+
+\subsubsection{Adding line breaks using EndStartsOnOwnLine and EndFinishesWithLineBreak}
+ Let's explore \texttt{EndStartsOnOwnLine} and \texttt{EndFinishesWithLineBreak} in
+ \cref{lst:env-mlb7,lst:env-mlb8}, and in particular, let's allow each of them in turn to take
+ a value of $1$.
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb7.yaml}[MLB-TCB]{\texttt{env-mlb7.yaml}}{lst:env-mlb7}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb8.yaml}[MLB-TCB]{\texttt{env-mlb8.yaml}}{lst:env-mlb8}
+ \end{minipage}
+
+ After running the following commands,
+ \begin{commandshell}
+latexindent.pl -m env-mlb.tex -l env-mlb7.yaml
+latexindent.pl -m env-mlb.tex -l env-mlb8.yaml
+\end{commandshell}
+ the output is as in \cref{lst:env-mlb-mod7,lst:env-mlb-mod8}.
+
+ \begin{widepage}
+ \begin{minipage}{.42\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod7.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb7}}{lst:env-mlb-mod7}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.57\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod8.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb8}}{lst:env-mlb-mod8}
+ \end{minipage}
+ \end{widepage}
+
+ There are a couple of points to note:
+ \begin{itemize}
+ \item in \cref{lst:env-mlb-mod7} a line break has been added at the point denoted by
+ $\EndStartsOnOwnLine$ in \vref{lst:env-mlb1-tex}; no other line breaks have been
+ changed and the \lstinline!\end{myenv}! statement has \emph{not}
+ received indentation (as intended);
+ \item in \cref{lst:env-mlb-mod8} a line break has been added at the point denoted by
+ $\EndFinishesWithLineBreak$ in \vref{lst:env-mlb1-tex}.
+ \end{itemize}
+
+ Let's now change each of the \texttt{1} values in
+ \cref{lst:env-mlb7,lst:env-mlb8} so that they are $2$ and save them
+ into \texttt{env-mlb9.yaml} and \texttt{env-mlb10.yaml} respectively (see
+ \cref{lst:env-mlb9,lst:env-mlb10}).
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb9.yaml}[MLB-TCB]{\texttt{env-mlb9.yaml}}{lst:env-mlb9}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb10.yaml}[MLB-TCB]{\texttt{env-mlb10.yaml}}{lst:env-mlb10}
+ \end{minipage}
+
+ Upon running commands analogous to the above, we obtain \cref{lst:env-mlb-mod9,lst:env-mlb-mod10}.
+
+ \begin{widepage}
+ \begin{minipage}{.43\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod9.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb9}}{lst:env-mlb-mod9}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.56\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod10.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb10}}{lst:env-mlb-mod10}
+ \end{minipage}
+ \end{widepage}
+
+ Note that line breaks have been added as in \cref{lst:env-mlb-mod7,lst:env-mlb-mod8}, but this time a
+ comment symbol has been added before adding the line break; in both cases, trailing
+ horizontal space has been stripped before doing so.
+
+ Let's%
+ \announce{2017-08-21}{demonstration of blank line poly-switch (3)} now change each of
+ the \texttt{1} values in \cref{lst:env-mlb7,lst:env-mlb8} so that they are
+ $3$ and save them into \texttt{env-mlb11.yaml} and
+ \texttt{env-mlb12.yaml} respectively (see \cref{lst:env-mlb11,lst:env-mlb12}).
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb11.yaml}[MLB-TCB]{\texttt{env-mlb11.yaml}}{lst:env-mlb11}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb12.yaml}[MLB-TCB]{\texttt{env-mlb12.yaml}}{lst:env-mlb12}
+ \end{minipage}
+
+ Upon running commands analogous to the above, we obtain \cref{lst:env-mlb-mod11,lst:env-mlb-mod12}.
+
+ \begin{widepage}
+ \begin{minipage}{.42\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod11.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb11}}{lst:env-mlb-mod11}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.57\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb-mod12.tex}{\texttt{env-mlb.tex} using \cref{lst:env-mlb12}}{lst:env-mlb-mod12}
+ \end{minipage}
+ \end{widepage}
+
+ Note that line breaks have been added as in \cref{lst:env-mlb-mod7,lst:env-mlb-mod8}, and that a
+ \emph{blank line} has been added after the line break.
+
+ Let's now change%
+ \announce*{2019-07-13}{demonstration of new blank line poly-switch} each of
+ the \texttt{1} values in \cref{lst:env-mlb11,lst:env-mlb12} so that they are
+ $4$ and save them into \texttt{env-end4.yaml} and
+ \texttt{env-end-f4.yaml} respectively (see \cref{lst:env-end4,lst:env-end-f4}).
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/env-end4.yaml}[MLB-TCB]{\texttt{env-end4.yaml}}{lst:env-end4}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.5\textwidth}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/env-end-f4.yaml}[MLB-TCB]{\texttt{env-end-f4.yaml}}{lst:env-end-f4}
+ \end{minipage}
+
+ We will demonstrate this poly-switch value using the code from
+ \vref{lst:env-mlb1-text}.
+
+ Upon running the commands
+ \begin{commandshell}
+latexindent.pl -m env-mlb1.tex -l env-end4.yaml
+latexindent.pl -m env-mlb.1tex -l env-end-f4.yaml
+\end{commandshell}
+
+ then we receive the respective outputs in \cref{lst:env-mlb1-end4,lst:env-mlb1-end-f4}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile*{demonstrations/env-mlb1-end4.tex}{\texttt{env-mlb1.tex} using \cref{lst:env-end4}}{lst:env-mlb1-end4}
+ \cmhlistingsfromfile*{demonstrations/env-mlb1-end-f4.tex}{\texttt{env-mlb1.tex} using \cref{lst:env-end-f4}}{lst:env-mlb1-end-f4}
+ \end{cmhtcbraster}
+
+ We note in particular that, by design, for this value of the poly-switches:
+ \begin{enumerate}
+ \item in \cref{lst:env-mlb1-end4} a blank line has been inserted before the
+ \lstinline!\end! statement, even though the \lstinline!\end!
+ statement was already on its own line;
+ \item in \cref{lst:env-mlb1-end-f4} a blank line has been inserted after the
+ \lstinline!\end! statement, even though it already began on its own line.
+ \end{enumerate}
+
+\subsubsection{poly-switches 1, 2, and 3 only add line breaks when necessary}
+ If you ask \texttt{latexindent.pl} to add a line break (possibly with a comment)
+ using a poly-switch value of $1$ (or $2$
+ or $3$), it will only do so if necessary. For example, if you
+ process the file in \vref{lst:mlb2} using poly-switch values of 1, 2, or 3,
+ it will be left unchanged.
+
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb2.tex}{\texttt{env-mlb2.tex}}{lst:mlb2}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb3.tex}{\texttt{env-mlb3.tex}}{lst:mlb3}
+ \end{minipage}
+
+ Setting the poly-switches to a value of $4$ instructs
+ \texttt{latexindent.pl} to add a line break even if the \emph{<part of thing>}
+ is already on its own line; see \cref{lst:env-mlb1-beg4,lst:env-mlb1-body4} and
+ \cref{lst:env-mlb1-end4,lst:env-mlb1-end-f4}.
+
+ In contrast, the output from processing the file in \cref{lst:mlb3} will
+ vary depending on the poly-switches used; in \cref{lst:env-mlb3-mod2} you'll see that
+ the comment symbol after the \lstinline!\begin{myenv}! has been moved to the next line,
+ as \texttt{BodyStartsOnOwnLine} is set to \texttt{1}. In
+ \cref{lst:env-mlb3-mod4} you'll see that the comment has been accounted for correctly
+ because \texttt{BodyStartsOnOwnLine} has been set to \texttt{2}, and
+ the comment symbol has \emph{not} been moved to its own line. You're
+ encouraged to experiment with \cref{lst:mlb3} and by setting the other
+ poly-switches considered so far to \texttt{2} in turn.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/env-mlb3-mod2.tex}{\texttt{env-mlb3.tex} using \vref{lst:env-mlb2}}{lst:env-mlb3-mod2}
+ \cmhlistingsfromfile{demonstrations/env-mlb3-mod4.tex}{\texttt{env-mlb3.tex} using \vref{lst:env-mlb4}}{lst:env-mlb3-mod4}
+ \end{cmhtcbraster}
+
+ The details of the discussion in this section have concerned \emph{global}
+ poly-switches in the \texttt{environments} field; each switch can also be
+ specified on a \emph{per-name} basis, which would take priority over the
+ global values; with reference to \vref{lst:environments-mlb}, an example is shown for
+ the \texttt{equation*} environment.
+
+\subsubsection{Removing line breaks (poly-switches set to $-1$)}
+ Setting poly-switches to $-1$ tells \texttt{latexindent.pl}
+ to remove line breaks of the \emph{<part of the thing>}, if necessary. We will consider
+ the example code given in \cref{lst:mlb4}, noting in particular the
+ positions of the line break highlighters, $\BeginStartsOnOwnLine$,
+ $\BodyStartsOnOwnLine$, $\EndStartsOnOwnLine$ and $\EndFinishesWithLineBreak$,
+ together with the associated YAML files in \crefrange{lst:env-mlb13}{lst:env-mlb16}.
+
+ \begin{minipage}{.45\linewidth}
+ \begin{cmhlistings}[style=tcblatex,escapeinside={(*@}{@*)}]{\texttt{env-mlb4.tex}}{lst:mlb4}
+before words(*@$\BeginStartsOnOwnLine$@*)
+\begin{myenv}(*@$\BodyStartsOnOwnLine$@*)
+body of myenv(*@$\EndStartsOnOwnLine$@*)
+\end{myenv}(*@$\EndFinishesWithLineBreak$@*)
+after words
+\end{cmhlistings}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.51\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb13.yaml}[MLB-TCB]{\texttt{env-mlb13.yaml}}{lst:env-mlb13}
+
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb14.yaml}[MLB-TCB]{\texttt{env-mlb14.yaml}}{lst:env-mlb14}
+
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb15.yaml}[MLB-TCB]{\texttt{env-mlb15.yaml}}{lst:env-mlb15}
+
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/env-mlb16.yaml}[MLB-TCB]{\texttt{env-mlb16.yaml}}{lst:env-mlb16}
+ \end{minipage}
+
+ After running the commands
+ \begin{commandshell}
+latexindent.pl -m env-mlb4.tex -l env-mlb13.yaml
+latexindent.pl -m env-mlb4.tex -l env-mlb14.yaml
+latexindent.pl -m env-mlb4.tex -l env-mlb15.yaml
+latexindent.pl -m env-mlb4.tex -l env-mlb16.yaml
+\end{commandshell}
+
+ we obtain the respective output in \crefrange{lst:env-mlb4-mod13}{lst:env-mlb4-mod16}.
+
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb4-mod13.tex}{\texttt{env-mlb4.tex} using \cref{lst:env-mlb13}}{lst:env-mlb4-mod13}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb4-mod14.tex}{\texttt{env-mlb4.tex} using \cref{lst:env-mlb14}}{lst:env-mlb4-mod14}
+ \end{minipage}
+
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb4-mod15.tex}{\texttt{env-mlb4.tex} using \cref{lst:env-mlb15}}{lst:env-mlb4-mod15}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\linewidth}
+ \cmhlistingsfromfile{demonstrations/env-mlb4-mod16.tex}{\texttt{env-mlb4.tex} using \cref{lst:env-mlb16}}{lst:env-mlb4-mod16}
+ \end{minipage}
+
+ Notice that in:
+ \begin{itemize}
+ \item \cref{lst:env-mlb4-mod13} the line break denoted by $\BeginStartsOnOwnLine$ in
+ \cref{lst:mlb4} has been removed;
+ \item \cref{lst:env-mlb4-mod14} the line break denoted by $\BodyStartsOnOwnLine$ in
+ \cref{lst:mlb4} has been removed;
+ \item \cref{lst:env-mlb4-mod15} the line break denoted by $\EndStartsOnOwnLine$ in
+ \cref{lst:mlb4} has been removed;
+ \item \cref{lst:env-mlb4-mod16} the line break denoted by $\EndFinishesWithLineBreak$ in
+ \cref{lst:mlb4} has been removed.
+ \end{itemize}
+ We examined each of these cases separately for clarity of explanation, but you can
+ combine all of the YAML settings in \crefrange{lst:env-mlb13}{lst:env-mlb16} into one file;
+ alternatively, you could tell \texttt{latexindent.pl} to load them all by using the
+ following command, for example
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl -m env-mlb4.tex -l env-mlb13.yaml,env-mlb14.yaml,env-mlb15.yaml,env-mlb16.yaml
+\end{commandshell}
+ \end{widepage}
+ which gives the output in \vref{lst:env-mlb1-tex}.
+
+\subsubsection{About trailing horizontal space}
+ Recall that on \cpageref{yaml:removeTrailingWhitespace} we discussed the YAML field
+ \texttt{removeTrailingWhitespace}, and that it has two (binary) switches to determine if
+ horizontal space should be removed \texttt{beforeProcessing} and
+ \texttt{afterProcessing}. The \texttt{beforeProcessing} is particularly relevant
+ when considering the \texttt{-m} switch; let's consider the file shown
+ in \cref{lst:mlb5}, which highlights trailing spaces.
+
+ \begin{cmhtcbraster}
+ \begin{cmhlistings}[style=tcblatex,showspaces=true,escapeinside={(*@}{@*)}]{\texttt{env-mlb5.tex}}{lst:mlb5}
+before words (*@$\BeginStartsOnOwnLine$@*)
+\begin{myenv} (*@$\BodyStartsOnOwnLine$@*)
+body of myenv (*@$\EndStartsOnOwnLine$@*)
+\end{myenv} (*@$\EndFinishesWithLineBreak$@*)
+after words
+\end{cmhlistings}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/removeTWS-before.yaml}[yaml-TCB]{\texttt{removeTWS-before.yaml}}{lst:removeTWS-before}
+ \end{cmhtcbraster}
+
+ The output from the following commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl -m env-mlb5.tex -l env-mlb13.yaml,env-mlb14.yaml,env-mlb15.yaml,env-mlb16.yaml
+latexindent.pl -m env-mlb5.tex -l env-mlb13.yaml,env-mlb14.yaml,env-mlb15.yaml,env-mlb16.yaml,removeTWS-before.yaml
+\end{commandshell}
+ \end{widepage}
+ is shown, respectively, in \cref{lst:env-mlb5-modAll,lst:env-mlb5-modAll-remove-WS}; note that the trailing
+ horizontal white space has been preserved (by default) in \cref{lst:env-mlb5-modAll},
+ while in \cref{lst:env-mlb5-modAll-remove-WS}, it has been removed using the switch specified in
+ \cref{lst:removeTWS-before}.
+
+ \begin{widepage}
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/env-mlb5-modAll.tex}{\texttt{env-mlb5.tex} using \crefrange{lst:env-mlb4-mod13}{lst:env-mlb4-mod16}}{lst:env-mlb5-modAll}
+
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/env-mlb5-modAll-remove-WS.tex}{\texttt{env-mlb5.tex} using \crefrange{lst:env-mlb4-mod13}{lst:env-mlb4-mod16} \emph{and} \cref{lst:removeTWS-before}}{lst:env-mlb5-modAll-remove-WS}
+ \end{widepage}
+
+\subsubsection{poly-switch line break removal and blank lines}
+ Now let's consider the file in \cref{lst:mlb6}, which contains blank lines.
+
+ \begin{cmhtcbraster}
+ \begin{cmhlistings}[style=tcblatex,escapeinside={(*@}{@*)}]{\texttt{env-mlb6.tex}}{lst:mlb6}
+before words(*@$\BeginStartsOnOwnLine$@*)
+
+
+\begin{myenv}(*@$\BodyStartsOnOwnLine$@*)
+
+
+body of myenv(*@$\EndStartsOnOwnLine$@*)
+
+
+\end{myenv}(*@$\EndFinishesWithLineBreak$@*)
+
+after words
+\end{cmhlistings}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/UnpreserveBlankLines.yaml}[MLB-TCB]{\texttt{UnpreserveBlankLines.yaml}}{lst:UnpreserveBlankLines}
+ \end{cmhtcbraster}
+
+ Upon running the following commands
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl -m env-mlb6.tex -l env-mlb13.yaml,env-mlb14.yaml,env-mlb15.yaml,env-mlb16.yaml
+latexindent.pl -m env-mlb6.tex -l env-mlb13.yaml,env-mlb14.yaml,env-mlb15.yaml,env-mlb16.yaml,UnpreserveBlankLines.yaml
+\end{commandshell}
+ \end{widepage}
+ we receive the respective outputs in \cref{lst:env-mlb6-modAll,lst:env-mlb6-modAll-un-Preserve-Blank-Lines}. In
+ \cref{lst:env-mlb6-modAll} we see that the multiple blank lines have each been
+ condensed into one blank line, but that blank lines have \emph{not}
+ been removed by the poly-switches -- this is because, by default,
+ \texttt{preserveBlankLines} is set to \texttt{1}. By contrast, in
+ \cref{lst:env-mlb6-modAll-un-Preserve-Blank-Lines}, we have allowed the poly-switches to remove blank lines
+ because, in \cref{lst:UnpreserveBlankLines}, we have set \texttt{preserveBlankLines} to
+ \texttt{0}.
+
+ \begin{cmhtcbraster}[ raster left skip=-3.5cm,
+ raster right skip=-2cm,
+ raster force size=false,
+ raster column 1/.style={add to width=-.2\textwidth},
+ raster column 2/.style={add to width=.2\textwidth},
+ raster column skip=.06\linewidth]
+ \cmhlistingsfromfile{demonstrations/env-mlb6-modAll.tex}{\texttt{env-mlb6.tex} using \crefrange{lst:env-mlb4-mod13}{lst:env-mlb4-mod16}}{lst:env-mlb6-modAll}
+ \cmhlistingsfromfile{demonstrations/env-mlb6-modAll-un-Preserve-Blank-Lines.tex}{\texttt{env-mlb6.tex} using \crefrange{lst:env-mlb4-mod13}{lst:env-mlb4-mod16} \emph{and} \cref{lst:UnpreserveBlankLines}}{lst:env-mlb6-modAll-un-Preserve-Blank-Lines}
+ \end{cmhtcbraster}
+
+ We can explore this further using the blank-line poly-switch value of
+ $3$; let's use the file given in \cref{lst:env-mlb7-tex}.
+
+ \cmhlistingsfromfile{demonstrations/env-mlb7.tex}{\texttt{env-mlb7.tex}}{lst:env-mlb7-tex}
+
+ Upon running the following commands
+ \begin{commandshell}
+latexindent.pl -m env-mlb7.tex -l env-mlb12.yaml,env-mlb13.yaml
+latexindent.pl -m env-mlb7.tex -l env-mlb13.yaml,env-mlb14.yaml,UnpreserveBlankLines.yaml
+\end{commandshell}
+ we receive the outputs given in \cref{lst:env-mlb7-preserve,lst:env-mlb7-no-preserve}.
+
+ \cmhlistingsfromfile{demonstrations/env-mlb7-preserve.tex}{\texttt{env-mlb7-preserve.tex}}{lst:env-mlb7-preserve}
+ \cmhlistingsfromfile{demonstrations/env-mlb7-no-preserve.tex}{\texttt{env-mlb7-no-preserve.tex}}{lst:env-mlb7-no-preserve}
+
+ Notice that in:
+ \begin{itemize}
+ \item \cref{lst:env-mlb7-preserve} that \lstinline!\end{one}! has added a blank line,
+ because of the value of \texttt{EndFinishesWithLineBreak} in \vref{lst:env-mlb12}, and
+ even though the line break ahead of \lstinline!\begin{two}! should have been removed
+ (because of \texttt{BeginStartsOnOwnLine} in \vref{lst:env-mlb13}), the blank line
+ has been preserved by default;
+ \item \cref{lst:env-mlb7-no-preserve}, by contrast, has had the additional line-break removed,
+ because of the settings in \cref{lst:UnpreserveBlankLines}.
+ \end{itemize}
+
+\subsection{Poly-switches for double back slash}\label{subsec:dbs}
+ With reference to \texttt{lookForAlignDelims} (see \vref{lst:aligndelims:basic})%
+ \announce*{2019-07-13}{poly-switch for double back slash} you can
+ specify poly-switches to dictate the line-break behaviour of double back slashes in
+ environments (\vref{lst:tabularafter:basic}), commands (\vref{lst:matrixafter}), or
+ special code blocks (\vref{lst:specialafter}). Note that for these poly-switches to
+ take effect, the name of the code block must necessarily be specified within
+ \texttt{lookForAlignDelims} (\vref{lst:aligndelims:basic}); we will demonstrate this in what follows.
+
+ Consider the code given in \cref{lst:dbs-demo}.
+ \begin{cmhlistings}*[style=tcblatex,escapeinside={(*@}{@*)}]{\texttt{tabular3.tex}}{lst:dbs-demo}
+\begin{tabular}{cc}
+ 1 & 2 (*@$\ElseStartsOnOwnLine$@*)\\(*@$\ElseFinishesWithLineBreak$@*) 3 & 4 (*@$\ElseStartsOnOwnLine$@*)\\(*@$\ElseFinishesWithLineBreak$@*)
+\end{tabular}
+\end{cmhlistings}
+ Referencing \cref{lst:dbs-demo}:
+ \begin{itemize}
+ \item \texttt{DBS} stands for \emph{double back slash};
+ \item line breaks ahead of the double back slash are annotated by $\ElseStartsOnOwnLine$,
+ and are controlled by \texttt{DBSStartsOnOwnLine};
+ \item line breaks after the double back slash are annotated by $\ElseFinishesWithLineBreak$, and
+ are controlled by \texttt{DBSFinishesWithLineBreak}.
+ \end{itemize}
+
+ Let's explore each of these in turn.
+
+\subsubsection{Double back slash starts on own line}
+ We explore \texttt{DBSStartsOnOwnLine} ($\ElseStartsOnOwnLine$ in \cref{lst:dbs-demo}); starting with the code in
+ \cref{lst:dbs-demo}, together with the YAML files given in
+ \cref{lst:DBS1} and \cref{lst:DBS2} and running the following
+ commands
+ \begin{commandshell}
+latexindent.pl -m tabular3.tex -l DBS1.yaml
+latexindent.pl -m tabular3.tex -l DBS2.yaml
+\end{commandshell}
+ then we receive the respective output given in \cref{lst:tabular3-DBS1} and
+ \cref{lst:tabular3-DBS2}.
+
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/tabular3-mod1.tex}{\texttt{tabular3.tex} using \cref{lst:DBS1}}{lst:tabular3-DBS1}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/DBS1.yaml}[MLB-TCB]{\texttt{DBS1.yaml}}{lst:DBS1}
+ \end{cmhtcbraster}
+
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/tabular3-mod2.tex}{\texttt{tabular3.tex} using \cref{lst:DBS2}}{lst:tabular3-DBS2}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/DBS2.yaml}[MLB-TCB]{\texttt{DBS2.yaml}}{lst:DBS2}
+ \end{cmhtcbraster}
+
+ We note that
+ \begin{itemize}
+ \item \cref{lst:DBS1} specifies \texttt{DBSStartsOnOwnLine} for
+ \emph{every} environment (that is within \texttt{lookForAlignDelims},
+ \vref{yaml:lookforaligndelims});
+ the double back slashes from \cref{lst:dbs-demo} have been moved to their own
+ line in \cref{lst:tabular3-DBS1};
+ \item \cref{lst:DBS2} specifies \texttt{DBSStartsOnOwnLine} on a
+ \emph{per-name} basis for \texttt{tabular} (that is within \texttt{lookForAlignDelims}, \vref{yaml:lookforaligndelims});
+ the double back slashes from \cref{lst:dbs-demo} have been moved to their own
+ line in \cref{lst:tabular3-DBS2}, having added comment symbols before moving them.
+ \end{itemize}
+
+\subsubsection{Double back slash finishes with line break}
+ Let's now explore \texttt{DBSFinishesWithLineBreak} ($\ElseFinishesWithLineBreak$ in \cref{lst:dbs-demo}); starting with the code in
+ \cref{lst:dbs-demo}, together with the YAML files given in
+ \cref{lst:DBS3} and \cref{lst:DBS4} and running the following
+ commands
+ \begin{commandshell}
+latexindent.pl -m tabular3.tex -l DBS3.yaml
+latexindent.pl -m tabular3.tex -l DBS4.yaml
+\end{commandshell}
+ then we receive the respective output given in \cref{lst:tabular3-DBS3} and
+ \cref{lst:tabular3-DBS4}.
+
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/tabular3-mod3.tex}{\texttt{tabular3.tex} using \cref{lst:DBS3}}{lst:tabular3-DBS3}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/DBS3.yaml}[MLB-TCB]{\texttt{DBS3.yaml}}{lst:DBS3}
+ \end{cmhtcbraster}
+
+ \begin{cmhtcbraster}[raster column skip=.01\linewidth]
+ \cmhlistingsfromfile*{demonstrations/tabular3-mod4.tex}{\texttt{tabular3.tex} using \cref{lst:DBS4}}{lst:tabular3-DBS4}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/DBS4.yaml}[MLB-TCB]{\texttt{DBS4.yaml}}{lst:DBS4}
+ \end{cmhtcbraster}
+
+ We note that
+ \begin{itemize}
+ \item \cref{lst:DBS3} specifies \texttt{DBSFinishesWithLineBreak} for
+ \emph{every} environment (that is within \texttt{lookForAlignDelims},
+ \vref{yaml:lookforaligndelims});
+ the code following the double back slashes from \cref{lst:dbs-demo} has been
+ moved to their own line in \cref{lst:tabular3-DBS3};
+ \item \cref{lst:DBS4} specifies \texttt{DBSFinishesWithLineBreak} on a
+ \emph{per-name} basis for \texttt{tabular} (that is within \texttt{lookForAlignDelims}, \vref{yaml:lookforaligndelims});
+ the first double back slashes from \cref{lst:dbs-demo} have moved code following
+ them to their own line in \cref{lst:tabular3-DBS4}, having added comment symbols
+ before moving them; the final double back slashes have \emph{not} added
+ a line break as they are at the end of the body within the code block.
+ \end{itemize}
+
+\subsubsection{Double back slash poly switches for specialBeginEnd}
+ Let's explore the double back slash poly-switches for code blocks within
+ \texttt{specialBeginEnd} code blocks (\vref{lst:specialBeginEnd}); we begin with
+ the code within \cref{lst:special4}.
+
+ \cmhlistingsfromfile*{demonstrations/special4.tex}{\texttt{special4.tex}}{lst:special4}
+
+ Upon using the YAML settings in \cref{lst:DBS5}, and running the command
+ \begin{commandshell}
+latexindent.pl -m special4.tex -l DBS5.yaml
+\end{commandshell}
+ then we receive the output given in \cref{lst:special4-DBS5}.
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=-.1\textwidth},
+ raster column skip=.06\linewidth]
+ \cmhlistingsfromfile*{demonstrations/special4-mod5.tex}{\texttt{special4.tex} using \cref{lst:DBS5}}{lst:special4-DBS5}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/DBS5.yaml}[MLB-TCB,width=0.6\textwidth]{\texttt{DBS5.yaml}}{lst:DBS5}
+ \end{cmhtcbraster}
+
+ There are a few things to note:
+ \begin{itemize}
+ \item in \cref{lst:DBS5} we have specified \texttt{cmhMath} within
+ \texttt{lookForAlignDelims}; without this, the double back slash poly-switches would be
+ ignored for this code block;
+ \item the \texttt{DBSFinishesWithLineBreak} poly-switch has controlled the line breaks following the
+ double back slashes;
+ \item the \texttt{SpecialEndStartsOnOwnLine} poly-switch has controlled the addition of a comment
+ symbol, followed by a line break, as it is set to a value of 2.
+ \end{itemize}
+
+\subsubsection{Double back slash poly switches for optional and mandatory arguments}
+ For clarity, we provide a demonstration of controlling the double back slash
+ poly-switches for optional and mandatory arguments. We begin with the code in
+ \cref{lst:mycommand2}.
+
+ \cmhlistingsfromfile*{demonstrations/mycommand2.tex}{\texttt{mycommand2.tex}}{lst:mycommand2}
+
+ Upon using the YAML settings in \cref{lst:DBS6,lst:DBS7}, and running the command
+ \begin{commandshell}
+latexindent.pl -m mycommand2.tex -l DBS6.yaml
+latexindent.pl -m mycommand2.tex -l DBS7.yaml
+\end{commandshell}
+ then we receive the output given in \cref{lst:mycommand2-DBS6,lst:mycommand2-DBS7}.
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=-.1\textwidth},
+ raster column skip=.03\linewidth]
+ \cmhlistingsfromfile*{demonstrations/mycommand2-mod6.tex}{\texttt{mycommand2.tex} using \cref{lst:DBS6}}{lst:mycommand2-DBS6}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/DBS6.yaml}[MLB-TCB,width=0.6\textwidth]{\texttt{DBS6.yaml}}{lst:DBS6}
+ \end{cmhtcbraster}
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=-.1\textwidth},
+ raster column skip=.03\linewidth]
+ \cmhlistingsfromfile*{demonstrations/mycommand2-mod7.tex}{\texttt{mycommand2.tex} using \cref{lst:DBS7}}{lst:mycommand2-DBS7}
+ \cmhlistingsfromfile*[style=yaml-LST]*{demonstrations/DBS7.yaml}[MLB-TCB,width=0.6\textwidth]{\texttt{DBS7.yaml}}{lst:DBS7}
+ \end{cmhtcbraster}
+
+\subsubsection{Double back slash optional square brackets}
+ The pattern matching for the double back slash will also, optionally, allow trailing
+ square brackets that contain a measurement of vertical spacing, for example
+ \lstinline!\\[3pt]!.
+
+ For example, beginning with the code in \cref{lst:pmatrix3}
+
+ \cmhlistingsfromfile*{demonstrations/pmatrix3.tex}{\texttt{pmatrix3.tex}}{lst:pmatrix3}
+
+ and running the following command, using \cref{lst:DBS3},
+ \begin{commandshell}
+latexindent.pl -m pmatrix3.tex -l DBS3.yaml
+\end{commandshell}
+ then we receive the output given in \cref{lst:pmatrix3-DBS3}.
+
+ \cmhlistingsfromfile*{demonstrations/pmatrix3-mod3.tex}{\texttt{pmatrix3.tex} using \cref{lst:DBS3}}{lst:pmatrix3-DBS3}
+
+ You can customise the pattern for the double back slash by exploring the
+ \emph{fine tuning} field detailed in \vref{lst:fineTuning}.
+
+\subsection{Poly-switches for other code blocks}
+ Rather than repeat the examples shown for the environment code blocks (in
+ \vref{sec:modifylinebreaks-environments}), we choose to detail the poly-switches for all other code
+ blocks in \cref{tab:poly-switch-mapping}; note that each and every one of these
+ poly-switches is \emph{off by default}, i.e, set to \texttt{0}.
+
+ Note also that, by design, line breaks involving, \texttt{filecontents} and
+ `comment-marked' code blocks (\vref{lst:alignmentmarkup}) can
+ \emph{not} be modified using
+ \texttt{latexindent.pl}.%
+ \announce{2019-05-05}*{verbatim poly-switch} However, there are two poly-switches available for
+ \texttt{verbatim} code blocks: environments (\vref{lst:verbatimEnvironments}),
+ commands (\vref{lst:verbatimCommands}) and \texttt{specialBeginEnd} (\vref{lst:special-verb1-yaml}).
+
+ \clearpage
+ \begin{longtable}{llll}
+ \caption{Poly-switch mappings for all code-block types}\label{tab:poly-switch-mapping} \\
+ \toprule
+ Code block & Sample & \multicolumn{2}{c}{Poly-switch mapping} \\
+ \midrule
+ environment & \verb!before words!$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & BeginStartsOnOwnLine \\
+ & \verb!\begin{myenv}!$\BodyStartsOnOwnLine$ & $\BodyStartsOnOwnLine$ & BodyStartsOnOwnLine \\
+ & \verb!body of myenv!$\EndStartsOnOwnLine$ & $\EndStartsOnOwnLine$ & EndStartsOnOwnLine \\
+ & \verb!\end{myenv}!$\EndFinishesWithLineBreak$ & $\EndFinishesWithLineBreak$ & EndFinishesWithLineBreak \\
+ & \verb!after words! & & \\
+ \cmidrule{2-4}
+ ifelsefi & \verb!before words!$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & IfStartsOnOwnLine \\
+ & \verb!\if...!$\BodyStartsOnOwnLine$ & $\BodyStartsOnOwnLine$ & BodyStartsOnOwnLine \\
+ & \verb!body of if/or statement!$\OrStartsOnOwnLine$ & $\OrStartsOnOwnLine$ & OrStartsOnOwnLine %
+ \announce{2018-04-27}{new ifElseFi code block poly-switches} \\
+ & \verb!\or!$\OrFinishesWithLineBreak$ & $\OrFinishesWithLineBreak$ & OrFinishesWithLineBreak \\
+ & \verb!body of if/or statement!$\ElseStartsOnOwnLine$ & $\ElseStartsOnOwnLine$ & ElseStartsOnOwnLine \\
+ & \verb!\else!$\ElseFinishesWithLineBreak$ & $\ElseFinishesWithLineBreak$ & ElseFinishesWithLineBreak \\
+ & \verb!body of else statement!$\EndStartsOnOwnLine$ & $\EndStartsOnOwnLine$ & FiStartsOnOwnLine \\
+ & \verb!\fi!$\EndFinishesWithLineBreak$ & $\EndFinishesWithLineBreak$ & FiFinishesWithLineBreak \\
+ & \verb!after words! & & \\
+ \cmidrule{2-4}
+ optionalArguments & \verb!...!$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & LSqBStartsOnOwnLine\footnote{LSqB stands for Left Square Bracket} \\
+ & \verb![!$\BodyStartsOnOwnLine$ & $\BodyStartsOnOwnLine$ & OptArgBodyStartsOnOwnLine \\
+ \announce*{2019-07-13}{new comma-related poly-switches} & \verb!value before comma!$\ElseStartsOnOwnLine$, & $\ElseStartsOnOwnLine$ & CommaStartsOnOwnLine \\
+ & $\ElseFinishesWithLineBreak$ & $\ElseFinishesWithLineBreak$ & CommaFinishesWithLineBreak \\
+ & \verb!end of body of opt arg!$\EndStartsOnOwnLine$ & $\EndStartsOnOwnLine$ & RSqBStartsOnOwnLine \\
+ & \verb!]!$\EndFinishesWithLineBreak$ & $\EndFinishesWithLineBreak$ & RSqBFinishesWithLineBreak \\
+ & \verb!...! & & \\
+ \cmidrule{2-4}
+ mandatoryArguments & \verb!...!$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & LCuBStartsOnOwnLine\footnote{LCuB stands for Left Curly Brace} \\
+ & \verb!{!$\BodyStartsOnOwnLine$ & $\BodyStartsOnOwnLine$ & MandArgBodyStartsOnOwnLine \\
+ \announce*{2019-07-13}{new comma-related poly-switches} & \verb!value before comma!$\ElseStartsOnOwnLine$, & $\ElseStartsOnOwnLine$ & CommaStartsOnOwnLine \\
+ & $\ElseFinishesWithLineBreak$ & $\ElseFinishesWithLineBreak$ & CommaFinishesWithLineBreak \\
+ & \verb!end of body of mand arg!$\EndStartsOnOwnLine$ & $\EndStartsOnOwnLine$ & RCuBStartsOnOwnLine \\
+ & \verb!}!$\EndFinishesWithLineBreak$ & $\EndFinishesWithLineBreak$ & RCuBFinishesWithLineBreak \\
+ & \verb!...! & & \\
+ \cmidrule{2-4}
+ commands & \verb!before words!$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & CommandStartsOnOwnLine \\
+ & \verb!\mycommand!$\BodyStartsOnOwnLine$ & $\BodyStartsOnOwnLine$ & CommandNameFinishesWithLineBreak \\
+ & $\langle$\itshape{arguments}$\rangle$ & & \\
+ \cmidrule{2-4}
+ namedGroupingBraces Brackets & before words$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & NameStartsOnOwnLine \\
+ & myname$\BodyStartsOnOwnLine$ & $\BodyStartsOnOwnLine$ & NameFinishesWithLineBreak \\
+ & $\langle$\itshape{braces/brackets}$\rangle$ & & \\
+ \cmidrule{2-4}
+ keyEqualsValuesBraces\newline Brackets & before words$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & KeyStartsOnOwnLine \\
+ & key$\EqualsStartsOnOwnLine$=$\BodyStartsOnOwnLine$ & $\EqualsStartsOnOwnLine$ & EqualsStartsOnOwnLine \\
+ & $\langle$\itshape{braces/brackets}$\rangle$ & $\BodyStartsOnOwnLine$ & EqualsFinishesWithLineBreak \\
+ \cmidrule{2-4}
+ items & before words$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & ItemStartsOnOwnLine \\
+ & \verb!\item!$\BodyStartsOnOwnLine$ & $\BodyStartsOnOwnLine$ & ItemFinishesWithLineBreak \\
+ & \verb!...! & & \\
+ \cmidrule{2-4}
+ specialBeginEnd & before words$\BeginStartsOnOwnLine$ & $\BeginStartsOnOwnLine$ & SpecialBeginStartsOnOwnLine \\
+ & \verb!\[!$\BodyStartsOnOwnLine$ & $\BodyStartsOnOwnLine$ & SpecialBodyStartsOnOwnLine \\
+ & \verb!body of special/middle!$\ElseStartsOnOwnLine$ & $\ElseStartsOnOwnLine$ & SpecialMiddleStartsOnOwnLine %
+ \announce{2018-04-27}{new special code block poly-switches} \\
+ & \verb!\middle!$\ElseFinishesWithLineBreak$ & $\ElseFinishesWithLineBreak$ & SpecialMiddleFinishesWithLineBreak \\
+ & body of special/middle $\EndStartsOnOwnLine$ & $\EndStartsOnOwnLine$ & SpecialEndStartsOnOwnLine \\
+ & \verb!\]!$\EndFinishesWithLineBreak$ & $\EndFinishesWithLineBreak$ & SpecialEndFinishesWithLineBreak \\
+ & after words & & \\
+ \cmidrule{2-4}
+ verbatim & before words$\BeginStartsOnOwnLine$\verb!\begin{verbatim}! & $\BeginStartsOnOwnLine$ & VerbatimBeginStartsOnOwnLine \\
+ \announce{2019-05-05}{verbatim poly-switches} & body of verbatim \verb!\end{verbatim}!$\EndFinishesWithLineBreak$ & $\EndFinishesWithLineBreak$ & VerbatimEndFinishesWithLineBreak \\
+ & after words & & \\
+ \bottomrule
+ \end{longtable}
diff --git a/support/latexindent/documentation/subsec-commands-and-their-options.tex b/support/latexindent/documentation/subsec-commands-and-their-options.tex
new file mode 100644
index 0000000000..a1184bf3a5
--- /dev/null
+++ b/support/latexindent/documentation/subsec-commands-and-their-options.tex
@@ -0,0 +1,245 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsection{Commands and the strings between their arguments}\label{subsec:commands-string-between}
+ The \texttt{command} code blocks will always look for optional (square bracketed)
+ and mandatory (curly braced) arguments which can contain comments, line breaks and
+ `beamer' commands \lstinline!<.*?>! between them. There are switches that can allow
+ them to contain other strings, which we discuss next.
+
+\yamltitle{commandCodeBlocks}*{fields}
+
+ The \texttt{commandCodeBlocks} field%
+ \announce{2018-04-27}*{commandCodeBlocks}
+ contains a few switches detailed in \cref{lst:commandCodeBlocks}.
+
+ \cmhlistingsfromfile[style=commandCodeBlocks]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{commandCodeBlocks}}{lst:commandCodeBlocks}
+
+\yamltitle{roundParenthesesAllowed}{0|1}
+
+ The need for this field was mostly motivated by commands found in code used to generate
+ images in \texttt{PSTricks} and \texttt{tikz}; for example, let's consider
+ the code given in \cref{lst:pstricks1}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/pstricks1.tex}{\texttt{pstricks1.tex}}{lst:pstricks1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/pstricks1-default.tex}{\texttt{pstricks1} default output}{lst:pstricks1-default}
+ \end{minipage}
+
+ Notice that the \lstinline!\defFunction! command has an optional argument, followed by a
+ mandatory argument, followed by a round-parenthesis argument, $(u,v)$.
+
+ By default, because \texttt{roundParenthesesAllowed} is set to $1$ in
+ \cref{lst:commandCodeBlocks}, then \texttt{latexindent.pl} will allow round parenthesis between
+ optional and mandatory arguments. In the case of the code in \cref{lst:pstricks1},
+ \texttt{latexindent.pl} finds \emph{all} the arguments of
+ \lstinline!defFunction!, both before and after \lstinline!(u,v)!.
+
+ The default output from running \texttt{latexindent.pl} on \cref{lst:pstricks1} actually
+ leaves it unchanged (see \cref{lst:pstricks1-default}); note in particular, this is because of
+ \texttt{noAdditionalIndentGlobal} as discussed on \cpageref{page:command:noAddGlobal}.
+
+ Upon using the YAML settings in \cref{lst:noRoundParentheses}, and running the command
+ \begin{commandshell}
+latexindent.pl pstricks1.tex -l noRoundParentheses.yaml
+\end{commandshell}
+ we obtain the output given in \cref{lst:pstricks1-nrp}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/pstricks1-nrp.tex}{\texttt{pstricks1.tex} using \cref{lst:noRoundParentheses}}{lst:pstricks1-nrp}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/noRoundParentheses.yaml}[yaml-TCB]{\texttt{noRoundParentheses.yaml}}{lst:noRoundParentheses}
+ \end{cmhtcbraster}
+
+ Notice the difference between \cref{lst:pstricks1-default} and \cref{lst:pstricks1-nrp}; in
+ particular, in \cref{lst:pstricks1-nrp}, because round parentheses are
+ \emph{not} allowed, \texttt{latexindent.pl} finds that the
+ \lstinline!\defFunction! command finishes at the first opening round parenthesis. As such,
+ the remaining braced, mandatory, arguments are found to be \texttt{UnNamedGroupingBracesBrackets} (see \vref{tab:code-blocks}) which,
+ by default, assume indentation for their body, and hence the tabbed indentation in
+ \cref{lst:pstricks1-nrp}.
+
+ Let's explore this using the YAML given in \cref{lst:defFunction} and run the command
+ \begin{commandshell}
+latexindent.pl pstricks1.tex -l defFunction.yaml
+\end{commandshell}
+ then the output is as in \cref{lst:pstricks1-indent-rules}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/pstricks1-indent-rules.tex}{\texttt{pstricks1.tex} using \cref{lst:defFunction}}{lst:pstricks1-indent-rules}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/defFunction.yaml}[yaml-TCB]{\texttt{defFunction.yaml}}{lst:defFunction}
+ \end{cmhtcbraster}
+
+ Notice in \cref{lst:pstricks1-indent-rules} that the \emph{body} of the
+ \lstinline!defFunction! command i.e, the subsequent lines containing arguments after the
+ command name, have received the single space of indentation specified by
+ \cref{lst:defFunction}.
+
+\yamltitle{stringsAllowedBetweenArguments}*{fields}
+ \texttt{tikz} users may well specify code such as that given in
+ \cref{lst:tikz-node1}; processing this code using
+ \texttt{latexindent.pl} gives the default output in \cref{lst:tikz-node1-default}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[columns=fixed]*{demonstrations/tikz-node1.tex}{\texttt{tikz-node1.tex}}{lst:tikz-node1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[columns=fixed]*{demonstrations/tikz-node1-default.tex}{\texttt{tikz-node1} default output}{lst:tikz-node1-default}
+ \end{minipage}
+
+ With reference to \vref{lst:commandCodeBlocks}, we see that the strings
+ \begin{quote}
+ to, node, ++
+ \end{quote}
+ are all allowed to appear between arguments; importantly, you are encouraged to add
+ further names to this field as necessary. This means that when \texttt{latexindent.pl}
+ processes \cref{lst:tikz-node1}, it consumes:
+ \begin{itemize}
+ \item the optional argument \lstinline![thin]!
+ \item the round-bracketed argument \lstinline!(c)! because \texttt{roundParenthesesAllowed} is
+ $1$ by default
+ \item the string \lstinline!to! (specified in \texttt{stringsAllowedBetweenArguments})
+ \item the optional argument \lstinline![in=110,out=-90]!
+ \item the string \lstinline!++! (specified in \texttt{stringsAllowedBetweenArguments})
+ \item the round-bracketed argument \lstinline!(0,-0.5cm)! because \texttt{roundParenthesesAllowed} is
+ $1$ by default
+ \item the string \lstinline!node! (specified in \texttt{stringsAllowedBetweenArguments})
+ \item the optional argument \lstinline![below,align=left,scale=0.5]!
+ \end{itemize}
+
+ We can explore this further, for example using \cref{lst:draw} and running the
+ command
+ \begin{commandshell}
+latexindent.pl tikz-node1.tex -l draw.yaml
+\end{commandshell}
+ we receive the output given in \cref{lst:tikz-node1-draw}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/tikz-node1-draw.tex}{\texttt{tikz-node1.tex} using \cref{lst:draw}}{lst:tikz-node1-draw}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/draw.yaml}[yaml-TCB]{\texttt{draw.yaml}}{lst:draw}
+ \end{cmhtcbraster}
+
+ Notice that each line after the \lstinline!\draw! command (its `body') in
+ \cref{lst:tikz-node1-draw} has been given the appropriate two-spaces worth of indentation
+ specified in \cref{lst:draw}.
+
+ Let's compare this with the output from using the YAML settings in
+ \cref{lst:no-strings}, and running the command
+ \begin{commandshell}
+latexindent.pl tikz-node1.tex -l no-strings.yaml
+\end{commandshell}
+ given in \cref{lst:tikz-node1-no-strings}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/tikz-node1-no-strings.tex}{\texttt{tikz-node1.tex} using \cref{lst:no-strings}}{lst:tikz-node1-no-strings}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/no-strings.yaml}[yaml-TCB]{\texttt{no-strings.yaml}}{lst:no-strings}
+ \end{cmhtcbraster}
+
+ In this case, \texttt{latexindent.pl} sees that:
+ \begin{itemize}
+ \item the \lstinline!\draw! command finishes after the \lstinline!(c)!, as
+ \texttt{stringsAllowedBetweenArguments} has been set to $0$ so there are no strings
+ allowed between arguments;
+ \item it finds a \texttt{namedGroupingBracesBrackets} called \texttt{to} (see \vref{tab:code-blocks}) \emph{with}
+ argument \lstinline![in=110,out=-90]!
+ \item it finds another \texttt{namedGroupingBracesBrackets} but this time called \texttt{node} with
+ argument \lstinline![below,align=left,scale=0.5]!
+ \end{itemize}
+
+ Referencing \vref{lst:commandCodeBlocks},%
+ \announce{2018-04-27}*{amalgamate feature in commandCodeBlocks}, we see that the first field in the \texttt{stringsAllowedBetweenArguments} is
+ \texttt{amalgamate} and is set to \texttt{1} by default. This is for
+ users who wish to specify their settings in multiple YAML files. For example, by using
+ the settings in either \cref{lst:amalgamate-demo} or\cref{lst:amalgamate-demo1} is equivalent to
+ using the settings in \cref{lst:amalgamate-demo2}.
+
+ \begin{cmhtcbraster}[raster columns=3,
+ raster left skip=-3.5cm,
+ raster right skip=-2cm,
+ raster column skip=.03\linewidth]
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/amalgamate-demo.yaml}[yaml-TCB]{\texttt{amalgamate-demo.yaml}}{lst:amalgamate-demo}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/amalgamate-demo1.yaml}[yaml-TCB]{\texttt{amalgamate-demo1.yaml}}{lst:amalgamate-demo1}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/amalgamate-demo2.yaml}[yaml-TCB]{\texttt{amalgamate-demo2.yaml}}{lst:amalgamate-demo2}
+ \end{cmhtcbraster}
+
+ We specify \texttt{amalgamate} to be set to \texttt{0} and in which case
+ any settings loaded prior to those specified, including the default, will be overwritten.
+ For example, using the settings in \cref{lst:amalgamate-demo3} means that only the strings
+ specified in that field will be used.
+
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/amalgamate-demo3.yaml}[yaml-TCB]{\texttt{amalgamate-demo3.yaml}}{lst:amalgamate-demo3}
+
+ It is important to note that the \texttt{amalgamate} field, if used, must be in the
+ first field, and specified using the syntax given in \cref{lst:amalgamate-demo1,lst:amalgamate-demo2,lst:amalgamate-demo3}.
+
+ We may explore this feature further with the code in \cref{lst:for-each}, whose
+ default output is given in \cref{lst:for-each-default}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/for-each.tex}{\texttt{for-each.tex}}{lst:for-each}
+ \cmhlistingsfromfile{demonstrations/for-each-default.tex}{\texttt{for-each} default output}{lst:for-each-default}
+ \end{cmhtcbraster}
+
+ Let's compare this with the output from using the YAML settings in
+ \cref{lst:foreach}, and running the command
+ \begin{commandshell}
+latexindent.pl for-each.tex -l foreach.yaml
+\end{commandshell}
+ given in \cref{lst:for-each-mod1}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/for-each-mod1.tex}{\texttt{for-each.tex} using \cref{lst:foreach}}{lst:for-each-mod1}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/foreach.yaml}[yaml-TCB]{\texttt{foreach.yaml}}{lst:foreach}
+ \end{cmhtcbraster}
+
+ You might like to compare the output given in \cref{lst:for-each-default} and
+ \cref{lst:for-each-mod1}. Note,in particular, in \cref{lst:for-each-default} that the
+ \texttt{foreach} command has not included any of the subsequent strings, and that
+ the braces have been treated as a \texttt{namedGroupingBracesBrackets}. In \cref{lst:for-each-mod1} the
+ \texttt{foreach} command has been allowed to have \lstinline!\x/\y! and
+ \texttt{in} between arguments because of the settings given in
+ \cref{lst:foreach}.
+
+\yamltitle{commandNameSpecial}*{fields}
+ There are some special command names%
+ \announce{2018-04-27}*{commandNameSpecial} that do not fit within the names recognised by
+ \texttt{latexindent.pl}, the first one of which is \lstinline!\@ifnextchar[!. From the
+ perspective of \texttt{latexindent.pl}, the whole of the text \lstinline!\@ifnextchar[! is
+ a command, because it is immediately followed by sets of mandatory arguments. However,
+ without the \texttt{commandNameSpecial} field, \texttt{latexindent.pl} would not be able to
+ label it as such, because the \lstinline![! is, necessarily, not matched by a
+ closing \lstinline!]!.
+
+ For example, consider the sample file in \cref{lst:ifnextchar}, which has default
+ output in \cref{lst:ifnextchar-default}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/ifnextchar.tex}{\texttt{ifnextchar.tex}}{lst:ifnextchar}
+ \cmhlistingsfromfile{demonstrations/ifnextchar-default.tex}{\texttt{ifnextchar.tex} default output}{lst:ifnextchar-default}
+ \end{cmhtcbraster}
+
+ Notice that in \cref{lst:ifnextchar-default} the \texttt{parbox} command has been able
+ to indent its body, because \texttt{latexindent.pl} has successfully found the command
+ \lstinline!\@ifnextchar! first; the pattern-matching of \texttt{latexindent.pl} starts
+ from \emph{the inner most <thing> and works outwards}, discussed in more detail on \cpageref{page:phases}.
+
+ For demonstration, we can compare this output with that given in \cref{lst:ifnextchar-off}
+ in which the settings from \cref{lst:no-ifnextchar} have dictated that no special command
+ names, including the \lstinline!\@ifnextchar[! command, should not be searched for
+ specially; as such, the \texttt{parbox} command has been \emph{unable}
+ to indent its body successfully, because the \lstinline!\@ifnextchar[! command has not been
+ found.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/ifnextchar-off.tex}{\texttt{ifnextchar.tex} using \cref{lst:no-ifnextchar}}{lst:ifnextchar-off}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/no-ifnextchar.yaml}[yaml-TCB]{\texttt{no-ifnextchar.yaml}}{lst:no-ifnextchar}
+ \end{cmhtcbraster}
+
+ The \texttt{amalgamate} field can be used for \texttt{commandNameSpecial}, just as for
+ \texttt{stringsAllowedBetweenArguments}. The same condition holds as stated previously, which we state
+ again here:
+ \begin{warning}
+ It is important to note that the \texttt{amalgamate} field, if used, in either \texttt{commandNameSpecial} or \texttt{stringsAllowedBetweenArguments} must be in the first field,
+ and specified using the syntax given in \cref{lst:amalgamate-demo1,lst:amalgamate-demo2,lst:amalgamate-demo3}.
+ \end{warning}
diff --git a/support/latexindent/documentation/subsec-conflicting-poly-switches.tex b/support/latexindent/documentation/subsec-conflicting-poly-switches.tex
new file mode 100644
index 0000000000..25ebe3efaa
--- /dev/null
+++ b/support/latexindent/documentation/subsec-conflicting-poly-switches.tex
@@ -0,0 +1,160 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsection{Conflicting poly-switches: sequential code blocks}
+ It is very easy to have conflicting poly-switches; if we use the example from
+ \vref{lst:mycommand1}, and consider the YAML settings given in \cref{lst:mycom-mlb4}.
+ The output from running
+ \begin{commandshell}
+latexindent.pl -m -l=mycom-mlb4.yaml mycommand1.tex
+\end{commandshell}
+ is given in \cref{lst:mycom-mlb4}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/mycommand1-mlb4.tex}{\texttt{mycommand1.tex} using \cref{lst:mycom-mlb4}}{lst:mycommand1-mlb4}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycom-mlb4.yaml}[MLB-TCB,width=\linewidth]{\texttt{mycom-mlb4.yaml}}{lst:mycom-mlb4}
+ \end{cmhtcbraster}
+
+ Studying \cref{lst:mycom-mlb4}, we see that the two poly-switches are at opposition with
+ one another:
+ \begin{itemize}
+ \item on the one hand, \texttt{LCuBStartsOnOwnLine} should \emph{not} start on its own line
+ (as poly-switch is set to $-1$);
+ \item on the other hand, \texttt{RCuBFinishesWithLineBreak} \emph{should} finish with a line break.
+ \end{itemize}
+ So, which should win the conflict? As demonstrated in \cref{lst:mycommand1-mlb4}, it is clear
+ that \texttt{LCuBStartsOnOwnLine} won this conflict, and the reason is that
+ \emph{the second argument was processed after the first} -- in general, the most recently-processed code block and
+ associated poly-switch takes priority.
+
+ We can explore this further by considering the YAML settings in \cref{lst:mycom-mlb5};
+ upon running the command
+ \begin{commandshell}
+latexindent.pl -m -l=mycom-mlb5.yaml mycommand1.tex
+\end{commandshell}
+ we obtain the output given in \cref{lst:mycommand1-mlb5}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/mycommand1-mlb5.tex}{\texttt{mycommand1.tex} using \cref{lst:mycom-mlb5}}{lst:mycommand1-mlb5}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycom-mlb5.yaml}[MLB-TCB,width=\linewidth]{\texttt{mycom-mlb5.yaml}}{lst:mycom-mlb5}
+ \end{cmhtcbraster}
+
+ As previously, the most-recently-processed code block takes priority -- as before, the
+ second (i.e, \emph{last}) argument. Exploring this further, we consider the
+ YAML settings in \cref{lst:mycom-mlb6}, which give associated output in
+ \cref{lst:mycommand1-mlb6}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/mycommand1-mlb6.tex}{\texttt{mycommand1.tex} using \cref{lst:mycom-mlb6}}{lst:mycommand1-mlb6}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycom-mlb6.yaml}[MLB-TCB,width=\linewidth]{\texttt{mycom-mlb6.yaml}}{lst:mycom-mlb6}
+ \end{cmhtcbraster}
+
+ Note that a \lstinline!%! \emph{has} been added to the trailing
+ first \lstinline!}!; this is because:
+ \begin{itemize}
+ \item while processing the \emph{first} argument, the trailing line break has been
+ removed (\texttt{RCuBFinishesWithLineBreak} set to $-1$);
+ \item while processing the \emph{second} argument, \texttt{latexindent.pl} finds that
+ it does \emph{not} begin on its own line, and so because
+ \texttt{LCuBStartsOnOwnLine} is set to $2$, it adds a comment, followed by a
+ line break.
+ \end{itemize}
+
+\subsection{Conflicting poly-switches: nested code blocks}
+ Now let's consider an example when nested code blocks have conflicting poly-switches;
+ we'll use the code in \cref{lst:nested-env}, noting that it contains nested
+ environments.
+
+ \cmhlistingsfromfile{demonstrations/nested-env.tex}{\texttt{nested-env.tex}}{lst:nested-env}
+
+ Let's use the YAML settings given in \cref{lst:nested-env-mlb1-yaml}, which upon running the
+ command
+ \begin{commandshell}
+latexindent.pl -m -l=nested-env-mlb1.yaml nested-env.tex
+\end{commandshell}
+ gives the output in \cref{lst:nested-env-mlb1}.
+
+ \begin{cmhtcbraster}[raster column skip=.05\linewidth]
+ \cmhlistingsfromfile{demonstrations/nested-env-mlb1.tex}{\texttt{nested-env.tex} using \cref{lst:nested-env-mlb1-yaml}}{lst:nested-env-mlb1}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/nested-env-mlb1.yaml}[MLB-TCB,width=\linewidth]{\texttt{nested-env-mlb1.yaml}}{lst:nested-env-mlb1-yaml}
+ \end{cmhtcbraster}
+
+ In \cref{lst:nested-env-mlb1}, let's first of all note that both environments have received
+ the appropriate (default) indentation; secondly, note that the poly-switch
+ \texttt{EndStartsOnOwnLine} appears to have won the conflict, as \lstinline!\end{one}! has
+ had its leading line break removed.
+
+ To understand it, let's talk about the three basic phases \label{page:phases}of
+ \texttt{latexindent.pl}:
+ \begin{enumerate}
+ \item Phase 1: packing, in which code blocks are replaced with unique ids, working from
+ \emph{the inside to the outside}, and then sequentially -- for example, in \cref{lst:nested-env},
+ the \texttt{two} environment is found \emph{before} the
+ \texttt{one} environment; if the -m switch is active, then during this phase:
+ \begin{itemize}
+ \item line breaks at the beginning of the \texttt{body} can be added (if
+ \texttt{BodyStartsOnOwnLine} is $1$ or $2$) or removed (if
+ \texttt{BodyStartsOnOwnLine} is $-1$);
+ \item line breaks at the end of the body can be added (if \texttt{EndStartsOnOwnLine} is
+ $1$ or $2$) or removed (if \texttt{EndStartsOnOwnLine} is
+ $-1$);
+ \item line breaks after the end statement can be added (if \texttt{EndFinishesWithLineBreak} is
+ $1$ or $2$).
+ \end{itemize}
+ \item Phase 2: indentation, in which white space is added to the begin, body, and end
+ statements;
+ \item Phase 3: unpacking, in which unique ids are replaced by their \emph{indented} code
+ blocks; if the -m switch is active, then during this phase,
+ \begin{itemize}
+ \item line breaks before \texttt{begin} statements can be added or removed (depending
+ upon \texttt{BeginStartsOnOwnLine});
+ \item line breaks after \emph{end} statements can be removed but
+ \emph{NOT} added (see \texttt{EndFinishesWithLineBreak}).
+ \end{itemize}
+ \end{enumerate}
+
+ With reference to \cref{lst:nested-env-mlb1}, this means that during Phase 1:
+ \begin{itemize}
+ \item the \texttt{two} environment is found first, and the line break ahead of the
+ \lstinline!\end{two}! statement is removed because \texttt{EndStartsOnOwnLine} is set to
+ $-1$. Importantly, because, \emph{at this stage},
+ \lstinline!\end{two}! \emph{does} finish with a line break,
+ \texttt{EndFinishesWithLineBreak} causes no action.
+ \item next, the \texttt{one} environment is found; the line break ahead of
+ \lstinline!\end{one}! is removed because \texttt{EndStartsOnOwnLine} is set to
+ $-1$.
+ \end{itemize}
+ The indentation is done in Phase 2; in Phase 3 \emph{there is no option to add a line break after the \lstinline!end! statements}. We can justify
+ this by remembering that during Phase 3, the \texttt{one} environment will be
+ found and processed first, followed by the \texttt{two} environment. If the
+ \texttt{two} environment were to add a line break after the
+ \lstinline!\end{two}! statement, then \texttt{latexindent.pl} would have no way of
+ knowing how much indentation to add to the subsequent text (in this case,
+ \lstinline!\end{one}!).
+
+ We can explore this further using the poly-switches in \cref{lst:nested-env-mlb2}; upon
+ running the command
+ \begin{commandshell}
+latexindent.pl -m -l=nested-env-mlb2.yaml nested-env.tex
+\end{commandshell}
+ we obtain the output given in \cref{lst:nested-env-mlb2-output}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/nested-env-mlb2.tex}{\texttt{nested-env.tex} using \cref{lst:nested-env-mlb2}}{lst:nested-env-mlb2-output}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/nested-env-mlb2.yaml}[MLB-TCB,width=\linewidth]{\texttt{nested-env-mlb2.yaml}}{lst:nested-env-mlb2}
+ \end{cmhtcbraster}
+
+ During Phase 1:
+ \begin{itemize}
+ \item the \texttt{two} environment is found first, and the line break ahead of the
+ \lstinline!\end{two}! statement is not changed because \texttt{EndStartsOnOwnLine} is set to
+ $1$. Importantly, because, \emph{at this stage},
+ \lstinline!\end{two}! \emph{does} finish with a line break,
+ \texttt{EndFinishesWithLineBreak} causes no action.
+ \item next, the \texttt{one} environment is found; the line break ahead of
+ \lstinline!\end{one}! is already present, and no action is needed.
+ \end{itemize}
+ The indentation is done in Phase 2, and then in Phase 3, the \texttt{one}
+ environment is found and processed first, followed by the \texttt{two}
+ environment. \emph{At this stage}, the \texttt{two} environment finds
+ \texttt{EndFinishesWithLineBreak} is $-1$, so it removes the trailing line break;
+ remember, at this point, \texttt{latexindent.pl} has completely finished with the
+ \texttt{one} environment.
diff --git a/support/latexindent/documentation/subsec-noAdditionalIndent-indentRules.tex b/support/latexindent/documentation/subsec-noAdditionalIndent-indentRules.tex
new file mode 100644
index 0000000000..53fd835392
--- /dev/null
+++ b/support/latexindent/documentation/subsec-noAdditionalIndent-indentRules.tex
@@ -0,0 +1,27 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsection{noAdditionalIndent and indentRules}\label{sec:noadd-indent-rules}
+ \texttt{latexindent.pl} operates on files by looking for code blocks, as detailed in
+ \vref{subsubsec:code-blocks};
+ for each type of code block in \vref{tab:code-blocks} (which we will call a \emph{$\langle$thing$\rangle$} in what follows) it searches YAML fields for
+ information in the following order:
+ \begin{enumerate}
+ \item \texttt{noAdditionalIndent} for the \emph{name} of the current \emph{$\langle$thing$\rangle$};
+ \item \texttt{indentRules} for the \emph{name} of the current \emph{$\langle$thing$\rangle$};
+ \item \texttt{noAdditionalIndentGlobal} for the \emph{type} of the current \emph{$\langle$thing$\rangle$};
+ \item \texttt{indentRulesGlobal} for the \emph{type} of the current
+ \emph{$\langle$thing$\rangle$}.
+ \end{enumerate}
+
+ Using the above list, the first piece of information to be found will be used; failing
+ that, the value of \texttt{defaultIndent} is used. If information is found in multiple
+ fields, the first one according to the list above will be used; for example, if
+ information is present in both \texttt{indentRules} and in \texttt{noAdditionalIndentGlobal}, then
+ the information from \texttt{indentRules} takes priority.
+
+ We now present details for the different type of code blocks known to
+ \texttt{latexindent.pl}, as detailed in \vref{tab:code-blocks}; for reference, there
+ follows a list of the code blocks covered.
+
+ \startcontents[noAdditionalIndent]
+ \printcontents[noAdditionalIndent]{}{0}{}
diff --git a/support/latexindent/documentation/subsec-partnering-poly-switches.tex b/support/latexindent/documentation/subsec-partnering-poly-switches.tex
new file mode 100644
index 0000000000..03337669ef
--- /dev/null
+++ b/support/latexindent/documentation/subsec-partnering-poly-switches.tex
@@ -0,0 +1,51 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsection{Partnering BodyStartsOnOwnLine with argument-based poly-switches}
+ Some poly-switches need to be partnered together; in particular, when line breaks
+ involving the \emph{first} argument of a code block need to be accounted for
+ using both \texttt{BodyStartsOnOwnLine} (or its equivalent, see \vref{tab:poly-switch-mapping}) and \texttt{LCuBStartsOnOwnLine} for mandatory arguments, and
+ \texttt{LSqBStartsOnOwnLine} for optional arguments.
+
+ Let's begin with the code in \cref{lst:mycommand1} and the YAML settings in
+ \cref{lst:mycom-mlb1}; with reference to \vref{tab:poly-switch-mapping}, the key
+ \texttt{CommandNameFinishesWithLineBreak} is an alias for \texttt{BodyStartsOnOwnLine}.
+
+ \cmhlistingsfromfile{demonstrations/mycommand1.tex}{\texttt{mycommand1.tex}}{lst:mycommand1}
+
+ Upon running the command
+ \begin{commandshell}
+latexindent.pl -m -l=mycom-mlb1.yaml mycommand1.tex
+\end{commandshell}
+ we obtain \cref{lst:mycommand1-mlb1}; note that the \emph{second} mandatory argument
+ beginning brace \lstinline!{! has had its leading line break removed, but that
+ the \emph{first} brace has not.
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=-1cm},
+ ]
+ \cmhlistingsfromfile{demonstrations/mycommand1-mlb1.tex}{\texttt{mycommand1.tex} using \cref{lst:mycom-mlb1}}{lst:mycommand1-mlb1}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycom-mlb1.yaml}[MLB-TCB,width=.6\textwidth]{\texttt{mycom-mlb1.yaml}}{lst:mycom-mlb1}
+ \end{cmhtcbraster}
+
+ Now let's change the YAML file so that it is as in \cref{lst:mycom-mlb2}; upon running
+ the analogous command to that given above, we obtain \cref{lst:mycommand1-mlb2}; both
+ beginning braces \lstinline!{! have had their leading line breaks removed.
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=-1cm},
+ ]
+ \cmhlistingsfromfile{demonstrations/mycommand1-mlb2.tex}{\texttt{mycommand1.tex} using \cref{lst:mycom-mlb2}}{lst:mycommand1-mlb2}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycom-mlb2.yaml}[MLB-TCB,width=.6\textwidth]{\texttt{mycom-mlb2.yaml}}{lst:mycom-mlb2}
+ \end{cmhtcbraster}
+
+ Now let's change the YAML file so that it is as in \cref{lst:mycom-mlb3}; upon running
+ the analogous command to that given above, we obtain \cref{lst:mycommand1-mlb3}.
+
+ \begin{cmhtcbraster}[
+ raster force size=false,
+ raster column 1/.style={add to width=-1cm},
+ ]
+ \cmhlistingsfromfile{demonstrations/mycommand1-mlb3.tex}{\texttt{mycommand1.tex} using \cref{lst:mycom-mlb3}}{lst:mycommand1-mlb3}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycom-mlb3.yaml}[MLB-TCB,width=.6\textwidth]{\texttt{mycom-mlb3.yaml}}{lst:mycom-mlb3}
+ \end{cmhtcbraster}
diff --git a/support/latexindent/documentation/subsubsec-commands-with-arguments.tex b/support/latexindent/documentation/subsubsec-commands-with-arguments.tex
new file mode 100644
index 0000000000..84bff810a1
--- /dev/null
+++ b/support/latexindent/documentation/subsubsec-commands-with-arguments.tex
@@ -0,0 +1,104 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsubsection{Commands with arguments}\label{subsubsec:commands-arguments}
+ Let's begin with the simple example in \cref{lst:mycommand}; when
+ \texttt{latexindent.pl} operates on this file, the default output is shown in
+ \cref{lst:mycommand-default}. \footnote{The command code blocks
+ have quite a few subtleties, described in \vref{subsec:commands-string-between}.}
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/mycommand.tex}{\texttt{mycommand.tex}}{lst:mycommand}
+ \cmhlistingsfromfile{demonstrations/mycommand-default.tex}{\texttt{mycommand.tex} default output}{lst:mycommand-default}
+ \end{cmhtcbraster}
+
+ As in the environment-based case (see \vref{lst:myenv-noAdd1,lst:myenv-noAdd2}) we may specify
+ \texttt{noAdditionalIndent} either in `scalar' form, or in `field' form, as shown in
+ \cref{lst:mycommand-noAdd1,lst:mycommand-noAdd2}
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycommand-noAdd1.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{mycommand-noAdd1.yaml}}{lst:mycommand-noAdd1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycommand-noAdd2.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{mycommand-noAdd2.yaml}}{lst:mycommand-noAdd2}
+ \end{minipage}
+
+ After running the following commands,
+ \begin{commandshell}
+latexindent.pl mycommand.tex -l mycommand-noAdd1.yaml
+latexindent.pl mycommand.tex -l mycommand-noAdd2.yaml
+\end{commandshell}
+ we receive the respective output given in \cref{lst:mycommand-output-noAdd1,lst:mycommand-output-noAdd2}
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/mycommand-noAdd1.tex}{\texttt{mycommand.tex} using \cref{lst:mycommand-noAdd1}}{lst:mycommand-output-noAdd1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/mycommand-noAdd2.tex}{\texttt{mycommand.tex} using \cref{lst:mycommand-noAdd2}}{lst:mycommand-output-noAdd2}
+ \end{minipage}
+
+ Note that in \cref{lst:mycommand-output-noAdd1} that the `body', optional argument
+ \emph{and} mandatory argument have \emph{all} received no
+ additional indentation, while in \cref{lst:mycommand-output-noAdd2}, only the `body' has not received
+ any additional indentation. We define the `body' of a command as any lines following the
+ command name that include its optional or mandatory arguments.
+
+ We may further customise \texttt{noAdditionalIndent} for \texttt{mycommand} as we did in
+ \vref{lst:myenv-noAdd5,lst:myenv-noAdd6}; explicit examples are given in \cref{lst:mycommand-noAdd3,lst:mycommand-noAdd4}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycommand-noAdd3.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{mycommand-noAdd3.yaml}}{lst:mycommand-noAdd3}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycommand-noAdd4.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{mycommand-noAdd4.yaml}}{lst:mycommand-noAdd4}
+ \end{minipage}
+
+ After running the following commands,
+ \begin{commandshell}
+latexindent.pl mycommand.tex -l mycommand-noAdd3.yaml
+latexindent.pl mycommand.tex -l mycommand-noAdd4.yaml
+\end{commandshell}
+ we receive the respective output given in \cref{lst:mycommand-output-noAdd3,lst:mycommand-output-noAdd4}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/mycommand-noAdd3.tex}{\texttt{mycommand.tex} using \cref{lst:mycommand-noAdd3}}{lst:mycommand-output-noAdd3}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/mycommand-noAdd4.tex}{\texttt{mycommand.tex} using \cref{lst:mycommand-noAdd4}}{lst:mycommand-output-noAdd4}
+ \end{minipage}
+
+ Attentive readers will note that the body of \texttt{mycommand} in both
+ \cref{lst:mycommand-output-noAdd3,lst:mycommand-output-noAdd4} has received no additional indent, even though
+ \texttt{body} is explicitly set to \texttt{0} in both
+ \cref{lst:mycommand-noAdd3,lst:mycommand-noAdd4}. This is because, by default, \texttt{noAdditionalIndentGlobal} for
+ \texttt{commands} is set to \texttt{1} by default; this can be easily
+ fixed as in \cref{lst:mycommand-noAdd5,lst:mycommand-noAdd6}.\label{page:command:noAddGlobal}
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycommand-noAdd5.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{mycommand-noAdd5.yaml}}{lst:mycommand-noAdd5}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mycommand-noAdd6.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{mycommand-noAdd6.yaml}}{lst:mycommand-noAdd6}
+ \end{minipage}
+
+ After running the following commands,
+ \begin{commandshell}
+latexindent.pl mycommand.tex -l mycommand-noAdd5.yaml
+latexindent.pl mycommand.tex -l mycommand-noAdd6.yaml
+\end{commandshell}
+ we receive the respective output given in \cref{lst:mycommand-output-noAdd5,lst:mycommand-output-noAdd6}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/mycommand-noAdd5.tex}{\texttt{mycommand.tex} using \cref{lst:mycommand-noAdd5}}{lst:mycommand-output-noAdd5}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/mycommand-noAdd6.tex}{\texttt{mycommand.tex} using \cref{lst:mycommand-noAdd6}}{lst:mycommand-output-noAdd6}
+ \end{minipage}
+
+ Both \texttt{indentRules} and \texttt{indentRulesGlobal} can be adjusted as they were for
+ \emph{environment} code blocks, as in \vref{lst:myenv-rules3,lst:myenv-rules4} and
+ \vref{lst:indentRulesGlobal:environments,lst:opt-args-indent-rules-glob,lst:mand-args-indent-rules-glob}.
diff --git a/support/latexindent/documentation/subsubsec-environments-and-their-arguments.tex b/support/latexindent/documentation/subsubsec-environments-and-their-arguments.tex
new file mode 100644
index 0000000000..a37e3eb0ed
--- /dev/null
+++ b/support/latexindent/documentation/subsubsec-environments-and-their-arguments.tex
@@ -0,0 +1,283 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsubsection{Environments and their arguments}\label{subsubsec:env-and-their-args}
+ There are a few different YAML switches governing the indentation of environments; let's
+ start with the code shown in \cref{lst:myenvtex}.
+
+ \cmhlistingsfromfile{demonstrations/myenvironment-simple.tex}{\texttt{myenv.tex}}{lst:myenvtex}
+
+\yamltitle{noAdditionalIndent}*{fields}
+ If we do not wish \texttt{myenv} to receive any additional indentation, we have a
+ few choices available to us, as demonstrated in \cref{lst:myenv-noAdd1,lst:myenv-noAdd2}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-noAdd1.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-noAdd1.yaml}}{lst:myenv-noAdd1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-noAdd2.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-noAdd2.yaml}}{lst:myenv-noAdd2}
+ \end{minipage}
+
+ On applying either of the following commands,
+ \begin{commandshell}
+latexindent.pl myenv.tex -l myenv-noAdd1.yaml
+latexindent.pl myenv.tex -l myenv-noAdd2.yaml
+\end{commandshell}
+ we obtain the output given in \cref{lst:myenv-output}; note in particular that the
+ environment \texttt{myenv} has not received any \emph{additional}
+ indentation, but that the \texttt{outer} environment \emph{has} still
+ received indentation.
+
+ \cmhlistingsfromfile{demonstrations/myenvironment-simple-noAdd-body1.tex}{\texttt{myenv.tex} output (using either \cref{lst:myenv-noAdd1} or \cref{lst:myenv-noAdd2})}{lst:myenv-output}
+
+ Upon changing the YAML files to those shown in \cref{lst:myenv-noAdd3,lst:myenv-noAdd4}, and running either
+ \begin{commandshell}
+latexindent.pl myenv.tex -l myenv-noAdd3.yaml
+latexindent.pl myenv.tex -l myenv-noAdd4.yaml
+\end{commandshell}
+ we obtain the output given in \cref{lst:myenv-output-4}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-noAdd3.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-noAdd3.yaml}}{lst:myenv-noAdd3}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-noAdd4.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-noAdd4.yaml}}{lst:myenv-noAdd4}
+ \end{minipage}
+
+ \cmhlistingsfromfile{demonstrations/myenvironment-simple-noAdd-body4.tex}{\texttt{myenv.tex output} (using either \cref{lst:myenv-noAdd3} or \cref{lst:myenv-noAdd4})}{lst:myenv-output-4}
+
+ Let's now allow \texttt{myenv} to have some optional and mandatory arguments, as
+ in \cref{lst:myenv-args}.
+
+ \cmhlistingsfromfile{demonstrations/myenvironment-args.tex}{\texttt{myenv-args.tex}}{lst:myenv-args}
+
+ Upon running
+ \begin{commandshell}
+latexindent.pl -l=myenv-noAdd1.yaml myenv-args.tex
+\end{commandshell}
+ we obtain the output shown in \cref{lst:myenv-args-noAdd1}; note that the optional argument,
+ mandatory argument and body \emph{all} have received no additional indent.
+ This is because, when \texttt{noAdditionalIndent} is specified in `scalar' form (as in
+ \cref{lst:myenv-noAdd1}), then \emph{all} parts of the environment (body,
+ optional and mandatory arguments) are assumed to want no additional indent.
+ \cmhlistingsfromfile{demonstrations/myenvironment-args-noAdd-body1.tex}{\texttt{myenv-args.tex} using \cref{lst:myenv-noAdd1}}{lst:myenv-args-noAdd1}
+
+ We may customise \texttt{noAdditionalIndent} for optional and mandatory arguments of the
+ \texttt{myenv} environment, as shown in, for example, \cref{lst:myenv-noAdd5,lst:myenv-noAdd6}.
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-noAdd5.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-noAdd5.yaml}}{lst:myenv-noAdd5}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-noAdd6.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-noAdd6.yaml}}{lst:myenv-noAdd6}
+ \end{minipage}
+
+ Upon running
+ \begin{commandshell}
+latexindent.pl myenv.tex -l myenv-noAdd5.yaml
+latexindent.pl myenv.tex -l myenv-noAdd6.yaml
+\end{commandshell}
+ we obtain the respective outputs given in \cref{lst:myenv-args-noAdd5,lst:myenv-args-noAdd6}. Note that in
+ \cref{lst:myenv-args-noAdd5} the text for the \emph{optional} argument has not
+ received any additional indentation, and that in \cref{lst:myenv-args-noAdd6} the
+ \emph{mandatory} argument has not received any additional indentation; in both
+ cases, the \emph{body} has not received any additional indentation.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/myenvironment-args-noAdd5.tex}{\texttt{myenv-args.tex} using \cref{lst:myenv-noAdd5}}{lst:myenv-args-noAdd5}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/myenvironment-args-noAdd6.tex}{\texttt{myenv-args.tex} using \cref{lst:myenv-noAdd6}}{lst:myenv-args-noAdd6}
+ \end{minipage}
+
+\yamltitle{indentRules}*{fields}
+ We may also specify indentation rules for environment code blocks using the
+ \texttt{indentRules} field; see, for example, \cref{lst:myenv-rules1,lst:myenv-rules2}.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-rules1.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-rules1.yaml}}{lst:myenv-rules1}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-rules2.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-rules2.yaml}}{lst:myenv-rules2}
+ \end{cmhtcbraster}
+
+ On applying either of the following commands,
+ \begin{commandshell}
+latexindent.pl myenv.tex -l myenv-rules1.yaml
+latexindent.pl myenv.tex -l myenv-rules2.yaml
+\end{commandshell}
+ we obtain the output given in \cref{lst:myenv-rules-output}; note in particular that the
+ environment \texttt{myenv} has received one tab (from the
+ \texttt{outer} environment) plus three spaces from \cref{lst:myenv-rules1} or
+ \ref{lst:myenv-rules2}.
+
+ \cmhlistingsfromfile[showtabs=true,showspaces=true]{demonstrations/myenv-rules1.tex}{\texttt{myenv.tex} output (using either \cref{lst:myenv-rules1} or \cref{lst:myenv-rules2})}{lst:myenv-rules-output}
+
+ If you specify a field in \texttt{indentRules} using anything other than horizontal
+ space, it will be ignored.
+
+ Returning to the example in \cref{lst:myenv-args} that contains optional and mandatory
+ arguments. Upon using \cref{lst:myenv-rules1} as in
+ \begin{commandshell}
+latexindent.pl myenv-args.tex -l=myenv-rules1.yaml
+\end{commandshell}
+ we obtain the output in \cref{lst:myenv-args-rules1}; note that the body, optional argument
+ and mandatory argument of \texttt{myenv} have \emph{all} received
+ the same customised indentation. \cmhlistingsfromfile[showtabs=true,showspaces=true]{demonstrations/myenvironment-args-rules1.tex}{\texttt{myenv-args.tex} using \cref{lst:myenv-rules1}}{lst:myenv-args-rules1}
+
+ You can specify different indentation rules for the different features using, for
+ example, \cref{lst:myenv-rules3,lst:myenv-rules4}
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-rules3.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-rules3.yaml}}{lst:myenv-rules3}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/myenv-rules4.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{myenv-rules4.yaml}}{lst:myenv-rules4}
+ \end{minipage}
+
+ After running
+ \begin{commandshell}
+latexindent.pl myenv-args.tex -l myenv-rules3.yaml
+latexindent.pl myenv-args.tex -l myenv-rules4.yaml
+\end{commandshell}
+ then we obtain the respective outputs given in \cref{lst:myenv-args-rules3,lst:myenv-args-rules4}.
+
+ \begin{widepage}
+ \begin{minipage}{.5\textwidth}
+ \cmhlistingsfromfile[showtabs=true,showspaces=true]{demonstrations/myenvironment-args-rules3.tex}{\texttt{myenv-args.tex} using \cref{lst:myenv-rules3}}{lst:myenv-args-rules3}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.5\textwidth}
+ \cmhlistingsfromfile[showtabs=true,showspaces=true]{demonstrations/myenvironment-args-rules4.tex}{\texttt{myenv-args.tex} using \cref{lst:myenv-rules4}}{lst:myenv-args-rules4}
+ \end{minipage}
+ \end{widepage}
+
+ Note that in \cref{lst:myenv-args-rules3}, the optional argument has only received a single
+ space of indentation, while the mandatory argument has received the default (tab)
+ indentation; the environment body has received three spaces of indentation.
+
+ In \cref{lst:myenv-args-rules4}, the optional argument has received the default (tab)
+ indentation, the mandatory argument has received two tabs of indentation, and the body
+ has received three spaces of indentation.
+
+\yamltitle{noAdditionalIndentGlobal}*{fields}
+ \begin{wrapfigure}[6]{r}[0pt]{7cm}
+ \cmhlistingsfromfile[style=noAdditionalIndentGlobalEnv]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{noAdditionalIndentGlobal}}{lst:noAdditionalIndentGlobal:environments}
+ \end{wrapfigure}
+ Assuming that your environment name is not found within neither \texttt{noAdditionalIndent}
+ nor \texttt{indentRules}, the next place that \texttt{latexindent.pl} will look is
+ \texttt{noAdditionalIndentGlobal}, and in particular \emph{for the environments} key (see
+ \cref{lst:noAdditionalIndentGlobal:environments}). Let's say that you change the value of \texttt{environments}
+ to \texttt{1} in \cref{lst:noAdditionalIndentGlobal:environments}, and that you run
+
+ \begin{widepage}
+ \begin{commandshell}
+latexindent.pl myenv-args.tex -l env-noAdditionalGlobal.yaml
+latexindent.pl myenv-args.tex -l myenv-rules1.yaml,env-noAdditionalGlobal.yaml
+\end{commandshell}
+ \end{widepage}
+
+ The respective output from these two commands are in \cref{lst:myenv-args-no-add-global1,lst:myenv-args-no-add-global2}; in
+ \cref{lst:myenv-args-no-add-global1} notice that \emph{both} environments receive no
+ additional indentation but that the arguments of \texttt{myenv} still
+ \emph{do} receive indentation. In \cref{lst:myenv-args-no-add-global2} notice that the
+ \emph{outer} environment does not receive additional indentation, but because
+ of the settings from \texttt{myenv-rules1.yaml} (in \vref{lst:myenv-rules1}), the \texttt{myenv} environment
+ still \emph{does} receive indentation.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/myenvironment-args-rules1-noAddGlobal1.tex}{\texttt{myenv-args.tex} using \cref{lst:noAdditionalIndentGlobal:environments}}{lst:myenv-args-no-add-global1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/myenvironment-args-rules1-noAddGlobal2.tex}{\texttt{myenv-args.tex} using \cref{lst:noAdditionalIndentGlobal:environments,lst:myenv-rules1}}{lst:myenv-args-no-add-global2}
+ \end{minipage}
+
+ In fact, \texttt{noAdditionalIndentGlobal} also contains keys that control the indentation of
+ optional and mandatory arguments; on referencing \cref{lst:opt-args-no-add-glob,lst:mand-args-no-add-glob}
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/opt-args-no-add-glob.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{opt-args-no-add-glob.yaml}}{lst:opt-args-no-add-glob}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mand-args-no-add-glob.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{mand-args-no-add-glob.yaml}}{lst:mand-args-no-add-glob}
+ \end{minipage}
+
+ we may run the commands
+ \begin{commandshell}
+latexindent.pl myenv-args.tex -local opt-args-no-add-glob.yaml
+latexindent.pl myenv-args.tex -local mand-args-no-add-glob.yaml
+\end{commandshell}
+ which produces the respective outputs given in \cref{lst:myenv-args-no-add-opt,lst:myenv-args-no-add-mand}. Notice that in
+ \cref{lst:myenv-args-no-add-opt} the \emph{optional} argument has not received any
+ additional indentation, and in \cref{lst:myenv-args-no-add-mand} the \emph{mandatory}
+ argument has not received any additional indentation.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/myenvironment-args-rules1-noAddGlobal3.tex}{\texttt{myenv-args.tex} using \cref{lst:opt-args-no-add-glob}}{lst:myenv-args-no-add-opt}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/myenvironment-args-rules1-noAddGlobal4.tex}{\texttt{myenv-args.tex} using \cref{lst:mand-args-no-add-glob}}{lst:myenv-args-no-add-mand}
+ \end{minipage}
+
+\yamltitle{indentRulesGlobal}*{fields}
+ \begin{wrapfigure}[4]{r}[0pt]{7cm}
+ \cmhlistingsfromfile[style=indentRulesGlobalEnv]*{../defaultSettings.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{indentRulesGlobal}}{lst:indentRulesGlobal:environments}
+ \end{wrapfigure}
+ The final check that \texttt{latexindent.pl} will make is to look for
+ \texttt{indentRulesGlobal} as detailed in \cref{lst:indentRulesGlobal:environments}; if you change the
+ \texttt{environments} field to anything involving horizontal space, say
+ \lstinline!" "!, and then run the following commands
+
+ \begin{commandshell}
+latexindent.pl myenv-args.tex -l env-indentRules.yaml
+latexindent.pl myenv-args.tex -l myenv-rules1.yaml,env-indentRules.yaml
+\end{commandshell}
+ then the respective output is shown in \cref{lst:myenv-args-indent-rules-global1,lst:myenv-args-indent-rules-global2}. Note that in
+ \cref{lst:myenv-args-indent-rules-global1}, both the environment blocks have received a single-space
+ indentation, whereas in \cref{lst:myenv-args-indent-rules-global2} the \texttt{outer} environment
+ has received single-space indentation (specified by \texttt{indentRulesGlobal}), but
+ \texttt{myenv} has received \lstinline!" "!, as specified by the
+ particular \texttt{indentRules} for \texttt{myenv} \vref{lst:myenv-rules1}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/myenvironment-args-global-rules1.tex}{\texttt{myenv-args.tex} using \cref{lst:indentRulesGlobal:environments}}{lst:myenv-args-indent-rules-global1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/myenvironment-args-global-rules2.tex}{\texttt{myenv-args.tex} using \cref{lst:myenv-rules1,lst:indentRulesGlobal:environments}}{lst:myenv-args-indent-rules-global2}
+ \end{minipage}
+
+ You can specify \texttt{indentRulesGlobal} for both optional and mandatory arguments, as
+ detailed in \cref{lst:opt-args-indent-rules-glob,lst:mand-args-indent-rules-glob}
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/opt-args-indent-rules-glob.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{opt-args-indent-rules-glob.yaml}}{lst:opt-args-indent-rules-glob}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/mand-args-indent-rules-glob.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{mand-args-indent-rules-glob.yaml}}{lst:mand-args-indent-rules-glob}
+ \end{minipage}
+
+ Upon running the following commands
+ \begin{commandshell}
+latexindent.pl myenv-args.tex -local opt-args-indent-rules-glob.yaml
+latexindent.pl myenv-args.tex -local mand-args-indent-rules-glob.yaml
+\end{commandshell}
+ we obtain the respective outputs in \cref{lst:myenv-args-indent-rules-global3,lst:myenv-args-indent-rules-global4}. Note that the
+ \emph{optional} argument in \cref{lst:myenv-args-indent-rules-global3} has received two tabs worth
+ of indentation, while the \emph{mandatory} argument has done so in
+ \cref{lst:myenv-args-indent-rules-global4}.
+
+ \begin{widepage}
+ \begin{minipage}{.55\textwidth}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/myenvironment-args-global-rules3.tex}{\texttt{myenv-args.tex} using \cref{lst:opt-args-indent-rules-glob}}{lst:myenv-args-indent-rules-global3}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.55\textwidth}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/myenvironment-args-global-rules4.tex}{\texttt{myenv-args.tex} using \cref{lst:mand-args-indent-rules-glob}}{lst:myenv-args-indent-rules-global4}
+ \end{minipage}
+ \end{widepage}
diff --git a/support/latexindent/documentation/subsubsec-environments-with-items.tex b/support/latexindent/documentation/subsubsec-environments-with-items.tex
new file mode 100644
index 0000000000..4cc53e654f
--- /dev/null
+++ b/support/latexindent/documentation/subsubsec-environments-with-items.tex
@@ -0,0 +1,61 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsubsection{Environments with items}
+ With reference to \vref{lst:indentafteritems,lst:itemNames}, some commands may contain
+ \texttt{item} commands; for the purposes of this discussion, we will use the
+ code from \vref{lst:itemsbefore}.
+
+ Assuming that you've populated \texttt{itemNames} with the name of your
+ \texttt{item}, you can put the item name into \texttt{noAdditionalIndent} as in
+ \cref{lst:item-noAdd1}, although a more efficient approach may be to change the relevant
+ field in \texttt{itemNames} to \texttt{0}. Similarly, you can customise
+ the indentation that your \texttt{item} receives using \texttt{indentRules},
+ as in \cref{lst:item-rules1}
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/item-noAdd1.yaml}[yaml-TCB]{\texttt{item-noAdd1.yaml}}{lst:item-noAdd1}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/item-rules1.yaml}[yaml-TCB]{\texttt{item-rules1.yaml}}{lst:item-rules1}
+ \end{cmhtcbraster}
+
+ Upon running the following commands
+ \begin{commandshell}
+latexindent.pl items1.tex -local item-noAdd1.yaml
+latexindent.pl items1.tex -local item-rules1.yaml
+\end{commandshell}
+ the respective outputs are given in \cref{lst:items1-noAdd1,lst:items1-rules1}; note that in
+ \cref{lst:items1-noAdd1} that the text after each \texttt{item} has not received
+ any additional indentation, and in \cref{lst:items1-rules1}, the text after each
+ \texttt{item} has received a single space of indentation, specified by
+ \cref{lst:item-rules1}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/items1-noAdd1.tex}{\texttt{items1.tex} using \cref{lst:item-noAdd1}}{lst:items1-noAdd1}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[showtabs=true,showspaces=true]{demonstrations/items1-rules1.tex}{\texttt{items1.tex} using \cref{lst:item-rules1}}{lst:items1-rules1}
+ \end{minipage}
+
+ Alternatively, you might like to populate \texttt{noAdditionalIndentGlobal} or
+ \texttt{indentRulesGlobal} using the \texttt{items} key, as demonstrated in
+ \cref{lst:items-noAdditionalGlobal,lst:items-indentRulesGlobal}. Note that there is a need to `reset/remove' the
+ \texttt{item} field from \texttt{indentRules} in both cases (see the hierarchy
+ description given on \cpageref{sec:noadd-indent-rules}) as the \texttt{item} command is a
+ member of \texttt{indentRules} by default.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/items-noAdditionalGlobal.yaml}[yaml-TCB]{\texttt{items-noAdditionalGlobal.yaml}}{lst:items-noAdditionalGlobal}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/items-indentRulesGlobal.yaml}[yaml-TCB]{\texttt{items-indentRulesGlobal.yaml}}{lst:items-indentRulesGlobal}
+ \end{minipage}
+
+ Upon running the following commands,
+ \begin{commandshell}
+latexindent.pl items1.tex -local items-noAdditionalGlobal.yaml
+latexindent.pl items1.tex -local items-indentRulesGlobal.yaml
+\end{commandshell}
+ the respective outputs from \cref{lst:items1-noAdd1,lst:items1-rules1} are obtained; note, however, that
+ \emph{all} such \texttt{item} commands without their own individual
+ \texttt{noAdditionalIndent} or \texttt{indentRules} settings would behave as in these
+ listings.
diff --git a/support/latexindent/documentation/subsubsec-headings.tex b/support/latexindent/documentation/subsubsec-headings.tex
new file mode 100644
index 0000000000..088ece973d
--- /dev/null
+++ b/support/latexindent/documentation/subsubsec-headings.tex
@@ -0,0 +1,85 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsubsection{afterHeading code blocks}\label{subsubsec-headings-no-add-indent-rules}
+ Let's use the example \cref{lst:headings2} for demonstration throughout this
+ \namecref{subsubsec-headings-no-add-indent-rules}. As discussed on \cpageref{lst:headings1}, by default
+ \texttt{latexindent.pl} will not add indentation after headings.
+
+ \cmhlistingsfromfile{demonstrations/headings2.tex}{\texttt{headings2.tex}}{lst:headings2}
+
+ On using the YAML file in \cref{lst:headings3yaml} by running the command
+ \begin{commandshell}
+latexindent.pl headings2.tex -l headings3.yaml
+\end{commandshell}
+ we obtain the output in \cref{lst:headings2-mod3}. Note that the argument of
+ \texttt{paragraph} has received (default) indentation, and that the body after the
+ heading statement has received (default) indentation.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/headings2-mod3.tex}{\texttt{headings2.tex} using \cref{lst:headings3yaml}}{lst:headings2-mod3}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/headings3.yaml}[yaml-TCB]{\texttt{headings3.yaml}}{lst:headings3yaml}
+ \end{cmhtcbraster}
+
+ If we specify \texttt{noAdditionalIndent} as in \cref{lst:headings4yaml} and run the command
+ \begin{commandshell}
+latexindent.pl headings2.tex -l headings4.yaml
+\end{commandshell}
+ then we receive the output in \cref{lst:headings2-mod4}. Note that the arguments
+ \emph{and} the body after the heading of \texttt{paragraph} has received
+ no additional indentation, because we have specified \texttt{noAdditionalIndent} in scalar
+ form.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/headings2-mod4.tex}{\texttt{headings2.tex} using \cref{lst:headings4yaml}}{lst:headings2-mod4}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/headings4.yaml}[yaml-TCB]{\texttt{headings4.yaml}}{lst:headings4yaml}
+ \end{cmhtcbraster}
+
+ Similarly, if we specify \texttt{indentRules} as in \cref{lst:headings5yaml} and run
+ analogous commands to those above, we receive the output in \cref{lst:headings2-mod5}; note
+ that the \emph{body}, \emph{mandatory argument} and content
+ \emph{after the heading} of \texttt{paragraph} have \emph{all} received
+ three tabs worth of indentation.
+
+ \begin{cmhtcbraster}[raster force size=false,
+ raster column 1/.style={add to width=1cm},
+ raster column 2/.style={add to width=-1cm},
+ ]
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/headings2-mod5.tex}{\texttt{headings2.tex} using \cref{lst:headings5yaml}}{lst:headings2-mod5}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/headings5.yaml}[yaml-TCB]{\texttt{headings5.yaml}}{lst:headings5yaml}
+ \end{cmhtcbraster}
+
+ We may, instead, specify \texttt{noAdditionalIndent} in `field' form, as in
+ \cref{lst:headings6yaml} which gives the output in \cref{lst:headings2-mod6}.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/headings2-mod6.tex}{\texttt{headings2.tex} using \cref{lst:headings6yaml}}{lst:headings2-mod6}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/headings6.yaml}[yaml-TCB]{\texttt{headings6.yaml}}{lst:headings6yaml}
+ \end{cmhtcbraster}
+
+ Analogously, we may specify \texttt{indentRules} as in \cref{lst:headings7yaml} which
+ gives the output in \cref{lst:headings2-mod7}; note that mandatory argument text has only
+ received a single space of indentation, while the body after the heading has received
+ three tabs worth of indentation.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/headings2-mod7.tex}{\texttt{headings2.tex} using \cref{lst:headings7yaml}}{lst:headings2-mod7}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/headings7.yaml}[yaml-TCB]{\texttt{headings7.yaml}}{lst:headings7yaml}
+ \end{cmhtcbraster}
+
+ Finally, let's consider \texttt{noAdditionalIndentGlobal} and \texttt{indentRulesGlobal} shown in
+ \cref{lst:headings8yaml,lst:headings9yaml} respectively, with respective output in \cref{lst:headings2-mod8,lst:headings2-mod9}.
+ Note that in \cref{lst:headings8yaml} the \emph{mandatory argument} of \texttt{paragraph}
+ has received a (default) tab's worth of indentation, while the body after the heading has
+ received \emph{no additional indentation}. Similarly, in \cref{lst:headings2-mod9}, the
+ \emph{argument} has received both a (default) tab plus two spaces of indentation
+ (from the global rule specified in \cref{lst:headings9yaml}), and the remaining body after
+ \texttt{paragraph} has received just two spaces of indentation.
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile{demonstrations/headings2-mod8.tex}{\texttt{headings2.tex} using \cref{lst:headings8yaml}}{lst:headings2-mod8}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/headings8.yaml}[yaml-TCB]{\texttt{headings8.yaml}}{lst:headings8yaml}
+ \end{cmhtcbraster}
+
+ \begin{cmhtcbraster}
+ \cmhlistingsfromfile[showspaces=true,showtabs=true]{demonstrations/headings2-mod9.tex}{\texttt{headings2.tex} using \cref{lst:headings9yaml}}{lst:headings2-mod9}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/headings9.yaml}[yaml-TCB]{\texttt{headings9.yaml}}{lst:headings9yaml}
+ \end{cmhtcbraster}
diff --git a/support/latexindent/documentation/subsubsec-ifelsefi.tex b/support/latexindent/documentation/subsubsec-ifelsefi.tex
new file mode 100644
index 0000000000..c7171bc752
--- /dev/null
+++ b/support/latexindent/documentation/subsubsec-ifelsefi.tex
@@ -0,0 +1,84 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsubsection{ifelsefi code blocks}
+ Let's use the simple example shown in \cref{lst:ifelsefi1}; when \texttt{latexindent.pl}
+ operates on this file, the output as in \cref{lst:ifelsefi1-default}; note that the body of
+ each of the \lstinline!\if! statements have been indented, and that the
+ \lstinline!\else! statement has been accounted for correctly.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/ifelsefi1.tex}{\texttt{ifelsefi1.tex}}{lst:ifelsefi1}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.54\textwidth}
+ \cmhlistingsfromfile{demonstrations/ifelsefi1-default.tex}{\texttt{ifelsefi1.tex} default output}{lst:ifelsefi1-default}
+ \end{minipage}
+
+ It is recommended to specify \texttt{noAdditionalIndent} and \texttt{indentRules} in the
+ `scalar' form only for these type of code blocks, although the `field' form would work,
+ assuming that \texttt{body} was specified. Examples are shown in
+ \cref{lst:ifnum-noAdd,lst:ifnum-indent-rules}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/ifnum-noAdd.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{ifnum-noAdd.yaml}}{lst:ifnum-noAdd}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/ifnum-indent-rules.yaml}[width=.8\linewidth,before=\centering,yaml-TCB]{\texttt{ifnum-indent-rules.yaml}}{lst:ifnum-indent-rules}
+ \end{minipage}
+
+ After running the following commands,
+ \begin{commandshell}
+latexindent.pl ifelsefi1.tex -local ifnum-noAdd.yaml
+latexindent.pl ifelsefi1.tex -l ifnum-indent-rules.yaml
+\end{commandshell}
+ we receive the respective output given in \cref{lst:ifelsefi1-output-noAdd,lst:ifelsefi1-output-indent-rules}; note that in
+ \cref{lst:ifelsefi1-output-noAdd}, the \texttt{ifnum} code block has \emph{not}
+ received any additional indentation, while in \cref{lst:ifelsefi1-output-indent-rules}, the
+ \texttt{ifnum} code block has received one tab and two spaces of indentation.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/ifelsefi1-noAdd.tex}{\texttt{ifelsefi1.tex} using \cref{lst:ifnum-noAdd}}{lst:ifelsefi1-output-noAdd}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.5\textwidth}
+ \cmhlistingsfromfile[showspaces=true,showtabs=true]{demonstrations/ifelsefi1-indent-rules.tex}{\texttt{ifelsefi1.tex} using \cref{lst:ifnum-indent-rules}}{lst:ifelsefi1-output-indent-rules}
+ \end{minipage}
+
+ We may specify \texttt{noAdditionalIndentGlobal} and \texttt{indentRulesGlobal} as in
+ \cref{lst:ifelsefi-noAdd-glob,lst:ifelsefi-indent-rules-global}.
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/ifelsefi-noAdd-glob.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{ifelsefi-noAdd-glob.yaml}}{lst:ifelsefi-noAdd-glob}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/ifelsefi-indent-rules-global.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{ifelsefi-indent-rules-global.yaml}}{lst:ifelsefi-indent-rules-global}
+ \end{minipage}
+
+ Upon running the following commands
+ \begin{commandshell}
+latexindent.pl ifelsefi1.tex -local ifelsefi-noAdd-glob.yaml
+latexindent.pl ifelsefi1.tex -l ifelsefi-indent-rules-global.yaml
+\end{commandshell}
+ we receive the outputs in \cref{lst:ifelsefi1-output-noAdd-glob,lst:ifelsefi1-output-indent-rules-global}; notice that in \cref{lst:ifelsefi1-output-noAdd-glob}
+ neither of the \texttt{ifelsefi} code blocks have received indentation, while in
+ \cref{lst:ifelsefi1-output-indent-rules-global} both code blocks have received a single space of indentation.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/ifelsefi1-noAdd-glob.tex}{\texttt{ifelsefi1.tex} using \cref{lst:ifelsefi-noAdd-glob}}{lst:ifelsefi1-output-noAdd-glob}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/ifelsefi1-indent-rules-global.tex}{\texttt{ifelsefi1.tex} using \cref{lst:ifelsefi-indent-rules-global}}{lst:ifelsefi1-output-indent-rules-global}
+ \end{minipage}
+
+ We can further explore the treatment of \texttt{ifElseFi} code
+ blocks%
+ \announce{2018-04-27}*{updates to ifElseFi code blocks} in \cref{lst:ifelsefi2},
+ and the associated default output given in \cref{lst:ifelsefi2-default}; note, in particular,
+ that the bodies of each of the `or statements' have been indented.
+
+ \begin{cmhtcbraster}[raster column skip=.1\linewidth]
+ \cmhlistingsfromfile{demonstrations/ifelsefi2.tex}{\texttt{ifelsefi2.tex}}{lst:ifelsefi2}
+ \cmhlistingsfromfile{demonstrations/ifelsefi2-default.tex}{\texttt{ifelsefi2.tex} default output}{lst:ifelsefi2-default}
+ \end{cmhtcbraster}
diff --git a/support/latexindent/documentation/subsubsec-no-add-remaining-code-blocks.tex b/support/latexindent/documentation/subsubsec-no-add-remaining-code-blocks.tex
new file mode 100644
index 0000000000..a91b4b0c98
--- /dev/null
+++ b/support/latexindent/documentation/subsubsec-no-add-remaining-code-blocks.tex
@@ -0,0 +1,135 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsubsection{The remaining code blocks}
+ Referencing the different types of code blocks in \vref{tab:code-blocks}, we have a few
+ code blocks yet to cover; these are very similar to the \texttt{commands} code block
+ type covered comprehensively in \vref{subsubsec:commands-arguments}, but a small discussion defining
+ these remaining code blocks is necessary.
+
+ \paragraph{keyEqualsValuesBracesBrackets}
+ \texttt{latexindent.pl} defines this type of code block by the following criteria:
+ \begin{itemize}
+ \item it must immediately follow either \lstinline!{! OR \lstinline![! OR
+ \lstinline!,! with comments and blank lines allowed.
+ \item then it has a name made up of the characters detailed in \vref{tab:code-blocks};
+ \item then an $=$ symbol;
+ \item then at least one set of curly braces or square brackets (comments and line breaks
+ allowed throughout).
+ \end{itemize}
+ See the \texttt{keyEqualsValuesBracesBrackets: follow} and \texttt{keyEqualsValuesBracesBrackets: name} fields of the fine tuning
+ section in \vref{lst:fineTuning}%
+ \announce*{2019-07-13}{fine tuning: keyEqualsValuesBracesBrackets}
+
+ An example is shown in \cref{lst:pgfkeysbefore}, with the default output given in
+ \cref{lst:pgfkeys1:default}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/pgfkeys1.tex}{\texttt{pgfkeys1.tex}}{lst:pgfkeysbefore}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.5\textwidth}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/pgfkeys1-default.tex}{\texttt{pgfkeys1.tex} default output}{lst:pgfkeys1:default}
+ \end{minipage}%
+
+ In \cref{lst:pgfkeys1:default}, note that the maximum indentation is three tabs, and these
+ come from:
+ \begin{itemize}
+ \item the \lstinline!\pgfkeys! command's mandatory argument;
+ \item the \lstinline!start coordinate/.initial! key's mandatory argument;
+ \item the \lstinline!start coordinate/.initial! key's body, which is defined as any lines following the name
+ of the key that include its arguments. This is the part controlled by the
+ \emph{body} field for \texttt{noAdditionalIndent} and friends from
+ \cpageref{sec:noadd-indent-rules}.
+ \end{itemize}
+ \paragraph{namedGroupingBracesBrackets}
+ This type of code block is mostly motivated by tikz-based code; we define this code block
+ as follows:
+ \begin{itemize}
+ \item it must immediately follow either \emph{horizontal space} OR \emph{one or more line breaks} OR
+ \lstinline!{! OR \lstinline![! OR \lstinline!$! OR
+ \lstinline!)! OR \lstinline!(!
+ \item the name may contain the characters detailed in \vref{tab:code-blocks};
+ \item then at least one set of curly braces or square brackets (comments and line breaks
+ allowed throughout).
+ \end{itemize}
+ See the \texttt{NamedGroupingBracesBrackets: follow} and \texttt{NamedGroupingBracesBrackets: name} fields of the fine tuning
+ section in \vref{lst:fineTuning}%
+ \announce*{2019-07-13}{fine tuning: namedGroupingBracesBrackets}
+
+ A simple example is given in \cref{lst:child1}, with default output in
+ \cref{lst:child1:default}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/child1.tex}{\texttt{child1.tex}}{lst:child1}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.5\textwidth}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/child1-default.tex}{\texttt{child1.tex} default output}{lst:child1:default}
+ \end{minipage}%
+
+ In particular, \texttt{latexindent.pl} considers \texttt{child},
+ \texttt{parent} and \texttt{node} all to be
+ \texttt{namedGroupingBracesBrackets}\footnote{
+ You may like to verify this by using the \texttt{-tt} option and checking \texttt{indent.log}! }. Referencing \cref{lst:child1:default}, note
+ that the maximum indentation is two tabs, and these come from:
+ \begin{itemize}
+ \item the \lstinline!child!'s mandatory argument;
+ \item the \lstinline!child!'s body, which is defined as any lines following the name of
+ the \texttt{namedGroupingBracesBrackets} that include its arguments. This is the part controlled by the
+ \emph{body} field for \texttt{noAdditionalIndent} and friends from
+ \cpageref{sec:noadd-indent-rules}.
+ \end{itemize}
+
+ \paragraph{UnNamedGroupingBracesBrackets} occur in a variety of situations; specifically, we define
+ this type of code block as satisfying the following criteria:
+ \begin{itemize}
+ \item it must immediately follow either \lstinline!{! OR \lstinline![! OR
+ \lstinline!,! OR \lstinline!&! OR \lstinline!)! OR
+ \lstinline!(! OR \lstinline!$!;
+ \item then at least one set of curly braces or square brackets (comments and line breaks
+ allowed throughout).
+ \end{itemize}
+ See the \texttt{UnNamedGroupingBracesBrackets: follow} field of the fine tuning section in \vref{lst:fineTuning}%
+ \announce*{2019-07-13}{fine tuning: namedGroupingBracesBrackets}
+
+ An example is shown in \cref{lst:psforeach1} with default output give in
+ \cref{lst:psforeach:default}.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/psforeach1.tex}{\texttt{psforeach1.tex}}{lst:psforeach1}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.5\textwidth}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/psforeach1-default.tex}{\texttt{psforeach1.tex} default output}{lst:psforeach:default}
+ \end{minipage}%
+
+ Referencing \cref{lst:psforeach:default}, there are \emph{three} sets of unnamed
+ braces. Note also that the maximum value of indentation is three tabs, and these come
+ from:
+ \begin{itemize}
+ \item the \lstinline!\psforeach! command's mandatory argument;
+ \item the \emph{first} un-named braces mandatory argument;
+ \item the \emph{first} un-named braces \emph{body}, which we define as any
+ lines following the first opening \lstinline!{! or \lstinline![! that
+ defined the code block. This is the part controlled by the \emph{body} field
+ for \texttt{noAdditionalIndent} and friends from \cpageref{sec:noadd-indent-rules}.
+ \end{itemize}
+ Users wishing to customise the mandatory and/or optional arguments on a
+ \emph{per-name} basis for the \texttt{UnNamedGroupingBracesBrackets} should use
+ \texttt{always-un-named}.
+
+ \paragraph{filecontents} code blocks behave just as \texttt{environments}, except that
+ neither arguments nor items are sought.
+
+\subsubsection{Summary}
+ Having considered all of the different types of code blocks, the functions of the fields
+ given in \cref{lst:noAdditionalIndentGlobal,lst:indentRulesGlobal} should now make sense.
+
+ \begin{widepage}
+ \begin{minipage}{.47\linewidth}
+ \cmhlistingsfromfile[style=noAdditionalIndentGlobal]*{../defaultSettings.yaml}[before=\centering,yaml-TCB]{\texttt{noAdditionalIndentGlobal}}{lst:noAdditionalIndentGlobal}
+ \end{minipage}%
+ \hfill
+ \begin{minipage}{.47\linewidth}
+ \cmhlistingsfromfile[style=indentRulesGlobal]*{../defaultSettings.yaml}[before=\centering,yaml-TCB]{\texttt{indentRulesGlobal}}{lst:indentRulesGlobal}
+ \end{minipage}%
+ \end{widepage}
diff --git a/support/latexindent/documentation/subsubsec-special.tex b/support/latexindent/documentation/subsubsec-special.tex
new file mode 100644
index 0000000000..378c4d1413
--- /dev/null
+++ b/support/latexindent/documentation/subsubsec-special.tex
@@ -0,0 +1,63 @@
+% arara: pdflatex: {shell: yes, files: [latexindent]}
+\subsubsection{specialBeginEnd code blocks}
+ Let's use the example from \vref{lst:specialbefore} which has default output shown in
+ \vref{lst:specialafter}.
+
+ It is recommended to specify \texttt{noAdditionalIndent} and \texttt{indentRules} in the
+ `scalar' form for these type of code blocks, although the `field' form would work,
+ assuming that \texttt{body} was specified. Examples are shown in
+ \cref{lst:displayMath-noAdd,lst:displayMath-indent-rules}.
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/displayMath-noAdd.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{displayMath-noAdd.yaml}}{lst:displayMath-noAdd}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/displayMath-indent-rules.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{displayMath-indent-rules.yaml}}{lst:displayMath-indent-rules}
+ \end{minipage}
+
+ After running the following commands,
+ \begin{commandshell}
+latexindent.pl special1.tex -local displayMath-noAdd.yaml
+latexindent.pl special1.tex -l displayMath-indent-rules.yaml
+\end{commandshell}
+ we receive the respective output given in \cref{lst:special1-output-noAdd,lst:special1-output-indent-rules}; note that in
+ \cref{lst:special1-output-noAdd}, the \texttt{displayMath} code block has \emph{not}
+ received any additional indentation, while in \cref{lst:special1-output-indent-rules}, the
+ \texttt{displayMath} code block has received three tabs worth of indentation.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/special1-noAdd.tex}{\texttt{special1.tex} using \cref{lst:displayMath-noAdd}}{lst:special1-output-noAdd}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[showtabs=true]{demonstrations/special1-indent-rules.tex}{\texttt{special1.tex} using \cref{lst:displayMath-indent-rules}}{lst:special1-output-indent-rules}
+ \end{minipage}
+
+ We may specify \texttt{noAdditionalIndentGlobal} and \texttt{indentRulesGlobal} as in
+ \cref{lst:special-noAdd-glob,lst:special-indent-rules-global}.
+
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/special-noAdd-glob.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{special-noAdd-glob.yaml}}{lst:special-noAdd-glob}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.49\textwidth}
+ \cmhlistingsfromfile[style=yaml-LST]*{demonstrations/special-indent-rules-global.yaml}[width=.9\linewidth,before=\centering,yaml-TCB]{\texttt{special-indent-rules-global.yaml}}{lst:special-indent-rules-global}
+ \end{minipage}
+
+ Upon running the following commands
+ \begin{commandshell}
+latexindent.pl special1.tex -local special-noAdd-glob.yaml
+latexindent.pl special1.tex -l special-indent-rules-global.yaml
+\end{commandshell}
+ we receive the outputs in \cref{lst:special1-output-noAdd-glob,lst:special1-output-indent-rules-global}; notice that in \cref{lst:special1-output-noAdd-glob}
+ neither of the \texttt{special} code blocks have received indentation, while in
+ \cref{lst:special1-output-indent-rules-global} both code blocks have received a single space of indentation.
+
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile{demonstrations/special1-noAdd-glob.tex}{\texttt{special1.tex} using \cref{lst:special-noAdd-glob}}{lst:special1-output-noAdd-glob}
+ \end{minipage}
+ \hfill
+ \begin{minipage}{.45\textwidth}
+ \cmhlistingsfromfile[showspaces=true]{demonstrations/special1-indent-rules-global.tex}{\texttt{special1.tex} using \cref{lst:special-indent-rules-global}}{lst:special1-output-indent-rules-global}
+ \end{minipage}
diff --git a/support/latexindent/documentation/title.tex b/support/latexindent/documentation/title.tex
new file mode 100644
index 0000000000..4e0ae04a2b
--- /dev/null
+++ b/support/latexindent/documentation/title.tex
@@ -0,0 +1,27 @@
+\title{%
+ \begin{tcolorbox}[
+ width=5.2cm,
+ boxrule=0pt,
+ colframe=white!40!black,
+ colback=white,
+ rightrule=2pt,
+ sharp corners,
+ enhanced,
+ overlay={\node[anchor=north east,outer sep=2pt] at ([xshift=3cm,yshift=4mm]frame.north east) {\includegraphics[width=3cm]{logo}}; }]
+ \centering\ttfamily\bfseries latexindent.pl\\[1cm] Version 3.7
+ \end{tcolorbox}
+}
+\author{Chris Hughes \thanks{and contributors!
+ See \vref{sec:contributors}.
+ For
+ all communication, please visit \cite{latexindent-home}.}}
+\maketitle
+\begin{adjustwidth}{1cm}{1cm}
+ \small
+ \texttt{latexindent.pl} is a \texttt{Perl} script that indents \texttt{.tex} (and other) files according to an indentation scheme that the user can modify to suit their taste.
+ Environments, including those with alignment delimiters (such as \texttt{tabular}), and commands, including those that can split braces and brackets across lines, are \emph{usually} handled correctly by the script.
+ Options for \texttt{verbatim}-like environments and commands, together with indentation after headings (such as \lstinline!chapter!, \lstinline!section!, etc) are also available.
+ The script also has the ability to modify line breaks, and to add comment symbols and blank lines; furthermore, it permits string or
+ regex-based substitutions.
+ All user options are customisable via the switches and the YAML interface; you can find a quick start guide in \vref{sec:quickstart}.
+\end{adjustwidth}
diff --git a/support/latexindent/latexindent-module-installer.pl b/support/latexindent/latexindent-module-installer.pl
new file mode 100755
index 0000000000..e45fdcbe73
--- /dev/null
+++ b/support/latexindent/latexindent-module-installer.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/env perl
+# 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;
+
+print ("============\nlatexindent.pl module installer\n============\n");
+print ("Would you like to run the following commands?\n");
+my @modulesToInstall = ("cpanm YAML::Tiny","cpanm File::HomeDir","cpanm Unicode::GCString","cpanm Log::Log4perl","cpanm Log::Dispatch");
+foreach (@modulesToInstall) {
+ print $_,"\n";
+}
+if (prompt_yn("Press Y to run the above commands")){
+ foreach (@modulesToInstall) {
+ system($_);
+ }
+} else {
+ print "Not installing modules\n";
+}
+exit;
+
+# reference: https://stackoverflow.com/questions/18103501/prompting-multiple-questions-to-user-yes-no-file-name-input
+sub prompt {
+ my ($query) = @_; # take a prompt string as argument
+ local $| = 1; # activate autoflush to immediately show the prompt
+ print $query;
+ chomp(my $answer = <STDIN>);
+ return $answer;
+}
+
+sub prompt_yn {
+ my ($query) = @_;
+ my $answer = prompt("$query (Y/N): ");
+ return lc($answer) eq 'y';
+}
diff --git a/support/latexindent/latexindent.pl b/support/latexindent/latexindent.pl
new file mode 100755
index 0000000000..ecdf7c79e4
--- /dev/null
+++ b/support/latexindent/latexindent.pl
@@ -0,0 +1,81 @@
+#!/usr/bin/env perl
+# latexindent.pl, version 3.7, 2019-07-13
+#
+# 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 FindBin; # help find defaultSettings.yaml
+use Getopt::Long; # to get the switches/options/flags
+
+# use lib to make sure that @INC contains the latexindent directory
+use lib $FindBin::RealBin;
+use LatexIndent::Document;
+
+# get the options
+my %switches = (readLocalSettings=>0);
+
+GetOptions (
+ "version|v"=>\$switches{version},
+ "silent|s"=>\$switches{silentMode},
+ "trace|t"=>\$switches{trace},
+ "ttrace|tt"=>\$switches{ttrace},
+ "local|l:s"=>\$switches{readLocalSettings},
+ "yaml|y=s"=>\$switches{yaml},
+ "onlydefault|d"=>\$switches{onlyDefault},
+ "overwrite|w"=>\$switches{overwrite},
+ "outputfile|o=s"=>\$switches{outputToFile},
+ "modifylinebreaks|m"=>\$switches{modifyLineBreaks},
+ "logfile|g=s"=>\$switches{logFileName},
+ "help|h"=>\$switches{showhelp},
+ "cruft|c=s"=>\$switches{cruftDirectory},
+ "screenlog|sl"=>\$switches{screenlog},
+ "replacement|r"=>\$switches{replacement},
+ "onlyreplacement|rr"=>\$switches{onlyreplacement},
+ "replacementrespectverb|rv"=>\$switches{replacementRespectVerb},
+);
+
+# check local settings doesn't interfer with reading the file;
+# this can happen if the script is called as follows:
+#
+# latexindent.pl -l myfile.tex
+#
+# in which case, the GetOptions routine mistakes myfile.tex
+# as the optional parameter to the l flag.
+#
+# In such circumstances, we correct the mistake by assuming that
+# the only argument is the file to be indented, and place it in @ARGV
+if($switches{readLocalSettings} and scalar(@ARGV) < 1) {
+ push(@ARGV,$switches{readLocalSettings});
+ $switches{readLocalSettings} = '';
+}
+
+# default value of readLocalSettings
+#
+# latexindent -l myfile.tex
+#
+# means that we wish to use localSettings.yaml
+if(defined($switches{readLocalSettings}) and ($switches{readLocalSettings} eq '')){
+ $switches{readLocalSettings} = 'localSettings.yaml';
+}
+
+# allow STDIN as input, if a filename is not present
+unshift( @ARGV, '-' ) unless @ARGV;
+
+my $document = bless ({name=>"masterDocument",modifyLineBreaksYamlName=>"masterDocument",fileName=>$ARGV[0],switches=>\%switches},"LatexIndent::Document");
+$document->latexindent;
+exit(0);