summaryrefslogtreecommitdiff
path: root/support/latexindent/LatexIndent/LogFile.pm
blob: 763ca6e39e6f71d57c51dbe967dc421331a6a182 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
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");
        if (-t 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;