]> git.lyx.org Git - lyx.git/blobdiff - src/LaTeX.cpp
Fix text direction issue for InsetInfo in RTL context
[lyx.git] / src / LaTeX.cpp
index 8597e6db6062aa0758ad76cbcee3166a94060be0..0144e1cf166cdab2e6890d6ca82652724accf989 100644 (file)
@@ -58,7 +58,7 @@ docstring runMessage(unsigned int count)
        return bformat(_("Waiting for LaTeX run number %1$d"), count);
 }
 
-} // anon namespace
+} // namespace
 
 /*
  * CLASS TEXERRORS
@@ -93,9 +93,10 @@ bool operator!=(AuxInfo const & a, AuxInfo const & o)
  */
 
 LaTeX::LaTeX(string const & latex, OutputParams const & rp,
-            FileName const & f, string const & p, string const & lp,
-            bool const clean_start)
-       : cmd(latex), file(f), path(p), lpath(lp), runparams(rp), biber(false)
+            FileName const & f, string const & p, string const & lp, 
+            bool allow_cancellation, bool const clean_start)
+       : cmd(latex), file(f), path(p), lpath(lp), runparams(rp), biber(false),
+       allow_cancel(allow_cancellation)
 {
        num_errors = 0;
        // lualatex can still produce a DVI with --output-format=dvi. However,
@@ -244,12 +245,16 @@ int LaTeX::run(TeXErrors & terr)
        message(runMessage(count));
 
        int exit_code = startscript();
+       if (exit_code == Systemcall::KILLED)
+               return Systemcall::KILLED;
 
        scanres = scanLogFile(terr);
        if (scanres & ERROR_RERUN) {
                LYXERR(Debug::LATEX, "Rerunning LaTeX");
                terr.clearErrors();
                exit_code = startscript();
+               if (exit_code == Systemcall::KILLED)
+                       return Systemcall::KILLED;
                scanres = scanLogFile(terr);
        }
 
@@ -279,20 +284,34 @@ int LaTeX::run(TeXErrors & terr)
                LYXERR(Debug::LATEX, "Running MakeIndex.");
                message(_("Running Index Processor."));
                // onlyFileName() is needed for cygwin
-               rerun |= runMakeIndex(onlyFileName(idxfile.absFileName()),
-                               runparams);
+               int const ret = 
+                               runMakeIndex(onlyFileName(idxfile.absFileName()), runparams);
+               if (ret == Systemcall::KILLED)
+                       return Systemcall::KILLED;
+               rerun = true;
        }
+
        FileName const nlofile(changeExtension(file.absFileName(), ".nlo"));
        // If all nomencl entries are removed, nomencl writes an empty nlo file.
        // DepTable::hasChanged() returns false in this case, since it does not
        // distinguish empty files from non-existing files. This is why we need
        // the extra checks here (to trigger a rerun). Cf. discussions in #8905.
        // FIXME: Sort out the real problem in DepTable.
-       if (head.haschanged(nlofile) || (nlofile.exists() && nlofile.isFileEmpty()))
-               rerun |= runMakeIndexNomencl(file, ".nlo", ".nls");
+       if (head.haschanged(nlofile) || (nlofile.exists() && nlofile.isFileEmpty())) {
+               int const ret = runMakeIndexNomencl(file, ".nlo", ".nls");
+               if (ret == Systemcall::KILLED)
+                       return Systemcall::KILLED;
+               rerun = true;
+       }
+
        FileName const glofile(changeExtension(file.absFileName(), ".glo"));
-       if (head.haschanged(glofile))
-               rerun |= runMakeIndexNomencl(file, ".glo", ".gls");
+       if (head.haschanged(glofile)) {
+               int const ret = runMakeIndexNomencl(file, ".glo", ".gls");
+               if (ret)
+                       return ret;
+               rerun = true;
+       }
+
 
        // check if we're using biber instead of bibtex
        // biber writes no info to the aux file, so we just check
@@ -310,7 +329,10 @@ int LaTeX::run(TeXErrors & terr)
                LYXERR(Debug::LATEX, "Running BibTeX.");
                message(_("Running BibTeX."));
                updateBibtexDependencies(head, bibtex_info);
