On Thu, Jun 06, 2019 at 03:42:05PM +0200, Pavel Sanda wrote: > Looks little bit difficult within the current machinery (if I understand > it correctly). Cits can be fixed by incremental runs and we see that in > updated result value of scanres of LaTeX::run, i.e. if fixed it does not > contain UNDEF_CIT anymore. > The accompanying structure of errors "terr" does not get reset, so once > you push there some info about missing citation it's not going away. > At the end if you by re-runing fix citation problem but there still remain > some other problem user will wrongly see it within the list of errors... > > I actually do not understand why not reseting "ter" before each run. > Seems reasonable to me, but it's hard to test without having examples > which produced all the trickery in the code. > Otherwise we could just grep in scanLog for the label/citation name > and push it to the error dialog.
Ok this is result of todays hacking, ref/cits will get proper information in error dialog as well. Many citations won't make it because pdflatex splits line at 80 chars and line-based parsing will fail. I tested plain bibtex & natbib, I don't use the other engines so have very little clue what happens there. Pavel
diff --git a/src/Buffer.cpp b/src/Buffer.cpp index c995f825f5..41d2cc9aad 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -4930,6 +4930,42 @@ void Buffer::bufferErrors(TeXErrors const & terr, ErrorList & errorList) const } +void Buffer::bufferRefs(TeXErrors const & terr, ErrorList & errorList) const +{ + TeXErrors::Errors::const_iterator err = terr.begin_ref(); + TeXErrors::Errors::const_iterator end = terr.end_ref(); + + for (; err != end; ++err) { + TexRow::TextEntry start = TexRow::text_none, end = TexRow::text_none; + int errorRow = err->error_in_line; + Buffer const * buf = 0; + Impl const * p = d; + if (err->child_name.empty()) + tie(start, end) = p->texrow.getEntriesFromRow(errorRow); + else { + // The error occurred in a child + for (Buffer const * child : getDescendents()) { + string const child_name = + DocFileName(changeExtension(child->absFileName(), "tex")). + mangledFileName(); + if (err->child_name != child_name) + continue; + tie(start, end) = child->d->texrow.getEntriesFromRow(errorRow); + if (!TexRow::isNone(start)) { + buf = d->cloned_buffer_ + ? child->d->cloned_buffer_->d->owner_ + : child->d->owner_; + p = child->d; + break; + } + } + } + errorList.push_back(ErrorItem(err->error_desc, err->error_text, + start, end, buf)); + } +} + + void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const { LBUFERR(!text().paragraphs().empty()); diff --git a/src/Buffer.h b/src/Buffer.h index f1bd1f5e79..7ba3262775 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -287,6 +287,7 @@ private: public: /// Fill in the ErrorList with the TeXErrors void bufferErrors(TeXErrors const &, ErrorList &) const; + void bufferRefs(TeXErrors const &, ErrorList &) const; enum OutputWhat { FullSource, diff --git a/src/Converter.cpp b/src/Converter.cpp index 8c22b1c42a..4dab2413db 100644 --- a/src/Converter.cpp +++ b/src/Converter.cpp @@ -881,6 +881,14 @@ Converters::RetVal Converters::runLaTeX(Buffer const & buffer, string const & co if (result & LaTeX::ERRORS) buffer.bufferErrors(terr, errorList); + if ((result & LaTeX::UNDEF_CIT) || (result & LaTeX::UNDEF_REF)) { + buffer.bufferRefs(terr, errorList); + if (errorList.empty()) + errorList.push_back(ErrorItem(_("Undefined reference"), + _("Undefined reference or citation was found during the build, please check the Log."), + &buffer)); + } + if (!errorList.empty()) { // We will show the LaTeX Errors GUI later which contains // specific error messages so it would be repetitive to give @@ -909,6 +917,8 @@ Converters::RetVal Converters::runLaTeX(Buffer const & buffer, string const & co int const ERROR_MASK = LaTeX::NO_LOGFILE | LaTeX::ERRORS | + LaTeX::UNDEF_CIT | + LaTeX::UNDEF_REF | LaTeX::NO_OUTPUT; return (result & ERROR_MASK) == 0 ? SUCCESS : FAILURE; diff --git a/src/LaTeX.cpp b/src/LaTeX.cpp index 0144e1cf16..ffbba14e8a 100644 --- a/src/LaTeX.cpp +++ b/src/LaTeX.cpp @@ -73,6 +73,15 @@ void TeXErrors::insertError(int line, docstring const & error_desc, } +void TeXErrors::insertRef(int line, docstring const & error_desc, + docstring const & error_text, + string const & child_name) +{ + Error newerr(line, error_desc, error_text, child_name); + undef_ref.push_back(newerr); +} + + bool operator==(AuxInfo const & a, AuxInfo const & o) { return a.aux_file == o.aux_file @@ -682,6 +691,14 @@ bool LaTeX::runBibTeX(vector<AuxInfo> const & bibtex_info, } +//helper func for scanLogFile; gets line number X from strings "... on input line X ..." +//returns 0 if none is found +int getLineNumber(const string &token){ + string l = support::token(token, ' ', tokenPos(token,' ',"line") + 1); + return l.empty() ? 0 : convert<int>(l); +} + + int LaTeX::scanLogFile(TeXErrors & terr) { int last_line = -1; @@ -706,6 +723,8 @@ int LaTeX::scanLogFile(TeXErrors & terr) stack <pair<string, int> > child; children.clear(); + terr.clearRefs(); + string token; while (getline(ifs, token)) { // MikTeX sometimes inserts \0 in the log file. They can't be @@ -752,6 +771,12 @@ int LaTeX::scanLogFile(TeXErrors & terr) if (contains(token, "file:line:error style messages enabled")) fle_style = true; + //Handles both "LaTeX Warning:" & "Package natbib Warning:" + //Various handlers for missing citations below won't catch the problem if citation + //key is long (>~25chars), because pdflatex splits output at line length 80. + if (contains(token, "There were undefined citations.")) + retval |= UNDEF_CIT; + if (prefixIs(token, "LaTeX Warning:") || prefixIs(token, "! pdfTeX warning")) { // Here shall we handle different @@ -771,15 +796,28 @@ int LaTeX::scanLogFile(TeXErrors & terr) } else if (contains(token, "Etaremune labels have changed")) { retval |= ERROR_RERUN; LYXERR(Debug::LATEX, "Force rerun."); + //"Citation `cit' on page X undefined on input line X." } else if (contains(token, "Citation") - && contains(token, "on page") + //&& contains(token, "on input line") //often split to newline && contains(token, "undefined")) { retval |= UNDEF_CIT; - } else if (contains(token, "Citation") - && contains(token, "on input line") + terr.insertRef(getLineNumber(token), from_ascii("Citation undefined"), + from_utf8(token), child_name); + //"Reference `X' on page Y undefined on input line Z." + } else if (contains(token, "Reference") + //&& contains(token, "on input line")) //often split to new line && contains(token, "undefined")) { - retval |= UNDEF_CIT; + retval |= UNDEF_REF; + terr.insertRef(getLineNumber(token), from_ascii("Reference undefined"), + from_utf8(token), child_name); + + //If label is too long pdlaftex log line splitting will make the above fail + //so we catch at least this generic statement occuring for both CIT & REF. + } else if (contains(token, "There were undefined references.")) { + if (!(retval & UNDEF_CIT)) //if handled already + retval |= UNDEF_REF; } + } else if (prefixIs(token, "Package")) { // Package warnings retval |= PACKAGE_WARNING; @@ -789,6 +827,9 @@ int LaTeX::scanLogFile(TeXErrors & terr) && contains(token, "on page") && contains(token, "undefined")) { retval |= UNDEF_CIT; + //Unf only keys up to ~6 chars will make it due to line splits + terr.insertRef(getLineNumber(token), from_ascii("Citation undefined"), + from_utf8(token), child_name); } } else if (contains(token, "run BibTeX")) { retval |= UNDEF_CIT; diff --git a/src/LaTeX.h b/src/LaTeX.h index a57cebc83b..ba088bb5cc 100644 --- a/src/LaTeX.h +++ b/src/LaTeX.h @@ -60,14 +60,26 @@ public: /// Errors::const_iterator end() const { return errors.end(); } /// + Errors::const_iterator begin_ref() const { return undef_ref.begin(); } + /// + Errors::const_iterator end_ref() const { return undef_ref.end(); } + /// void insertError(int line, docstring const & error_desc, docstring const & error_text, std::string const & child_name = empty_string()); /// void clearErrors() { errors.clear(); } + /// + void insertRef(int line, docstring const & error_desc, + docstring const & error_text, + std::string const & child_name = empty_string()); + /// + void clearRefs() { undef_ref.clear(); } private: /// Errors errors; + /// For missing Citation and references + Errors undef_ref; };