X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=74d5ac8deb428621552f968fb5e24fd25b339aac;hb=6b095e2b7107110bec593edd02bbdcf25adae76a;hp=294c7a1092ee5a03151f6cca1cfc81f6da28f9ec;hpb=6c6cf5e07136fd1b74c19ef142cf18e1f3723de7;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 294c7a1092..74d5ac8deb 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -1075,8 +1075,7 @@ bool Buffer::importString(string const & format, docstring const & contents, Err return false; // It is important to use the correct extension here, since some // converters create a wrong output file otherwise (e.g. html2latex) - TempFile const tempfile("Buffer_importStringXXXXXX." + fmt->extension()); - FileName const name(tempfile.name()); + FileName const name = tempFileName("Buffer_importStringXXXXXX." + fmt->extension()); ofdocstream os(name.toFilesystemEncoding().c_str()); // Do not convert os implicitly to bool, since that is forbidden in C++11. bool const success = !(os << contents).fail(); @@ -1092,8 +1091,7 @@ bool Buffer::importString(string const & format, docstring const & contents, Err converted = importFile(format, name, errorList); } - if (name.exists()) - name.removeFile(); + removeTempFile(name); return converted; } @@ -1103,10 +1101,14 @@ bool Buffer::importFile(string const & format, FileName const & name, ErrorList if (!theConverters().isReachable(format, "lyx")) return false; - TempFile const tempfile("Buffer_importFileXXXXXX.lyx"); - FileName const lyx(tempfile.name()); - if (theConverters().convert(0, name, lyx, name, format, "lyx", errorList)) - return readFile(lyx) == ReadSuccess; + FileName const lyx = tempFileName("Buffer_importFileXXXXXX.lyx"); + Converters::RetVal const retval = + theConverters().convert(0, name, lyx, name, format, "lyx", errorList); + if (retval == Converters::SUCCESS) { + bool const success = readFile(lyx) == ReadSuccess; + removeTempFile(lyx); + return success; + } return false; } @@ -1658,7 +1660,7 @@ bool Buffer::write(ostream & ofs) const } -bool Buffer::makeLaTeXFile(FileName const & fname, +Buffer::ExportStatus Buffer::makeLaTeXFile(FileName const & fname, string const & original_path, OutputParams const & runparams_in, OutputWhat output) const @@ -1682,14 +1684,14 @@ bool Buffer::makeLaTeXFile(FileName const & fname, Alert::error(_("Iconv software exception Detected"), bformat(_("Please " "verify that the support software for your encoding (%1$s) is " "properly installed"), from_ascii(encoding))); - return false; + return ExportError; } if (!openFileWrite(ofs, fname)) - return false; + return ExportError; ErrorList & errorList = d->errorLists["Export"]; errorList.clear(); - bool failed_export = false; + ExportStatus status = ExportSuccess; otexstream os(ofs); // make sure we are ready to export @@ -1699,32 +1701,45 @@ bool Buffer::makeLaTeXFile(FileName const & fname, updateBuffer(); updateMacroInstances(OutputUpdate); + ExportStatus retval; try { - writeLaTeXSource(os, original_path, runparams, output); + retval = writeLaTeXSource(os, original_path, runparams, output); + if (retval == ExportKilled) + return ExportKilled; } catch (EncodingException const & e) { docstring const failed(1, e.failed_char); ostringstream oss; oss << "0x" << hex << e.failed_char << dec; - docstring msg = bformat(_("Could not find LaTeX command for character '%1$s'" - " (code point %2$s)"), - failed, from_utf8(oss.str())); - errorList.push_back(ErrorItem(msg, _("Some characters of your document are probably not " - "representable in the chosen encoding.\n" - "Changing the document encoding to utf8 could help."), - {e.par_id, e.pos}, {e.par_id, e.pos + 1})); - failed_export = true; + if (getParFromID(e.par_id).paragraph().layout().pass_thru) { + docstring msg = bformat(_("Uncodable character '%1$s'" + " (code point %2$s)"), + failed, from_utf8(oss.str())); + errorList.push_back(ErrorItem(msg, _("Some characters of your document are not " + "representable in specific verbatim contexts.\n" + "Changing the document encoding to utf8 could help."), + {e.par_id, e.pos}, {e.par_id, e.pos + 1})); + } else { + docstring msg = bformat(_("Could not find LaTeX command for character '%1$s'" + " (code point %2$s)"), + failed, from_utf8(oss.str())); + errorList.push_back(ErrorItem(msg, _("Some characters of your document are probably not " + "representable in the chosen encoding.\n" + "Changing the document encoding to utf8 could help."), + {e.par_id, e.pos}, {e.par_id, e.pos + 1})); + } + status = ExportError; } catch (iconv_codecvt_facet_exception const & e) { errorList.push_back(ErrorItem(_("iconv conversion failed"), _(e.what()))); - failed_export = true; + status = ExportError; } catch (exception const & e) { errorList.push_back(ErrorItem(_("conversion failed"), _(e.what()))); lyxerr << e.what() << endl; - failed_export = true; + status = ExportError; } catch (...) { lyxerr << "Caught some really weird exception..." << endl; @@ -1735,7 +1750,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname, ofs.close(); if (ofs.fail()) { - failed_export = true; + status = ExportError; lyxerr << "File '" << fname << "' was not closed properly." << endl; } @@ -1743,11 +1758,11 @@ bool Buffer::makeLaTeXFile(FileName const & fname, errorList.clear(); else errors("Export"); - return !failed_export; + return status; } -void Buffer::writeLaTeXSource(otexstream & os, +Buffer::ExportStatus Buffer::writeLaTeXSource(otexstream & os, string const & original_path, OutputParams const & runparams_in, OutputWhat output) const @@ -1766,6 +1781,9 @@ void Buffer::writeLaTeXSource(otexstream & os, // (or not reached) and characters encodable in the current // encoding are not converted to ASCII-representation. + // Some macros rely on font encoding + runparams.main_fontenc = params().main_font_encoding(); + // If we are compiling a file standalone, even if this is the // child of some other buffer, let's cut the link here, so the // file is really independent and no concurring settings from @@ -1941,7 +1959,7 @@ void Buffer::writeLaTeXSource(otexstream & os, // Restore the parenthood if needed if (!runparams.is_child) d->ignore_parent = false; - return; + return ExportSuccess; } // make the body. @@ -1964,7 +1982,10 @@ void Buffer::writeLaTeXSource(otexstream & os, LYXERR(Debug::INFO, "preamble finished, now the body."); // the real stuff - latexParagraphs(*this, text(), os, runparams); + try { + latexParagraphs(*this, text(), os, runparams); + } + catch (ConversionException const &) { return ExportKilled; } // Restore the parenthood if needed if (!runparams.is_child) @@ -1983,10 +2004,11 @@ void Buffer::writeLaTeXSource(otexstream & os, LYXERR(Debug::INFO, "Finished making LaTeX file."); LYXERR(Debug::INFO, "Row count was " << os.texrow().rows() - 1 << '.'); + return ExportSuccess; } -void Buffer::makeDocBookFile(FileName const & fname, +Buffer::ExportStatus Buffer::makeDocBookFile(FileName const & fname, OutputParams const & runparams, OutputWhat output) const { @@ -1994,22 +2016,26 @@ void Buffer::makeDocBookFile(FileName const & fname, ofdocstream ofs; if (!openFileWrite(ofs, fname)) - return; + return ExportError; // make sure we are ready to export // this needs to be done before we validate updateBuffer(); updateMacroInstances(OutputUpdate); - writeDocBookSource(ofs, fname.absFileName(), runparams, output); + ExportStatus const retval = + writeDocBookSource(ofs, fname.absFileName(), runparams, output); + if (retval == ExportKilled) + return ExportKilled; ofs.close(); if (ofs.fail()) lyxerr << "File '" << fname << "' was not closed properly." << endl; + return ExportSuccess; } -void Buffer::writeDocBookSource(odocstream & os, string const & fname, +Buffer::ExportStatus Buffer::writeDocBookSource(odocstream & os, string const & fname, OutputParams const & runparams, OutputWhat output) const { @@ -2083,35 +2109,42 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, sgml::openTag(os, top); os << '\n'; - docbookParagraphs(text(), *this, os, runparams); + try { + docbookParagraphs(text(), *this, os, runparams); + } + catch (ConversionException const &) { return ExportKilled; } sgml::closeTag(os, top_element); } + return ExportSuccess; } -void Buffer::makeLyXHTMLFile(FileName const & fname, +Buffer::ExportStatus Buffer::makeLyXHTMLFile(FileName const & fname, OutputParams const & runparams) const { LYXERR(Debug::LATEX, "makeLyXHTMLFile..."); ofdocstream ofs; if (!openFileWrite(ofs, fname)) - return; + return ExportError; // make sure we are ready to export // this has to be done before we validate updateBuffer(UpdateMaster, OutputUpdate); updateMacroInstances(OutputUpdate); - writeLyXHTMLSource(ofs, runparams, FullSource); + ExportStatus const retval = writeLyXHTMLSource(ofs, runparams, FullSource); + if (retval == ExportKilled) + return retval; ofs.close(); if (ofs.fail()) lyxerr << "File '" << fname << "' was not closed properly." << endl; + return retval; } -void Buffer::writeLyXHTMLSource(odocstream & os, +Buffer::ExportStatus Buffer::writeLyXHTMLSource(odocstream & os, OutputParams const & runparams, OutputWhat output) const { @@ -2212,13 +2245,18 @@ void Buffer::writeLyXHTMLSource(odocstream & os, if (output != IncludedFile) // if we're an included file, the counters are in the master. params().documentClass().counters().reset(); - xhtmlParagraphs(text(), *this, xs, runparams); + try { + xhtmlParagraphs(text(), *this, xs, runparams); + } + catch (ConversionException const &) { return ExportKilled; } if (output_body_tag) os << "\n"; } if (output_preamble) os << "\n"; + + return ExportSuccess; } @@ -2241,7 +2279,12 @@ int Buffer::runChktex() runparams.flavor = OutputParams::LATEX; runparams.nice = false; runparams.linelen = lyxrc.plaintext_linelen; - makeLaTeXFile(FileName(name), org_path, runparams); + ExportStatus const retval = + makeLaTeXFile(FileName(name), org_path, runparams); + if (retval != ExportSuccess) { + // error code on failure + return -1; + } TeXErrors terr; Chktex chktex(lyxrc.chktex_command, onlyFileName(name), filePath()); @@ -2333,10 +2376,19 @@ BiblioInfo const & Buffer::masterBibInfo() const } +BiblioInfo const & Buffer::bibInfo() const +{ + return d->bibinfo_; +} + + void Buffer::registerBibfiles(FileNamePairList const & bf) const { + // We register the bib files in the master buffer, + // if there is one, but also in every single buffer, + // in case a child is compiled alone. Buffer const * const tmp = masterBuffer(); if (tmp != this) - return tmp->registerBibfiles(bf); + tmp->registerBibfiles(bf); for (auto const & p : bf) { FileNamePairList::const_iterator temp = @@ -2405,21 +2457,33 @@ void Buffer::collectBibKeys(FileNameList & checkedFiles) const } -void Buffer::addBiblioInfo(BiblioInfo const & bi) const +void Buffer::addBiblioInfo(BiblioInfo const & bin) const { - Buffer const * tmp = masterBuffer(); - BiblioInfo & masterbi = (tmp == this) ? - d->bibinfo_ : tmp->d->bibinfo_; - masterbi.mergeBiblioInfo(bi); + // We add the biblio info to the master buffer, + // if there is one, but also to every single buffer, + // in case a child is compiled alone. + BiblioInfo & bi = d->bibinfo_; + bi.mergeBiblioInfo(bin); + + if (parent() != 0) { + BiblioInfo & masterbi = parent()->d->bibinfo_; + masterbi.mergeBiblioInfo(bin); + } } -void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bi) const +void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bin) const { - Buffer const * tmp = masterBuffer(); - BiblioInfo & masterbi = (tmp == this) ? - d->bibinfo_ : tmp->d->bibinfo_; - masterbi[key] = bi; + // We add the bibtex info to the master buffer, + // if there is one, but also to every single buffer, + // in case a child is compiled alone. + BiblioInfo & bi = d->bibinfo_; + bi[key] = bin; + + if (parent() != 0) { + BiblioInfo & masterbi = parent()->d->bibinfo_; + masterbi[key] = bin; + } } @@ -2430,6 +2494,11 @@ void Buffer::makeCitationLabels() const } +void Buffer::invalidateCiteLabels() const +{ + masterBuffer()->d->cite_labels_valid_ = false; +} + bool Buffer::citeLabelsValid() const { return masterBuffer()->d->cite_labels_valid_; @@ -2513,10 +2582,6 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; } - case LFUN_BUFFER_CHKTEX: - enable = params().isLatex() && !lyxrc.chktex_command.empty(); - break; - case LFUN_BUILD_PROGRAM: enable = params().isExportable("program", false); break; @@ -2558,15 +2623,16 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setOnOff(params().output_changes); break; - case LFUN_BUFFER_TOGGLE_COMPRESSION: { + case LFUN_BUFFER_TOGGLE_COMPRESSION: flag.setOnOff(params().compressed); break; - } - case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: { + case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: flag.setOnOff(params().output_sync); break; - } + + case LFUN_BUFFER_ANONYMIZE: + break; default: return false; @@ -2629,10 +2695,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) break; } - case LFUN_BUFFER_CHKTEX: - runChktex(); - break; - case LFUN_BUFFER_EXPORT_CUSTOM: { string format_name; string command = split(argument, format_name, ' '); @@ -2842,6 +2904,15 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) params().output_sync = !params().output_sync; break; + case LFUN_BUFFER_ANONYMIZE: { + undo().recordUndoFullBuffer(CursorData()); + CursorData cur(doc_iterator_begin(this)); + for ( ; cur ; cur.forwardPar()) + cur.paragraph().anonymize(); + dr.forceBufferUpdate(); + break; + } + default: dispatched = false; break; @@ -3112,9 +3183,28 @@ vector const Buffer::prepareBibFilePaths(OutputParams const & runpara string utf8input = to_utf8(bit.first); string database = prepareFileNameForLaTeX(utf8input, ".bib", runparams.nice); - FileName const try_in_file = + FileName try_in_file = makeAbsPath(database + ".bib", filePath()); - bool const not_from_texmf = try_in_file.isReadableFile(); + bool not_from_texmf = try_in_file.isReadableFile(); + // If the file has not been found, try with the real file name + // (it might come from a child in a sub-directory) + if (!not_from_texmf) { + try_in_file = bit.second; + if (try_in_file.isReadableFile()) { + // Check if the file is in texmf + FileName kpsefile(findtexfile(changeExtension(utf8input, "bib"), "bib", true)); + not_from_texmf = kpsefile.empty() + || kpsefile.absFileName() != try_in_file.absFileName(); + if (not_from_texmf) + // If this exists, make path relative to the master + // FIXME Unicode + database = + removeExtension(prepareFileNameForLaTeX( + to_utf8(makeRelPath(from_utf8(try_in_file.absFileName()), + from_utf8(filePath()))), + ".bib", runparams.nice)); + } + } if (!runparams.inComment && !runparams.dryrun && !runparams.nice && not_from_texmf) { @@ -4210,6 +4300,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir return ExportNoPathToFormat; } runparams.flavor = converters.getFlavor(path, this); + runparams.hyperref_driver = converters.getHyperrefDriver(path); for (auto const & edge : path) if (theConverters().get(edge).nice()) { need_nice_file = true; @@ -4239,40 +4330,52 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir // Plain text backend if (backend_format == "text") { runparams.flavor = OutputParams::TEXT; - writePlaintextFile(*this, FileName(filename), runparams); + try { + writePlaintextFile(*this, FileName(filename), runparams); + } + catch (ConversionException const &) { return ExportCancel; } } // HTML backend else if (backend_format == "xhtml") { runparams.flavor = OutputParams::HTML; setMathFlavor(runparams); - makeLyXHTMLFile(FileName(filename), runparams); + if (makeLyXHTMLFile(FileName(filename), runparams) == ExportKilled) + return ExportKilled; } else if (backend_format == "lyx") writeFile(FileName(filename)); // Docbook backend else if (params().isDocBook()) { runparams.nice = !put_in_tempdir; - makeDocBookFile(FileName(filename), runparams); + if (makeDocBookFile(FileName(filename), runparams) == ExportKilled) + return ExportKilled; } // LaTeX backend else if (backend_format == format || need_nice_file) { runparams.nice = true; - bool const success = makeLaTeXFile(FileName(filename), string(), runparams); + ExportStatus const retval = + makeLaTeXFile(FileName(filename), string(), runparams); + if (retval == ExportKilled) + return ExportKilled; if (d->cloned_buffer_) d->cloned_buffer_->d->errorLists["Export"] = d->errorLists["Export"]; - if (!success) - return ExportError; + if (retval != ExportSuccess) + return retval; } else if (!lyxrc.tex_allows_spaces && contains(filePath(), ' ')) { Alert::error(_("File name error"), - _("The directory path to the document cannot contain spaces.")); + bformat(_("The directory path to the document\n%1$s\n" + "contains spaces, but your TeX installation does " + "not allow them."), from_ascii(filePath()))); return ExportTexPathHasSpaces; } else { runparams.nice = false; - bool const success = makeLaTeXFile( - FileName(filename), filePath(), runparams); + ExportStatus const retval = + makeLaTeXFile(FileName(filename), filePath(), runparams); + if (retval == ExportKilled) + return ExportKilled; if (d->cloned_buffer_) d->cloned_buffer_->d->errorLists["Export"] = d->errorLists["Export"]; - if (!success) + if (retval != ExportSuccess) return ExportError; } @@ -4281,9 +4384,12 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir ErrorList & error_list = d->errorLists[error_type]; string const ext = theFormats().extension(format); FileName const tmp_result_file(changeExtension(filename, ext)); - bool const success = converters.convert(this, FileName(filename), - tmp_result_file, FileName(absFileName()), backend_format, format, - error_list); + Converters::RetVal const retval = + converters.convert(this, FileName(filename), tmp_result_file, + FileName(absFileName()), backend_format, format, error_list); + if (retval == Converters::KILLED) + return ExportCancel; + bool success = (retval == Converters::SUCCESS); // Emit the signal to show the error list or copy it back to the // cloned Buffer so that it can be emitted afterwards. @@ -4622,8 +4728,9 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const DocumentClass const & textclass = master->params().documentClass(); FileNamePairList old_bibfiles; - // do this only if we are the top-level Buffer - if (master == this) { + // Do this only if we are the top-level Buffer. We also need to account + // for the case of a previewed child with ignored parent here. + if (master == this && !d->ignore_parent) { textclass.counters().reset(from_ascii("bibitem")); reloadBibInfoCache(); // we will re-read this cache as we go through, but we need @@ -4684,9 +4791,13 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const return; // if the bibfiles changed, the cache of bibinfo is invalid - sort(d->bibfiles_cache_.begin(), d->bibfiles_cache_.end()); - // the old one should already be sorted - if (old_bibfiles != d->bibfiles_cache_) { + FileNamePairList new_bibfiles = d->bibfiles_cache_; + // this is a trick to determine whether the two vectors have + // the same elements. + sort(new_bibfiles.begin(), new_bibfiles.end()); + sort(old_bibfiles.begin(), old_bibfiles.end()); + if (old_bibfiles != new_bibfiles) { + LYXERR(Debug::FILES, "Reloading bibinfo cache."); invalidateBibinfoCache(); reloadBibInfoCache(); // We relied upon the bibinfo cache when recalculating labels. But that @@ -4696,10 +4807,21 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const // labels. Nothing else will have changed. So we could create a new // UpdateType that would signal that fact, if we needed to do so. parit = cbuf.par_iterator_begin(); + // we will be re-doing the counters and references and such. + textclass.counters().reset(); + clearReferenceCache(); + // we should not need to do this again? + // updateMacros(); + setChangesPresent(false); updateBuffer(parit, utype); + // this will already have been done by reloadBibInfoCache(); + // d->bibinfo_cache_valid_ = true; } - else + else { + LYXERR(Debug::FILES, "Bibfiles unchanged."); + // this is also set to true on the other path, by reloadBibInfoCache. d->bibinfo_cache_valid_ = true; + } d->cite_labels_valid_ = true; /// FIXME: Perf cbuf.tocBackend().update(true, utype); @@ -5276,7 +5398,6 @@ void Buffer::Impl::fileExternallyModified(bool const exists) "checksum unchanged: " << filename); return; } - lyx_clean = bak_clean = false; // If the file has been deleted, only mark the file as dirty since it is // pointless to prompt for reloading. If later a file is moved into this // location, then the externally modified warning will appear then.