-               rerun |= runBibTeX(bibtex_info, runparams);
+               int exit_code;
+               rerun |= runBibTeX(bibtex_info, runparams, exit_code);
+               if (exit_code == Systemcall::KILLED)
+                       return Systemcall::KILLED;
                FileName const blgfile(changeExtension(file.absFileName(), ".blg"));
                if (blgfile.exists())
                        bscanres = scanBlgFile(head, terr);
@@ -339,7 +361,9 @@ int LaTeX::run(TeXErrors & terr)
                LYXERR(Debug::DEPEND, "Dep. file has changed or rerun requested");
                LYXERR(Debug::LATEX, "Run #" << count);
                message(runMessage(count));
-               startscript();
+               int exit_code = startscript();
+               if (exit_code == Systemcall::KILLED)
+                       return Systemcall::KILLED;
                scanres = scanLogFile(terr);
 
                // update the depedencies
@@ -348,7 +372,7 @@ int LaTeX::run(TeXErrors & terr)
        } else {
                LYXERR(Debug::DEPEND, "Dep. file has NOT changed");
        }
-       
+
        // 3
        // rerun bibtex?
        // Complex bibliography packages such as Biblatex require
@@ -361,7 +385,10 @@ int LaTeX::run(TeXErrors & terr)
                LYXERR(Debug::LATEX, "Running BibTeX.");
                message(_("Running BibTeX."));
                updateBibtexDependencies(head, bibtex_info);
-               rerun |= runBibTeX(bibtex_info, runparams);
+               int exit_code;
+               rerun |= runBibTeX(bibtex_info, runparams, exit_code);
+               if (exit_code == Systemcall::KILLED)
+                       return Systemcall::KILLED;
                FileName const blgfile(changeExtension(file.absFileName(), ".blg"));
                if (blgfile.exists())
                        bscanres = scanBlgFile(head, terr);
@@ -381,15 +408,18 @@ int LaTeX::run(TeXErrors & terr)
                LYXERR(Debug::LATEX, "Running MakeIndex.");
                message(_("Running Index Processor."));
                // onlyFileName() is needed for cygwin
