X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetInclude.cpp;h=87d2e5103d0dd913d5df419807fe1b93fa7fcf10;hb=ba738d0167bcea87df47f49b1bc90b04ae4dbd68;hp=b0d2be4f0317db8804ecb67b726fad4da8f709b5;hpb=aa794a8806ec309240bf8f4a64d84adb9b94dd64;p=features.git diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index b0d2be4f03..87d2e5103d 100644 --- a/src/insets/InsetInclude.cpp +++ b/src/insets/InsetInclude.cpp @@ -65,8 +65,6 @@ #include "support/mutex.h" #include "support/ExceptionMessage.h" -#include "support/bind.h" - using namespace std; using namespace lyx::support; @@ -189,7 +187,8 @@ char_type replaceCommaInBraces(docstring & params) InsetInclude::InsetInclude(Buffer * buf, InsetCommandParams const & p) : InsetCommand(buf, p), include_label(uniqueID()), preview_(make_unique(this)), failedtoload_(false), - set_label_(false), label_(nullptr), child_buffer_(nullptr), file_exist_(false) + set_label_(false), label_(nullptr), child_buffer_(nullptr), file_exist_(false), + recursion_error_(false) { preview_->connect([=](){ fileChanged(); }); @@ -205,7 +204,7 @@ InsetInclude::InsetInclude(InsetInclude const & other) : InsetCommand(other), include_label(other.include_label), preview_(make_unique(this)), failedtoload_(false), set_label_(false), label_(nullptr), child_buffer_(nullptr), - file_exist_(other.file_exist_) + file_exist_(other.file_exist_),recursion_error_(other.recursion_error_) { preview_->connect([=](){ fileChanged(); }); @@ -379,6 +378,7 @@ void InsetInclude::setParams(InsetCommandParams const & p) // reset in order to allow loading new file failedtoload_ = false; + recursion_error_ = false; InsetCommand::setParams(p); set_label_ = false; @@ -444,17 +444,6 @@ docstring InsetInclude::screenLabel() const } -Buffer * InsetInclude::getChildBuffer() const -{ - Buffer * childBuffer = loadIfNeeded(); - - // FIXME RECURSIVE INCLUDE - // This isn't sufficient, as the inclusion could be downstream. - // But it'll have to do for now. - return (childBuffer == &buffer()) ? nullptr : childBuffer; -} - - Buffer * InsetInclude::loadIfNeeded() const { // This is for background export and preview. We don't even want to @@ -482,6 +471,9 @@ Buffer * InsetInclude::loadIfNeeded() const return nullptr; Buffer * child = theBufferList().getBuffer(included_file); + if (checkForRecursiveInclude(child)) + return child; + if (!child) { // the readonly flag can/will be wrong, not anymore I think. if (!included_file.exists()) { @@ -494,6 +486,7 @@ Buffer * InsetInclude::loadIfNeeded() const // Buffer creation is not possible. return nullptr; + buffer().pushIncludedBuffer(child); // Set parent before loading, such that macros can be tracked child->setParent(&buffer()); @@ -502,9 +495,11 @@ Buffer * InsetInclude::loadIfNeeded() const child->setParent(nullptr); //close the buffer we just opened theBufferList().release(child); + buffer().popIncludedBuffer(); return nullptr; } + buffer().popIncludedBuffer(); if (!child->errorList("Parse").empty()) { // FIXME: Do something. } @@ -527,6 +522,26 @@ Buffer * InsetInclude::loadIfNeeded() const } +bool InsetInclude::checkForRecursiveInclude( + Buffer const * cbuf, bool silent) const +{ + if (recursion_error_) + return true; + + if (!buffer().isBufferIncluded(cbuf)) + return false; + + if (!silent) { + docstring const msg = _("The file\n%1$s\n has attempted to include itself.\n" + "The document set will not work properly until this is fixed!"); + frontend::Alert::warning(_("Recursive Include"), + bformat(msg, from_utf8(cbuf->fileName().absFileName()))); + } + recursion_error_ = true; + return true; +} + + void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const { string incfile = ltrim(to_utf8(params()["filename"])); @@ -551,20 +566,6 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const } FileName const included_file = includedFileName(buffer(), params()); - - // Check we're not trying to include ourselves. - // FIXME RECURSIVE INCLUDE - // This isn't sufficient, as the inclusion could be downstream. - // But it'll have to do for now. - if (isInputOrInclude(params()) && - buffer().absFileName() == included_file.absFileName()) - { - Alert::error(_("Recursive input"), - bformat(_("Attempted to include file %1$s in itself! " - "Ignoring inclusion."), from_utf8(incfile))); - return; - } - Buffer const * const masterBuffer = buffer().masterBuffer(); // if incfile is relative, make it relative to the master @@ -803,6 +804,9 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const return; } + if (recursion_error_) + return; + if (!runparams.silent) { if (tmp->params().baseClass() != masterBuffer->params().baseClass()) { // FIXME UNICODE @@ -933,7 +937,7 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const } -docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const & rp) const +docstring InsetInclude::xhtml(XMLStream & xs, OutputParams const & rp) const { if (rp.inComment) return docstring(); @@ -943,11 +947,11 @@ docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const & rp) const bool const listing = isListings(params()); if (listing || isVerbatim(params())) { if (listing) - xs << html::StartTag("pre"); + xs << xml::StartTag("pre"); // FIXME: We don't know the encoding of the file, default to UTF-8. xs << includedFileName(buffer(), params()).fileContents("UTF-8"); if (listing) - xs << html::EndTag("pre"); + xs << xml::EndTag("pre"); return docstring(); } @@ -966,19 +970,13 @@ docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const & rp) const // In the other cases, we will generate the HTML and include it. - // Check we're not trying to include ourselves. - // FIXME RECURSIVE INCLUDE - if (buffer().absFileName() == included_file.absFileName()) { - Alert::error(_("Recursive input"), - bformat(_("Attempted to include file %1$s in itself! " - "Ignoring inclusion."), ltrim(params()["filename"]))); - return docstring(); - } - Buffer const * const ibuf = loadIfNeeded(); if (!ibuf) return docstring(); + if (recursion_error_) + return docstring(); + // are we generating only some paragraphs, or all of them? bool const all_pars = !rp.dryrun || (rp.par_begin == 0 && @@ -990,11 +988,12 @@ docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const & rp) const op.par_end = 0; ibuf->writeLyXHTMLSource(xs.os(), op, Buffer::IncludedFile); } else - xs << XHTMLStream::ESCAPE_NONE + xs << XMLStream::ESCAPE_NONE << ""; + return docstring(); } @@ -1029,6 +1028,10 @@ int InsetInclude::plaintext(odocstringstream & os, os << str; return str.size(); } + + if (recursion_error_) + return 0; + writePlaintextFile(*ibuf, os, op); return 0; } @@ -1043,18 +1046,6 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const return 0; string const included_file = includedFileName(buffer(), params()).absFileName(); - - // Check we're not trying to include ourselves. - // FIXME RECURSIVE INCLUDE - // This isn't sufficient, as the inclusion could be downstream. - // But it'll have to do for now. - if (buffer().absFileName() == included_file) { - Alert::error(_("Recursive input"), - bformat(_("Attempted to include file %1$s in itself! " - "Ignoring inclusion."), from_utf8(incfile))); - return 0; - } - string exppath = incfile; if (!runparams.export_folder.empty()) { exppath = makeAbsPath(exppath, runparams.export_folder).realPath(); @@ -1067,6 +1058,9 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const Buffer * tmp = loadIfNeeded(); if (tmp) { + if (recursion_error_) + return 0; + string const mangled = writefile.mangledFileName(); writefile = makeAbsPath(mangled, buffer().masterBuffer()->temppath()); @@ -1136,40 +1130,41 @@ void InsetInclude::validate(LaTeXFeatures & features) const // Load the file in the include if it needs // to be loaded: Buffer * const tmp = loadIfNeeded(); - if (tmp) { - // the file is loaded - // make sure the buffer isn't us - // FIXME RECURSIVE INCLUDES - // This is not sufficient, as recursive includes could be - // more than a file away. But it will do for now. - if (tmp && tmp != &buffer()) { - // We must temporarily change features.buffer, - // otherwise it would always be the master buffer, - // and nested includes would not work. - features.setBuffer(*tmp); - // Maybe this is already a child - bool const is_child = - features.runparams().is_child; - features.runparams().is_child = true; - tmp->validate(features); - features.runparams().is_child = is_child; - features.setBuffer(buffer()); - } - } + if (!tmp) + return; + + // the file is loaded + if (checkForRecursiveInclude(tmp)) + return; + buffer().pushIncludedBuffer(tmp); + + // We must temporarily change features.buffer, + // otherwise it would always be the master buffer, + // and nested includes would not work. + features.setBuffer(*tmp); + // Maybe this is already a child + bool const is_child = + features.runparams().is_child; + features.runparams().is_child = true; + tmp->validate(features); + features.runparams().is_child = is_child; + features.setBuffer(buffer()); + + buffer().popIncludedBuffer(); } void InsetInclude::collectBibKeys(InsetIterator const & /*di*/, FileNameList & checkedFiles) const { - Buffer * child = loadIfNeeded(); - if (!child) + Buffer * ibuf = loadIfNeeded(); + if (!ibuf) return; - // FIXME RECURSIVE INCLUDE - // This isn't sufficient, as the inclusion could be downstream. - // But it'll have to do for now. - if (child == &buffer()) + + if (checkForRecursiveInclude(ibuf)) return; - child->collectBibKeys(checkedFiles); + buffer().pushIncludedBuffer(ibuf); + ibuf->collectBibKeys(checkedFiles); + buffer().popIncludedBuffer(); } @@ -1189,7 +1184,7 @@ void InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const } else { if (!set_label_) { set_label_ = true; - button_.update(screenLabel(), true, false, !file_exist_); + button_.update(screenLabel(), true, false, !file_exist_ || recursion_error_); } button_.metrics(mi, dim); } @@ -1229,9 +1224,9 @@ string InsetInclude::contextMenuName() const } -Inset::DisplayType InsetInclude::display() const +Inset::RowFlags InsetInclude::rowFlags() const { - return type(params()) == INPUT ? Inline : AlignCenter; + return type(params()) == INPUT ? Inline : Display; } @@ -1327,7 +1322,7 @@ void InsetInclude::addToToc(DocIterator const & cpit, bool output_active, b.pushItem(cpit, screenLabel(), output_active); b.pop(); } else { - Buffer const * const childbuffer = getChildBuffer(); + Buffer const * const childbuffer = loadIfNeeded(); TocBuilder & b = backend.builder("child"); docstring str = childbuffer ? childbuffer->fileName().displayName() @@ -1338,15 +1333,19 @@ void InsetInclude::addToToc(DocIterator const & cpit, bool output_active, if (!childbuffer) return; + if (checkForRecursiveInclude(childbuffer)) + return; + buffer().pushIncludedBuffer(childbuffer); // Update the child's tocBackend. The outliner uses the master's, but // the navigation menu uses the child's. childbuffer->tocBackend().update(output_active, utype); // Include Tocs from children childbuffer->inset().addToToc(DocIterator(), output_active, utype, backend); - //Copy missing outliner names (though the user has been warned against - //having different document class and module selection between master - //and child). + buffer().popIncludedBuffer(); + // Copy missing outliner names (though the user has been warned against + // having different document class and module selection between master + // and child). for (auto const & name : childbuffer->params().documentClass().outlinerNames()) backend.addName(name.first, translateIfPossible(name.second)); @@ -1379,14 +1378,16 @@ void InsetInclude::updateCommand() void InsetInclude::updateBuffer(ParIterator const & it, UpdateType utype, bool const deleted) { file_exist_ = includedFileExist(); - - button_.update(screenLabel(), true, false, !file_exist_); - - Buffer const * const childbuffer = getChildBuffer(); + Buffer const * const childbuffer = loadIfNeeded(); if (childbuffer) { - childbuffer->updateBuffer(Buffer::UpdateChildOnly, utype); + if (!checkForRecursiveInclude(childbuffer)) + childbuffer->updateBuffer(Buffer::UpdateChildOnly, utype); + button_.update(screenLabel(), true, false, recursion_error_); return; } + + button_.update(screenLabel(), true, false, !file_exist_); + if (!isListings(params())) return;