diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/latexindent/LatexIndent/Command.pm |
Initial commit
Diffstat (limited to 'support/latexindent/LatexIndent/Command.pm')
-rw-r--r-- | support/latexindent/LatexIndent/Command.pm | 215 |
1 files changed, 215 insertions, 0 deletions
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; |