// TeXworksScript
// Title: LaTeX errors
// Description: Looks for errors in the LaTeX terminal output
// Author: Jonathan Kew & Stefan Löffler
// Modified by Henrik Skov Midtiby
// Version: 0.5
// Date: 2011-11-13
// Script-Type: hook
// Hook: AfterTypeset
// This is just a simple proof-of-concept; it will often get filenames wrong, for example.
// Switching the engines to use the FILE:LINE-style error messages could help a lot.
// The script will handle long filenames better
// with the following change of the environment
// (such that latex does not wrap long lines)
//
// Add the line
// max_print_line=150
// to the file
// C:\Users\hemi\AppData\Roaming\MiKTeX\2.9\miktex\config\pdflatex.ini
//
// The file can also be reached by the command
// initexmf.exe --edit-config-file=pdflatex
//
// Inspiration from http://tex.stackexchange.com/a/1193/1366 and
// http://docs.miktex.org/2.9/manual/runtimeparams.html
function LatexErrorAnalyzer() {
var obj = {};
obj.analyzeLog = function()
{
obj.initializeParameters();
obj.getLinesToAnalyze();
obj.analyzeGatheredLines();
obj.suggestToDeleteAuxFilesIfSpecificErrorIsSeen();
obj.showFormattedOutput();
}
obj.initializeParameters = function()
{
this.parenRE = new RegExp("[()]");
// Should catch filenames of the following forms:
// * ./abc, "./abc"
// * /abc, "/abc"
// * .\abc, ".\abc"
// * C:\abc, "C:\abc"
// * \\server\abc, "\\server\abc"
// Caveats: filenames with escaped " or space in the filename don't work (correctly)
this.newFileRE = new RegExp("^\\(\"?((?:\\./|/|.\\\\|[a-zA-Z]:\\\\|\\\\\\\\[^\\\" )]+\\\\)[^\" )]+)");
this.lineNumRE = new RegExp("^l\\.(\\d+)");
this.badLineRE = new RegExp("^(?:Over|Under)full \\\\hbox.*at lines (\\d+)");
this.warnLineRE = new RegExp("^(?:LaTeX|Package (?:.*)) Warning: .*");
this.warnLineNumRE = new RegExp("on input line (\\d+).");
this.latexmkApplyingRule = new RegExp("Latexmk: applying rule \'(.*)\'");
this.errors = [];
this.warnings = [];
this.infos = [];
this.curFile = undefined;
this.filenames = [];
this.extraParens = 0;
}
obj.getLinesToAnalyze = function()
{
// get the text from the standard console output
txt = TW.target.consoleOutput;
this.lines = txt.split('\n');
}
obj.analyzeGatheredLines = function()
{
for (i = 0; i < this.lines.length; ++i) {
line = this.lines[i];
// check for error messages
if (line.match("^! ")) {
this.addErrorFromLine(line);
continue;
}
// check for over- or underfull lines
matched = this.badLineRE.exec(line);
if (matched) {
this.addInfoFromLine(line);
continue;
}
// check for other warnings
matched = this.warnLineRE.exec(line);
if (matched) {
this.checkForOtherWarnings(line);
continue;
}
this.trackBeginningEndingOfInputFiles(line);
this.checkForRerunOfLatex(line);
}
}
obj.addErrorFromLine = function(line)
{
var error = [];
// record the current input file
error[0] = this.curFile;
// record the error message itself
error[2] = line;
// look ahead for the line number and record that
error[1] = 0;
while (++i < this.lines.length) {
line = this.lines[i];
if(trim(line) == '') break;
matched = this.lineNumRE.exec(line);
if (matched)
error[1] = matched[1];
error[2] += "\n" + line;
}
this.errors.push(error);
}
function trim (zeichenkette) {
return zeichenkette.replace (/^\s+/, '').replace (/\s+$/, '');
}
obj.addInfoFromLine = function(line)
{
var error = [];
error[0] = this.curFile;
error[1] = matched[1];
error[2] = line;
this.infos.push(error);
}
obj.checkForOtherWarnings = function(line)
{
var error = [];
error[0] = this.curFile;
error[1] = "?";
error[2] = line;
while (++i < this.lines.length) {
line = this.lines[i];
if(line == '') break;
error[2] += "\n" + line;
}
matched = this.warnLineNumRE.exec(error[2].replace(/\n/, ""));
if (matched)
error[1] = matched[1];
this.warnings.push(error);
}
obj.trackBeginningEndingOfInputFiles = function(line)
{
// try to track beginning/ending of input files (flaky!)
pos = line.search(this.parenRE);
while (pos >= 0) {
line = line.slice(pos);
if (line.charAt(0) == ")") {
if (this.extraParens > 0) {
--this.extraParens;
}
else if (this.filenames.length > 0) {
this.curFile = this.filenames.pop();
}
line = line.slice(1);
}
else {
match = this.newFileRE.exec(line);
if (match) {
this.filenames.push(this.curFile);
this.curFile = match[1];
line = line.slice(match[0].length);
this.extraParens = 0;
}
else {
++this.extraParens;
line = line.slice(1);
}
}
if (line == undefined) {
break;
}
pos = line.search(this.parenRE);
}
}
obj.checkForRerunOfLatex = function(line) {
matched = this.latexmkApplyingRule.exec(line);
if(matched)
{
this.resetWarningsInfosAndErrors();
}
}
obj.resetWarningsInfosAndErrors = function() {
this.warnings.length = 0;
this.infos.length = 0;
this.errors.length = 0;
}
function htmlize(str) {
var html = str;
html = html.replace(/&/g, "&");
html = html.replace(//g, ">");
html = html.replace(/\n /g, "\n ");
html = html.replace(/ /g, " ");
html = html.replace(/ /g, " ");
return html.replace(/\n/g, "
\n");
}
function makeResultRow(data, color) {
var html = '';
var url = 'texworks:' + data[0] + (data[1] != '?' && data[1] != 0 ? '#' + data[1] : '');
html += '