-               rerun = runMakeIndex(onlyFileName(changeExtension(
+               int const ret = runMakeIndex(onlyFileName(changeExtension(
                                file.absFileName(), ".idx")), runparams);
+               if (ret == Systemcall::KILLED)
+                       return Systemcall::KILLED;
+               rerun = true;
        }
 
-       // I am not pretty sure if need this twice.
+       // MSVC complains that bool |= int is unsafe. Not sure why.
        if (head.haschanged(nlofile))
-               rerun |= runMakeIndexNomencl(file, ".nlo", ".nls");
+               rerun |= (runMakeIndexNomencl(file, ".nlo", ".nls") != 0);
        if (head.haschanged(glofile))
-               rerun |= runMakeIndexNomencl(file, ".glo", ".gls");
+               rerun |= (runMakeIndexNomencl(file, ".glo", ".gls") != 0);
 
        // 5
        // we will only run latex more if the log file asks for it.
@@ -442,25 +472,27 @@ int LaTeX::startscript()
                     + quoteName(onlyFileName(file.toFilesystemEncoding()))
                     + " > " + os::nulldev();
        Systemcall one;
-       return one.startscript(Systemcall::Wait, tmp, path, lpath);
+       Systemcall::Starttype const starttype = 
+               allow_cancel ? Systemcall::WaitLoop : Systemcall::Wait;
+       return one.startscript(starttype, tmp, path, lpath, true);
 }
 
 
-bool LaTeX::runMakeIndex(string const & f, OutputParams const & runparams,
+int LaTeX::runMakeIndex(string const & f, OutputParams const & rp,
                         string const & params)
 {
-       string tmp = runparams.use_japanese ?
+       string tmp = rp.use_japanese ?
                lyxrc.jindex_command : lyxrc.index_command;
-       
-       if (!runparams.index_command.empty())
-               tmp = runparams.index_command;
+
+       if (!rp.index_command.empty())
+               tmp = rp.index_command;
 
        LYXERR(Debug::LATEX,
                "idx file has been made, running index processor ("
                << tmp << ") on file " << f);
 
-       tmp = subst(tmp, "$$lang", runparams.document_language);
-       if (runparams.use_indices) {
+       tmp = subst(tmp, "$$lang", rp.document_language);
+       if (rp.use_indices) {
                tmp = lyxrc.splitindex_command + " -m " + quoteName(tmp);
                LYXERR(Debug::LATEX,
                "Multiple indices. Using splitindex command: " << tmp);
@@ -469,29 +501,31 @@ bool LaTeX::runMakeIndex(string const & f, OutputParams const & runparams,
        tmp += quoteName(f);
        tmp += params;
        Systemcall one;
-       one.startscript(Systemcall::Wait, tmp, path, lpath);
-       return true;
+       Systemcall::Starttype const starttype = 
+               allow_cancel ? Systemcall::WaitLoop : Systemcall::Wait;
+       return one.startscript(starttype, tmp, path, lpath, true);
 }
 
 
-bool LaTeX::runMakeIndexNomencl(FileName const & file,
+int LaTeX::runMakeIndexNomencl(FileName const & fname,
                string const & nlo, string const & nls)
 {
        LYXERR(Debug::LATEX, "Running MakeIndex for nomencl.");
        message(_("Running MakeIndex for nomencl."));
        string tmp = lyxrc.nomencl_command + ' ';
        // onlyFileName() is needed for cygwin
-       tmp += quoteName(onlyFileName(changeExtension(file.absFileName(), nlo)));
+       tmp += quoteName(onlyFileName(changeExtension(fname.absFileName(), nlo)));
        tmp += " -o "
-               + onlyFileName(changeExtension(file.toFilesystemEncoding(), nls));
+               + onlyFileName(changeExtension(fname.toFilesystemEncoding(), nls));
        Systemcall one;
-       one.startscript(Systemcall::Wait, tmp, path, lpath);
-       return true;
+       Systemcall::Starttype const starttype = 
+               allow_cancel ? Systemcall::WaitLoop : Systemcall::Wait;
+       return one.startscript(starttype, tmp, path, lpath, true);
 }
 
 
 vector<AuxInfo> const
-LaTeX::scanAuxFiles(FileName const & file, bool const only_childbibs)
+LaTeX::scanAuxFiles(FileName const & fname, bool const only_childbibs)
 {
        vector<AuxInfo> result;
 
@@ -500,7 +534,7 @@ LaTeX::scanAuxFiles(FileName const & file, bool const only_childbibs)
        if (only_childbibs) {
                for (string const &s: children) {
                        FileName fn =
-                               makeAbsPath(s, file.onlyPath().realPath());
+                               makeAbsPath(s, fname.onlyPath().realPath());
                        fn.changeExtension("aux");
                        if (fn.exists())
                                result.push_back(scanAuxFile(fn));
@@ -508,10 +542,10 @@ LaTeX::scanAuxFiles(FileName const & file, bool const only_childbibs)
                return result;
        }
 
-       result.push_back(scanAuxFile(file));
+       result.push_back(scanAuxFile(fname));
 
        // This is for bibtopic
-       string const basename = removeExtension(file.absFileName());
+       string const basename = removeExtension(fname.absFileName());
        for (int i = 1; i < 1000; ++i) {
                FileName const file2(basename
                        + '.' + convert<string>(i)
@@ -524,20 +558,20 @@ LaTeX::scanAuxFiles(FileName const & file, bool const only_childbibs)
 }
 
 
-AuxInfo const LaTeX::scanAuxFile(FileName const & file)
+AuxInfo const LaTeX::scanAuxFile(FileName const & fname)
 {
        AuxInfo result;
-       result.aux_file = file;
-       scanAuxFile(file, result);
+       result.aux_file = fname;
+       scanAuxFile(fname, result);
        return result;
 }
 
 
-void LaTeX::scanAuxFile(FileName const & file, AuxInfo & aux_info)
+void LaTeX::scanAuxFile(FileName const & fname, AuxInfo & aux_info)
 {
-       LYXERR(Debug::LATEX, "Scanning aux file: " << file);
+       LYXERR(Debug::LATEX, "Scanning aux file: " << fname);
 
-       ifstream ifs(file.toFilesystemEncoding().c_str());
+       ifstream ifs(fname.toFilesystemEncoding().c_str());
        string token;
        static regex const reg1("\\\\citation\\{([^}]+)\\}");
        static regex const reg2("\\\\bibdata\\{([^}]+)\\}");
@@ -620,22 +654,28 @@ void LaTeX::updateBibtexDependencies(DepTable & dep,
 
 
 bool LaTeX::runBibTeX(vector<AuxInfo> const & bibtex_info,
-                     OutputParams const & runparams)
+                     OutputParams const & rp, int & exit_code)
 {
        bool result = false;
+       exit_code = 0;
        for (vector<AuxInfo>::const_iterator it = bibtex_info.begin();
             it != bibtex_info.end(); ++it) {
                if (!biber && it->databases.empty())
                        continue;
                result = true;
 
-               string tmp = runparams.bibtex_command;
+               string tmp = rp.bibtex_command;
                tmp += " ";
                // onlyFileName() is needed for cygwin
                tmp += quoteName(onlyFileName(removeExtension(
                                it->aux_file.absFileName())));
                Systemcall one;
-               one.startscript(Systemcall::Wait, tmp, path, lpath);
+               Systemcall::Starttype const starttype = 
+               allow_cancel ? Systemcall::WaitLoop : Systemcall::Wait;
+               exit_code = one.startscript(starttype, tmp, path, lpath, true);
+               if (exit_code) {
+                       return result;
+               }
        }
        // Return whether bibtex was run
        return result;
@@ -651,10 +691,13 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                onlyFileName(changeExtension(file.absFileName(), ".log"));
        LYXERR(Debug::LATEX, "Log file: " << tmp);
        FileName const fn = FileName(makeAbsPath(tmp));
+       // FIXME we should use an ifdocstream here and a docstring for token
+       // below. The encoding of the log file depends on the _output_ (font)
+       // encoding of the TeX file (T1, TU etc.). See #10728.
        ifstream ifs(fn.toFilesystemEncoding().c_str());
        bool fle_style = false;
        static regex const file_line_error(".+\\.\\D+:[0-9]+: (.+)");
-       static regex const child_file(".*([0-9]+[A-Za-z]*_.+\\.tex).*");
+       static regex const child_file("[^0-9]*([0-9]+[A-Za-z]*_.+\\.tex).*");
        // Flag for 'File ended while scanning' message.
        // We need to wait for subsequent processing.
        string wait_for_error;
@@ -689,8 +732,12 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                string const substr = token.substr(i + 1, len);
                                if (regex_match(substr, sub, child_file)) {
                                        string const name = sub.str(1);
-                                       child.push(make_pair(name, pnest));
-                                       children.push_back(name);
+                                       // Sometimes also masters have a name that matches
+                                       // (if their name starts with a number and _)
+                                       if (name != file.onlyFileName()) {
+                                               child.push(make_pair(name, pnest));
+                                               children.push_back(name);
+                                       }
                                        i += len;
                                }
                        } else if (token[i] == ')') {
@@ -825,13 +872,12 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                } while (!contains(tmp, "(job aborted"));
 
                                terr.insertError(0,
-                                                from_local8bit("Emergency stop"),
+                                                from_ascii("Emergency stop"),
                                                 from_local8bit(errstr),
                                                 child_name);
                        }
 
                        // get the next line
-                       string tmp;
                        int count = 0;
                        do {
                                if (!getline(ifs, tmp))
@@ -924,7 +970,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                // !pdfTeX error: pdflatex (file feyn10): Font feyn10 at 600 not found
                                retval |= ERRORS;
                                terr.insertError(0,
-                                                from_local8bit("pdfTeX Error"),
+                                                from_ascii("pdfTeX Error"),
                                                 from_local8bit(token),
                                                 child_name);
                        } else if (!ignore_missing_glyphs
@@ -933,11 +979,18 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                // Warning about missing glyph in selected font
                                // may be dataloss (bug 9610)
                                // but can be ignored for 'nullfont' (bug 10394).
-                               retval |= LATEX_ERROR;
-                               terr.insertError(0,
-                                                from_local8bit("Missing glyphs!"),
-                                                from_local8bit(token),
-                                                child_name);
+                               // as well as for ZERO WIDTH NON-JOINER (0x200C) which is
+                               // missing in many fonts and output for ligature break (bug 10727).
+                               // Since this error only occurs with utf8 output, we can safely assume
+                               // that the log file is utf8-encoded
+                               docstring const utoken = from_utf8(token);
+                               if (!contains(utoken, 0x200C)) {
+                                       retval |= LATEX_ERROR;
+                                       terr.insertError(0,
+                                                        from_ascii("Missing glyphs!"),
+                                                        utoken,
+                                                        child_name);
+                               }
                        } else if (!wait_for_error.empty()) {
                                // We collect information until we know we have an error.
                                wait_for_error += token + '\n';
@@ -1067,8 +1120,8 @@ bool completeFilename(string const & ff, DepTable & head)
 }
 
 
-int iterateLine(string const & token, regex const & reg, string const & closing,
-               int fragment_pos, DepTable & head)
+int iterateLine(string const & token, regex const & reg, string const & opening,
+               string const & closing, int fragment_pos, DepTable & head)
 {
        smatch what;
        string::const_iterator first = token.begin();
@@ -1085,6 +1138,15 @@ int iterateLine(string const & token, regex const & reg, string const & closing,
                                // since we had a closing bracket,
                                // do not investigate further
                                fragment = false;
+                       } else if (what.str(2) == opening) {
+                               // if we have another opening bracket,
+                               // we might have a nested file chain
+                               // as is (file.ext (subfile.ext))
+                               fragment = !handleFoundFile(rtrim(what.str(1)), head);
+                               // decrease first position by one in order to
+                               // consider the opening delimiter on next iteration
+                               if (first > token.begin())
+                                       --first;
                        } else
                                // if we have no closing bracket,
                                // try to handle as file nevertheless
@@ -1129,7 +1191,7 @@ int iterateLine(string const & token, regex const & reg, string const & closing,
        return result;
 }
 
-} // anon namespace
+} // namespace
 
 
 void LaTeX::deplog(DepTable & head)
@@ -1268,7 +1330,7 @@ void LaTeX::deplog(DepTable & head)
                if (regex_match(token, sub, reg5)) {
                        // search for strings in <...>
                        static regex const reg5_1("<([^>]+)(.)");
-                       fragment_pos = iterateLine(token, reg5_1, ">",
+                       fragment_pos = iterateLine(token, reg5_1, "<", ">",
                                                   fragment_pos, head);
                        fragment = (fragment_pos != -1);
                }
@@ -1281,7 +1343,7 @@ void LaTeX::deplog(DepTable & head)
                if (regex_match(token, sub, reg6)) {
                        // search for strings in (...)
                        static regex const reg6_1("\\(([^()]+)(.)");
-                       fragment_pos = iterateLine(token, reg6_1, ")",
+                       fragment_pos = iterateLine(token, reg6_1, "(", ")",
                                                   fragment_pos, head);
                        fragment = (fragment_pos != -1);
                }
@@ -1336,32 +1398,32 @@ int LaTeX::scanBlgFile(DepTable & dep, TeXErrors & terr)
                         || regex_match(token, sub, bibtexError5)) {
                        retval |= BIBTEX_ERROR;
                        string errstr = N_("BibTeX error: ") + token;
-                       string message;
+                       string msg;
                        if ((prefixIs(token, "while executing---line")
                             || prefixIs(token, "---line ")
                             || prefixIs(token, "*Please notify the BibTeX"))
                            && !prevtoken.empty()) {
                                errstr = N_("BibTeX error: ") + prevtoken;
-                               message = prevtoken + '\n';
+                               msg = prevtoken + '\n';
                        }
-                       message += token;
+                       msg += token;
                        terr.insertError(0,
                                         from_local8bit(errstr),
-                                        from_local8bit(message));
+                                        from_local8bit(msg));
                } else if (regex_match(prevtoken, sub, bibtexError3)) {
                        retval |= BIBTEX_ERROR;
                        string errstr = N_("BibTeX error: ") + prevtoken;
-                       string message = prevtoken + '\n' + token;
+                       string msg = prevtoken + '\n' + token;
                        terr.insertError(0,
                                         from_local8bit(errstr),
-                                        from_local8bit(message));
+                                        from_local8bit(msg));
                } else if (regex_match(token, sub, biberError)) {
                        retval |= BIBTEX_ERROR;
                        string errstr = N_("Biber error: ") + sub.str(2);
-                       string message = token;
+                       string msg = token;
                        terr.insertError(0,
                                         from_local8bit(errstr),
-                                        from_local8bit(message));
+                                        from_local8bit(msg));
                }
                prevtoken = token;
        }