X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetInclude.cpp;h=4e44ec8c87800f1825b2d65da6991fb9b6a1d837;hb=239b9919ffe28338d789e6dc9122228f77ab77a7;hp=f2304557b5763c73a655c5df49f9c3c7f589a201;hpb=973968afce1b010f4cbcd3def3e6d56c70e10188;p=lyx.git diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index f2304557b5..4e44ec8c87 100644 --- a/src/insets/InsetInclude.cpp +++ b/src/insets/InsetInclude.cpp @@ -18,8 +18,10 @@ #include "BufferList.h" #include "BufferParams.h" #include "BufferView.h" +#include "Converter.h" #include "Cursor.h" #include "DispatchResult.h" +#include "Encoding.h" #include "ErrorList.h" #include "Exporter.h" #include "Format.h" @@ -29,12 +31,12 @@ #include "LayoutFile.h" #include "LayoutModuleList.h" #include "LyX.h" -#include "LyXFunc.h" -#include "LyXRC.h" #include "Lexer.h" #include "MetricsInfo.h" +#include "output_plaintext.h" #include "output_xhtml.h" #include "OutputParams.h" +#include "texstream.h" #include "TextClass.h" #include "TocBackend.h" @@ -48,6 +50,8 @@ #include "insets/InsetListingsParams.h" #include "insets/RenderPreview.h" +#include "mathed/MacroTable.h" + #include "support/convert.h" #include "support/debug.h" #include "support/docstream.h" @@ -57,8 +61,10 @@ #include "support/lassert.h" #include "support/lstrings.h" // contains #include "support/lyxalgo.h" +#include "support/mutex.h" +#include "support/ExceptionMessage.h" -#include +#include "support/bind.h" using namespace std; using namespace lyx::support; @@ -73,6 +79,8 @@ namespace { docstring const uniqueID() { static unsigned int seed = 1000; + static Mutex mutex; + Mutex::Locker lock(&mutex); return "file" + convert(++seed); } @@ -121,7 +129,7 @@ bool isVerbatim(InsetCommandParams const & params) bool isInputOrInclude(InsetCommandParams const & params) { Types const t = type(params); - return t == INPUT || t == INCLUDE; + return t == INPUT || t == INCLUDE; } @@ -134,17 +142,17 @@ FileName const masterFileName(Buffer const & buffer) void add_preview(RenderMonitoredPreview &, InsetInclude const &, Buffer const &); -string const parentFilename(Buffer const & buffer) +string const parentFileName(Buffer const & buffer) { return buffer.absFileName(); } -FileName const includedFilename(Buffer const & buffer, +FileName const includedFileName(Buffer const & buffer, InsetCommandParams const & params) { return makeAbsPath(to_utf8(params["filename"]), - onlyPath(parentFilename(buffer))); + onlyPath(parentFileName(buffer))); } @@ -161,16 +169,17 @@ InsetLabel * createLabel(Buffer * buf, docstring const & label_str) InsetInclude::InsetInclude(Buffer * buf, InsetCommandParams const & p) - : InsetCommand(buf, p, "include"), include_label(uniqueID()), + : InsetCommand(buf, p), include_label(uniqueID()), preview_(new RenderMonitoredPreview(this)), failedtoload_(false), set_label_(false), label_(0), child_buffer_(0) { - preview_->fileChanged(boost::bind(&InsetInclude::fileChanged, this)); + preview_->fileChanged(bind(&InsetInclude::fileChanged, this)); if (isListings(params())) { InsetListingsParams listing_params(to_utf8(p["lstparams"])); label_ = createLabel(buffer_, from_utf8(listing_params.getParamValue("label"))); - } + } else if (isInputOrInclude(params()) && buf) + loadIfNeeded(); } @@ -179,7 +188,7 @@ InsetInclude::InsetInclude(InsetInclude const & other) preview_(new RenderMonitoredPreview(this)), failedtoload_(false), set_label_(false), label_(0), child_buffer_(0) { - preview_->fileChanged(boost::bind(&InsetInclude::fileChanged, this)); + preview_->fileChanged(bind(&InsetInclude::fileChanged, this)); if (other.label_) label_ = new InsetLabel(*other.label_); @@ -188,6 +197,8 @@ InsetInclude::InsetInclude(InsetInclude const & other) InsetInclude::~InsetInclude() { + if (isBufferLoaded()) + buffer().invalidateBibfileCache(); delete label_; } @@ -228,7 +239,7 @@ bool InsetInclude::isCompatibleCommand(string const & s) void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) { - switch (cmd.action) { + switch (cmd.action()) { case LFUN_INSET_EDIT: { editIncluded(to_utf8(params()["filename"])); @@ -236,15 +247,16 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) } case LFUN_INSET_MODIFY: { - // It should be OK just to invalidate the cache is setParams() + // It should be OK just to invalidate the cache in setParams() // If not.... // child_buffer_ = 0; InsetCommandParams p(INCLUDE_CODE); if (cmd.getArg(0) == "changetype") { + cur.recordUndo(); InsetCommand::doDispatch(cur, cmd); p = params(); } else - InsetCommand::string2params("include", to_utf8(cmd.argument()), p); + InsetCommand::string2params(to_utf8(cmd.argument()), p); if (!p.getCmdName().empty()) { if (isListings(p)){ InsetListingsParams new_params(to_utf8(p["lstparams"])); @@ -264,7 +276,7 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) } if (new_label != old_label) { - label_->updateCommand(new_label); + label_->updateLabelAndRefs(new_label, &cur); // the label might have been adapted (duplicate) if (new_label != label_->getParam("name")) { new_params.addParam("label", "{" + @@ -274,9 +286,11 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) } } } + cur.recordUndo(); setParams(p); + cur.forceBufferUpdate(); } else - cur.noUpdate(); + cur.noScreenUpdate(); break; } @@ -305,7 +319,7 @@ void InsetInclude::editIncluded(string const & file) bool InsetInclude::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & flag) const { - switch (cmd.action) { + switch (cmd.action()) { case LFUN_INSET_EDIT: flag.setEnabled(true); @@ -338,7 +352,7 @@ void InsetInclude::setParams(InsetCommandParams const & p) if (type(params()) == INPUT) add_preview(*preview_, *this, buffer()); - buffer().updateBibfilesCache(); + buffer().invalidateBibfileCache(); } @@ -378,7 +392,8 @@ docstring InsetInclude::screenLabel() const temp = listings_label_; break; case NONE: - LASSERT(false, /**/); + LASSERT(false, temp = buffer().B_("Unknown")); + break; } temp += ": "; @@ -386,7 +401,7 @@ docstring InsetInclude::screenLabel() const if (params()["filename"].empty()) temp += "???"; else - temp += from_utf8(onlyFilename(to_utf8(params()["filename"]))); + temp += from_utf8(onlyFileName(to_utf8(params()["filename"]))); return temp; } @@ -396,36 +411,37 @@ Buffer * InsetInclude::getChildBuffer() const { Buffer * childBuffer = loadIfNeeded(); - // FIXME: recursive includes + // FIXME RECURSIVE INCLUDE + // This isn't sufficient, as the inclusion could be downstream. + // But it'll have to do for now. return (childBuffer == &buffer()) ? 0 : childBuffer; } Buffer * InsetInclude::loadIfNeeded() const { - // This is for background export and preview. We don't want to load the - // cloned child document again. - if (child_buffer_ && theBufferList().isLoaded(child_buffer_) - && child_buffer_->isClone()) + // This is for background export and preview. We don't even want to + // try to load the cloned child document again. + if (buffer().isClone()) return child_buffer_; - + // Don't try to load it again if we failed before. if (failedtoload_ || isVerbatim(params()) || isListings(params())) return 0; + FileName const included_file = includedFileName(buffer(), params()); // Use cached Buffer if possible. if (child_buffer_ != 0) { - if (theBufferList().isLoaded(child_buffer_)) + if (theBufferList().isLoaded(child_buffer_) + // additional sanity check: make sure the Buffer really is + // associated with the file we want. + && child_buffer_ == theBufferList().getBuffer(included_file)) return child_buffer_; // Buffer vanished, so invalidate cache and try to reload. child_buffer_ = 0; } - string const parent_filename = buffer().absFileName(); - FileName const included_file = - makeAbsPath(to_utf8(params()["filename"]), onlyPath(parent_filename)); - - if (!isLyXFilename(included_file.absFilename())) + if (!isLyXFileName(included_file.absFileName())) return 0; Buffer * child = theBufferList().getBuffer(included_file); @@ -434,50 +450,65 @@ Buffer * InsetInclude::loadIfNeeded() const if (!included_file.exists()) return 0; - child = theBufferList().newBuffer(included_file.absFilename()); + child = theBufferList().newBuffer(included_file.absFileName()); if (!child) // Buffer creation is not possible. return 0; - if (!child->loadLyXFile(included_file)) { + // Set parent before loading, such that macros can be tracked + child->setParent(&buffer()); + + if (child->loadLyXFile() != Buffer::ReadSuccess) { failedtoload_ = true; + child->setParent(0); //close the buffer we just opened theBufferList().release(child); return 0; } - + if (!child->errorList("Parse").empty()) { // FIXME: Do something. } + } else { + // The file was already loaded, so, simply + // inform parent buffer about local macros. + Buffer const * parent = &buffer(); + child->setParent(parent); + MacroNameSet macros; + child->listMacroNames(macros); + MacroNameSet::const_iterator cit = macros.begin(); + MacroNameSet::const_iterator end = macros.end(); + for (; cit != end; ++cit) + parent->usermacros.insert(*cit); } - child->setParent(&buffer()); + // Cache the child buffer. child_buffer_ = child; return child; } -int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const +void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const { string incfile = to_utf8(params()["filename"]); // Do nothing if no file name has been specified if (incfile.empty()) - return 0; + return; - FileName const included_file = includedFilename(buffer(), params()); + 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()) + buffer().absFileName() == included_file.absFileName()) { Alert::error(_("Recursive input"), bformat(_("Attempted to include file %1$s in itself! " "Ignoring inclusion."), from_utf8(incfile))); - return 0; + return; } Buffer const * const masterBuffer = buffer().masterBuffer(); @@ -486,120 +517,55 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const // buffer directory. if (!FileName::isAbsolute(incfile)) { // FIXME UNICODE - incfile = to_utf8(makeRelPath(from_utf8(included_file.absFilename()), + incfile = to_utf8(makeRelPath(from_utf8(included_file.absFileName()), from_utf8(masterBuffer->filePath()))); } + string exppath = incfile; + if (!runparams.export_folder.empty()) { + exppath = makeAbsPath(exppath, runparams.export_folder).realPath(); + FileName(exppath).onlyPath().createPath(); + } + // write it to a file (so far the complete file) string exportfile; string mangled; // bug 5681 if (type(params()) == LISTINGS) { - exportfile = incfile; - mangled = DocFileName(included_file).mangledFilename(); + exportfile = exppath; + mangled = DocFileName(included_file).mangledFileName(); } else { - exportfile = changeExtension(incfile, ".tex"); - mangled = DocFileName(changeExtension(included_file.absFilename(), ".tex")). - mangledFilename(); + exportfile = changeExtension(exppath, ".tex"); + mangled = DocFileName(changeExtension(included_file.absFileName(), ".tex")). + mangledFileName(); } - FileName const writefile(makeAbsPath(mangled, masterBuffer->temppath())); - if (!runparams.nice) incfile = mangled; - else if (!isValidLaTeXFilename(incfile)) { + else if (!runparams.silent) + ; // no warning wanted + else if (!isValidLaTeXFileName(incfile)) { frontend::Alert::warning(_("Invalid filename"), - _("The following filename is likely to cause trouble " - "when running the exported file through LaTeX: ") + - from_utf8(incfile)); + _("The following filename will cause troubles " + "when running the exported file through LaTeX: ") + + from_utf8(incfile)); + } else if (!isValidDVIFileName(incfile)) { + frontend::Alert::warning(_("Problematic filename for DVI"), + _("The following filename can cause troubles " + "when running the exported file through LaTeX " + "and opening the resulting DVI: ") + + from_utf8(incfile), true); } + + FileName const writefile(makeAbsPath(mangled, runparams.for_preview ? + buffer().temppath() : masterBuffer->temppath())); + LYXERR(Debug::LATEX, "incfile:" << incfile); LYXERR(Debug::LATEX, "exportfile:" << exportfile); LYXERR(Debug::LATEX, "writefile:" << writefile); - if (runparams.inComment || runparams.dryrun) { - //Don't try to load or copy the file if we're - //in a comment or doing a dryrun - } else if (isInputOrInclude(params()) && - isLyXFilename(included_file.absFilename())) { - //if it's a LyX file and we're inputting or including, - //try to load it so we can write the associated latex - if (!loadIfNeeded()) - return false; - - Buffer * tmp = theBufferList().getBuffer(included_file); - - if (tmp->params().baseClass() != masterBuffer->params().baseClass()) { - // FIXME UNICODE - docstring text = bformat(_("Included file `%1$s'\n" - "has textclass `%2$s'\n" - "while parent file has textclass `%3$s'."), - included_file.displayName(), - from_utf8(tmp->params().documentClass().name()), - from_utf8(masterBuffer->params().documentClass().name())); - Alert::warning(_("Different textclasses"), text, true); - } - - // Make sure modules used in child are all included in master - // FIXME It might be worth loading the children's modules into the master - // over in BufferParams rather than doing this check. - LayoutModuleList const masterModules = masterBuffer->params().getModules(); - LayoutModuleList const childModules = tmp->params().getModules(); - LayoutModuleList::const_iterator it = childModules.begin(); - LayoutModuleList::const_iterator end = childModules.end(); - for (; it != end; ++it) { - string const module = *it; - LayoutModuleList::const_iterator found = - find(masterModules.begin(), masterModules.end(), module); - if (found == masterModules.end()) { - docstring text = bformat(_("Included file `%1$s'\n" - "uses module `%2$s'\n" - "which is not used in parent file."), - included_file.displayName(), from_utf8(module)); - Alert::warning(_("Module not found"), text); - } - } - - tmp->markDepClean(masterBuffer->temppath()); - - // FIXME: handle non existing files - // FIXME: Second argument is irrelevant! - // since only_body is true, makeLaTeXFile will not look at second - // argument. Should we set it to string(), or should makeLaTeXFile - // make use of it somehow? (JMarc 20031002) - // The included file might be written in a different encoding - // and language. - Encoding const * const oldEnc = runparams.encoding; - Language const * const oldLang = runparams.master_language; - runparams.encoding = &tmp->params().encoding(); - runparams.master_language = buffer().params().language; - tmp->makeLaTeXFile(writefile, - masterFileName(buffer()).onlyPath().absFilename(), - runparams, false); - runparams.encoding = oldEnc; - runparams.master_language = oldLang; - } else { - // In this case, it's not a LyX file, so we copy the file - // to the temp dir, so that .aux files etc. are not created - // in the original dir. Files included by this file will be - // found via input@path, see ../Buffer.cpp. - unsigned long const checksum_in = included_file.checksum(); - unsigned long const checksum_out = writefile.checksum(); - - if (checksum_in != checksum_out) { - if (!included_file.copyTo(writefile)) { - // FIXME UNICODE - LYXERR(Debug::LATEX, - to_utf8(bformat(_("Could not copy the file\n%1$s\n" - "into the temporary directory."), - from_utf8(included_file.absFilename())))); - return 0; - } - } - } + string const tex_format = flavor2format(runparams.flavor); - string const tex_format = (runparams.flavor == OutputParams::LATEX) ? - "latex" : "pdflatex"; switch (type(params())) { case VERB: case VERBAST: { @@ -608,27 +574,29 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const os << '\\' << from_ascii(params().getCmdName()) << '{' << from_utf8(incfile) << '}'; break; - } + } case INPUT: { runparams.exportdata->addExternalFile(tex_format, writefile, exportfile); // \input wants file with extension (default is .tex) - if (!isLyXFilename(included_file.absFilename())) { + if (!isLyXFileName(included_file.absFileName())) { incfile = latex_path(incfile); // FIXME UNICODE os << '\\' << from_ascii(params().getCmdName()) << '{' << from_utf8(incfile) << '}'; } else { - incfile = changeExtension(incfile, ".tex"); - incfile = latex_path(incfile); + incfile = changeExtension(incfile, ".tex"); + incfile = latex_path(incfile); // FIXME UNICODE os << '\\' << from_ascii(params().getCmdName()) << '{' << from_utf8(incfile) << '}'; } break; - } + } case LISTINGS: { + runparams.exportdata->addExternalFile(tex_format, writefile, + exportfile); os << '\\' << from_ascii(params().getCmdName()); string const opt = to_utf8(params()["lstparams"]); // opt is set in QInclude dialog and should have passed validation. @@ -637,7 +605,7 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const os << "[" << from_utf8(params.params()) << "]"; os << '{' << from_utf8(incfile) << '}'; break; - } + } case INCLUDE: { runparams.exportdata->addExternalFile(tex_format, writefile, exportfile); @@ -655,11 +623,159 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const break; } - return 0; + if (runparams.inComment || runparams.dryrun) + // Don't try to load or copy the file if we're + // in a comment or doing a dryrun + return; + + if (isInputOrInclude(params()) && + isLyXFileName(included_file.absFileName())) { + // if it's a LyX file and we're inputting or including, + // try to load it so we can write the associated latex + + Buffer * tmp = loadIfNeeded(); + if (!tmp) { + if (!runparams.silent) { + docstring text = bformat(_("Could not load included " + "file\n`%1$s'\n" + "Please, check whether it actually exists."), + included_file.displayName()); + Alert::warning(_("Missing included file"), text); + } + return; + } + + if (!runparams.silent) { + if (tmp->params().baseClass() != masterBuffer->params().baseClass()) { + // FIXME UNICODE + docstring text = bformat(_("Included file `%1$s'\n" + "has textclass `%2$s'\n" + "while parent file has textclass `%3$s'."), + included_file.displayName(), + from_utf8(tmp->params().documentClass().name()), + from_utf8(masterBuffer->params().documentClass().name())); + Alert::warning(_("Different textclasses"), text, true); + } + + string const child_tf = tmp->params().useNonTeXFonts ? "true" : "false"; + string const master_tf = masterBuffer->params().useNonTeXFonts ? "true" : "false"; + if (tmp->params().useNonTeXFonts != masterBuffer->params().useNonTeXFonts) { + docstring text = bformat(_("Included file `%1$s'\n" + "has use-non-TeX-fonts set to `%2$s'\n" + "while parent file has use-non-TeX-fonts set to `%3$s'."), + included_file.displayName(), + from_utf8(child_tf), + from_utf8(master_tf)); + Alert::warning(_("Different use-non-TeX-fonts settings"), text, true); + } + + // Make sure modules used in child are all included in master + // FIXME It might be worth loading the children's modules into the master + // over in BufferParams rather than doing this check. + LayoutModuleList const masterModules = masterBuffer->params().getModules(); + LayoutModuleList const childModules = tmp->params().getModules(); + LayoutModuleList::const_iterator it = childModules.begin(); + LayoutModuleList::const_iterator end = childModules.end(); + for (; it != end; ++it) { + string const module = *it; + LayoutModuleList::const_iterator found = + find(masterModules.begin(), masterModules.end(), module); + if (found == masterModules.end()) { + docstring text = bformat(_("Included file `%1$s'\n" + "uses module `%2$s'\n" + "which is not used in parent file."), + included_file.displayName(), from_utf8(module)); + Alert::warning(_("Module not found"), text); + } + } + } + + tmp->markDepClean(masterBuffer->temppath()); + + // Don't assume the child's format is latex + string const inc_format = tmp->params().bufferFormat(); + FileName const tmpwritefile(changeExtension(writefile.absFileName(), + formats.extension(inc_format))); + + // FIXME: handle non existing files + // The included file might be written in a different encoding + // and language. + Encoding const * const oldEnc = runparams.encoding; + Language const * const oldLang = runparams.master_language; + // If the master uses non-TeX fonts (XeTeX, LuaTeX), + // the children must be encoded in plain utf8! + runparams.encoding = masterBuffer->params().useNonTeXFonts ? + encodings.fromLyXName("utf8-plain") + : &tmp->params().encoding(); + runparams.master_language = buffer().params().language; + runparams.par_begin = 0; + runparams.par_end = tmp->paragraphs().size(); + runparams.is_child = true; + if (!tmp->makeLaTeXFile(tmpwritefile, masterFileName(buffer()). + onlyPath().absFileName(), runparams, Buffer::OnlyBody)) { + if (!runparams.silent) { + docstring msg = bformat(_("Included file `%1$s' " + "was not exported correctly.\n " + "LaTeX export is probably incomplete."), + included_file.displayName()); + ErrorList const & el = tmp->errorList("Export"); + if (!el.empty()) + msg = bformat(from_ascii("%1$s\n\n%2$s\n\n%3$s"), + msg, el.begin()->error, + el.begin()->description); + throw ExceptionMessage(ErrorException, _("Error: "), + msg); + } + } + runparams.encoding = oldEnc; + runparams.master_language = oldLang; + runparams.is_child = false; + + // If needed, use converters to produce a latex file from the child + if (tmpwritefile != writefile) { + ErrorList el; + bool const success = + theConverters().convert(tmp, tmpwritefile, writefile, + included_file, + inc_format, tex_format, el); + + if (!success && !runparams.silent) { + docstring msg = bformat(_("Included file `%1$s' " + "was not exported correctly.\n " + "LaTeX export is probably incomplete."), + included_file.displayName()); + if (!el.empty()) + msg = bformat(from_ascii("%1$s\n\n%2$s\n\n%3$s"), + msg, el.begin()->error, + el.begin()->description); + throw ExceptionMessage(ErrorException, _("Error: "), + msg); + } + } + } else { + // In this case, it's not a LyX file, so we copy the file + // to the temp dir, so that .aux files etc. are not created + // in the original dir. Files included by this file will be + // found via either the environment variable TEXINPUTS, or + // input@path, see ../Buffer.cpp. + unsigned long const checksum_in = included_file.checksum(); + unsigned long const checksum_out = writefile.checksum(); + + if (checksum_in != checksum_out) { + if (!included_file.copyTo(writefile)) { + // FIXME UNICODE + LYXERR(Debug::LATEX, + to_utf8(bformat(_("Could not copy the file\n%1$s\n" + "into the temporary directory."), + from_utf8(included_file.absFileName())))); + return; + } + } + } } -docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const &rp) const +docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const & rp) const { if (rp.inComment) return docstring(); @@ -671,7 +787,7 @@ docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const &rp) const if (listing) xs << html::StartTag("pre"); // FIXME: We don't know the encoding of the file, default to UTF-8. - xs << includedFilename(buffer(), params()).fileContents("UTF-8"); + xs << includedFileName(buffer(), params()).fileContents("UTF-8"); if (listing) xs << html::EndTag("pre"); return docstring(); @@ -680,11 +796,10 @@ docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const &rp) const // We don't (yet) know how to Input or Include non-LyX files. // (If we wanted to get really arcane, we could run some tex2html // converter on the included file. But that's just masochistic.) - string const parent_filename = buffer().absFileName(); - FileName const included_file = - makeAbsPath(to_utf8(params()["filename"]), onlyPath(parent_filename)); - if (!isLyXFilename(included_file.absFilename())) { - frontend::Alert::warning(_("Unsupported Inclusion"), + FileName const included_file = includedFileName(buffer(), params()); + if (!isLyXFileName(included_file.absFileName())) { + if (!rp.silent) + frontend::Alert::warning(_("Unsupported Inclusion"), bformat(_("LyX does not know how to include non-LyX files when " "generating HTML output. Offending file:\n%1$s"), params()["filename"])); @@ -695,7 +810,7 @@ docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const &rp) const // Check we're not trying to include ourselves. // FIXME RECURSIVE INCLUDE - if (buffer().absFileName() == included_file.absFilename()) { + if (buffer().absFileName() == included_file.absFileName()) { Alert::error(_("Recursive input"), bformat(_("Attempted to include file %1$s in itself! " "Ignoring inclusion."), params()["filename"])); @@ -705,24 +820,54 @@ docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const &rp) const Buffer const * const ibuf = loadIfNeeded(); if (!ibuf) return docstring(); - ibuf->writeLyXHTMLSource(xs.os(), rp, true); + + // are we generating only some paragraphs, or all of them? + bool const all_pars = !rp.dryrun || + (rp.par_begin == 0 && + rp.par_end == (int)buffer().text().paragraphs().size()); + + OutputParams op = rp; + if (all_pars) { + op.par_begin = 0; + op.par_end = 0; + ibuf->writeLyXHTMLSource(xs.os(), op, Buffer::IncludedFile); + } else + xs << XHTMLStream::ESCAPE_NONE + << ""; return docstring(); } -int InsetInclude::plaintext(odocstream & os, OutputParams const &) const +int InsetInclude::plaintext(odocstringstream & os, + OutputParams const & op, size_t) const { + // just write the filename if we're making a tooltip or toc entry, + // or are generating this for advanced search + if (op.for_tooltip || op.for_toc || op.for_search) { + os << '[' << screenLabel() << '\n' + << getParam("filename") << "\n]"; + return PLAINTEXT_NEWLINE + 1; // one char on a separate line + } + if (isVerbatim(params()) || isListings(params())) { - os << '[' << screenLabel() << '\n'; - // FIXME: We don't know the encoding of the file, default to UTF-8. - os << includedFilename(buffer(), params()).fileContents("UTF-8"); - os << "\n]"; + os << '[' << screenLabel() << '\n' + // FIXME: We don't know the encoding of the file, default to UTF-8. + << includedFileName(buffer(), params()).fileContents("UTF-8") + << "\n]"; return PLAINTEXT_NEWLINE + 1; // one char on a separate line - } else { + } + + Buffer const * const ibuf = loadIfNeeded(); + if (!ibuf) { docstring const str = '[' + screenLabel() + ']'; os << str; return str.size(); } + writePlaintextFile(*ibuf, os, op); + return 0; } @@ -734,7 +879,7 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const if (incfile.empty()) return 0; - string const included_file = includedFilename(buffer(), params()).absFilename(); + string const included_file = includedFileName(buffer(), params()).absFileName(); // Check we're not trying to include ourselves. // FIXME RECURSIVE INCLUDE @@ -747,14 +892,19 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const return 0; } + string exppath = incfile; + if (!runparams.export_folder.empty()) { + exppath = makeAbsPath(exppath, runparams.export_folder).realPath(); + FileName(exppath).onlyPath().createPath(); + } + // write it to a file (so far the complete file) - string const exportfile = changeExtension(incfile, ".sgml"); + string const exportfile = changeExtension(exppath, ".sgml"); DocFileName writefile(changeExtension(included_file, ".sgml")); - if (loadIfNeeded()) { - Buffer * tmp = theBufferList().getBuffer(FileName(included_file)); - - string const mangled = writefile.mangledFilename(); + Buffer * tmp = loadIfNeeded(); + if (tmp) { + string const mangled = writefile.mangledFileName(); writefile = makeAbsPath(mangled, buffer().masterBuffer()->temppath()); if (!runparams.nice) @@ -764,7 +914,7 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const LYXERR(Debug::LATEX, "exportfile:" << exportfile); LYXERR(Debug::LATEX, "writefile:" << writefile); - tmp->makeDocBookFile(writefile, runparams, true); + tmp->makeDocBookFile(writefile, runparams, Buffer::OnlyBody); } runparams.exportdata->addExternalFile("docbook", writefile, @@ -785,27 +935,27 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const void InsetInclude::validate(LaTeXFeatures & features) const { - string incfile = to_utf8(params()["filename"]); - string writefile; - - LASSERT(&buffer() == &features.buffer(), /**/); + LATTEST(&buffer() == &features.buffer()); + string incfile = to_utf8(params()["filename"]); string const included_file = - includedFilename(buffer(), params()).absFilename(); + includedFileName(buffer(), params()).absFileName(); - if (isLyXFilename(included_file)) + string writefile; + if (isLyXFileName(included_file)) writefile = changeExtension(included_file, ".sgml"); else writefile = included_file; if (!features.runparams().nice && !isVerbatim(params()) && !isListings(params())) { - incfile = DocFileName(writefile).mangledFilename(); + incfile = DocFileName(writefile).mangledFileName(); writefile = makeAbsPath(incfile, - buffer().masterBuffer()->temppath()).absFilename(); + buffer().masterBuffer()->temppath()).absFileName(); } features.includeFile(include_label, writefile); + features.useInsetLayout(getLayout()); if (isVerbatim(params())) features.require("verbatim"); else if (isListings(params())) @@ -814,9 +964,9 @@ void InsetInclude::validate(LaTeXFeatures & features) const // Here we must do the fun stuff... // Load the file in the include if it needs // to be loaded: - if (loadIfNeeded()) { - // a file got loaded - Buffer * const tmp = theBufferList().getBuffer(FileName(included_file)); + 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 @@ -826,51 +976,38 @@ void InsetInclude::validate(LaTeXFeatures & features) const // 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()); } } } -void InsetInclude::fillWithBibKeys(BiblioInfo & keys, - InsetIterator const & /*di*/) const +void InsetInclude::collectBibKeys(InsetIterator const & /*di*/) const { - if (loadIfNeeded()) { - string const included_file = includedFilename(buffer(), params()).absFilename(); - Buffer * tmp = theBufferList().getBuffer(FileName(included_file)); - BiblioInfo const & newkeys = tmp->localBibInfo(); - keys.mergeBiblioInfo(newkeys); - } -} - - -void InsetInclude::updateBibfilesCache() -{ - Buffer const * const child = getChildBuffer(); - if (child) - child->updateBibfilesCache(Buffer::UpdateChildOnly); -} - - -support::FileNameList const & - InsetInclude::getBibfilesCache() const -{ - Buffer const * const child = getChildBuffer(); - if (child) - return child->getBibfilesCache(Buffer::UpdateChildOnly); - - static support::FileNameList const empty; - return empty; + Buffer * child = loadIfNeeded(); + if (!child) + 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()) + return; + child->collectBibKeys(); } void InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const { - LASSERT(mi.base.bv, /**/); + LBUFERR(mi.base.bv); bool use_preview = false; - if (RenderPreview::status() != LyXRC::PREVIEW_OFF) { + if (RenderPreview::previewText()) { graphics::PreviewImage const * pimage = preview_->getPreviewImage(mi.base.bv->buffer()); use_preview = pimage && pimage->image(); @@ -893,10 +1030,10 @@ void InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const void InsetInclude::draw(PainterInfo & pi, int x, int y) const { - LASSERT(pi.base.bv, /**/); + LBUFERR(pi.base.bv); bool use_preview = false; - if (RenderPreview::status() != LyXRC::PREVIEW_OFF) { + if (RenderPreview::previewText()) { graphics::PreviewImage const * pimage = preview_->getPreviewImage(pi.base.bv->buffer()); use_preview = pimage && pimage->image(); @@ -909,9 +1046,15 @@ void InsetInclude::draw(PainterInfo & pi, int x, int y) const } -docstring InsetInclude::contextMenu(BufferView const &, int, int) const +void InsetInclude::write(ostream & os) const +{ + params().Write(os, &buffer()); +} + + +string InsetInclude::contextMenuName() const { - return from_ascii("context-include"); + return "context-include"; } @@ -921,6 +1064,13 @@ Inset::DisplayType InsetInclude::display() const } +docstring InsetInclude::layoutName() const +{ + if (isListings(params())) + return from_ascii("IncludeListings"); + return InsetCommand::layoutName(); +} + // // preview stuff @@ -933,7 +1083,7 @@ void InsetInclude::fileChanged() const return; preview_->removePreview(*buffer); - add_preview(*preview_.get(), *this, *buffer); + add_preview(*preview_, *this, *buffer); preview_->startLoading(*buffer); } @@ -942,7 +1092,7 @@ namespace { bool preview_wanted(InsetCommandParams const & params, Buffer const & buffer) { - FileName const included_file = includedFilename(buffer, params); + FileName const included_file = includedFileName(buffer, params); return type(params) == INPUT && params.preview() && included_file.isReadableFile(); @@ -951,14 +1101,16 @@ bool preview_wanted(InsetCommandParams const & params, Buffer const & buffer) docstring latexString(InsetInclude const & inset) { - odocstringstream os; + odocstringstream ods; + otexstream os(ods); // We don't need to set runparams.encoding since this will be done // by latex() anyway. OutputParams runparams(0); runparams.flavor = OutputParams::LATEX; + runparams.for_preview = true; inset.latex(os, runparams); - return os.str(); + return ods.str(); } @@ -966,9 +1118,8 @@ void add_preview(RenderMonitoredPreview & renderer, InsetInclude const & inset, Buffer const & buffer) { InsetCommandParams const & params = inset.params(); - if (RenderPreview::status() != LyXRC::PREVIEW_OFF && - preview_wanted(params, buffer)) { - renderer.setAbsFile(includedFilename(buffer, params)); + if (RenderPreview::previewText() && preview_wanted(params, buffer)) { + renderer.setAbsFile(includedFileName(buffer, params)); docstring const snippet = latexString(inset); renderer.addPreview(snippet, buffer); } @@ -983,47 +1134,44 @@ void InsetInclude::addPreview(DocIterator const & /*inset_pos*/, Buffer const & buffer = ploader.buffer(); if (!preview_wanted(params(), buffer)) return; - preview_->setAbsFile(includedFilename(buffer, params())); + preview_->setAbsFile(includedFileName(buffer, params())); docstring const snippet = latexString(*this); preview_->addPreview(snippet, ploader); } -void InsetInclude::addToToc(DocIterator const & cpit) +void InsetInclude::addToToc(DocIterator const & cpit, bool output_active, + UpdateType utype) const { - TocBackend & backend = buffer().tocBackend(); - if (isListings(params())) { if (label_) - label_->addToToc(cpit); - + label_->addToToc(cpit, output_active, utype); + TocBuilder & b = buffer().tocBackend().builder("listing"); + b.pushItem(cpit, screenLabel(), output_active); InsetListingsParams p(to_utf8(params()["lstparams"])); - string caption = p.getParamValue("caption"); - if (caption.empty()) + b.argumentItem(from_utf8(p.getParamValue("caption"))); + b.pop(); + } else { + Buffer const * const childbuffer = getChildBuffer(); + + TocBuilder & b = buffer().tocBackend().builder("child"); + docstring str = childbuffer ? childbuffer->fileName().displayName() + : from_ascii("?"); + b.pushItem(cpit, str, output_active); + b.pop(); + + if (!childbuffer) return; - Toc & toc = backend.toc("listing"); - docstring str = convert(toc.size() + 1) - + ". " + from_utf8(caption); - DocIterator pit = cpit; - toc.push_back(TocItem(pit, 0, str)); - return; - } - Buffer const * const childbuffer = getChildBuffer(); - if (!childbuffer) - return; - Toc & toc = backend.toc("child"); - docstring str = childbuffer->fileName().displayName(); - toc.push_back(TocItem(cpit, 0, str)); - - TocList & toclist = backend.tocs(); - childbuffer->tocBackend().update(); - TocList const & childtoclist = childbuffer->tocBackend().tocs(); - TocList::const_iterator it = childtoclist.begin(); - TocList::const_iterator const end = childtoclist.end(); - for(; it != end; ++it) - toclist[it->first].insert(toclist[it->first].end(), - it->second.begin(), it->second.end()); + // Include Tocs from children + childbuffer->tocBackend().update(output_active, utype); + for(auto const & pair : childbuffer->tocBackend().tocs()) { + string const & type = pair.first; + shared_ptr child_toc = pair.second; + shared_ptr toc = buffer().tocBackend().toc(type); + toc->insert(toc->end(), child_toc->begin(), child_toc->end()); + } + } } @@ -1033,7 +1181,7 @@ void InsetInclude::updateCommand() return; docstring old_label = label_->getParam("name"); - label_->updateCommand(old_label, false); + label_->updateLabel(old_label); // the label might have been adapted (duplicate) docstring new_label = label_->getParam("name"); if (old_label == new_label) @@ -1048,18 +1196,21 @@ void InsetInclude::updateCommand() setParams(p); } -void InsetInclude::updateLabels(ParIterator const & it, UpdateType utype) + +void InsetInclude::updateBuffer(ParIterator const & it, UpdateType utype) { + button_.update(screenLabel(), true); + Buffer const * const childbuffer = getChildBuffer(); if (childbuffer) { - childbuffer->updateLabels(Buffer::UpdateChildOnly, utype); + childbuffer->updateBuffer(Buffer::UpdateChildOnly, utype); return; } if (!isListings(params())) return; if (label_) - label_->updateLabels(it, utype); + label_->updateBuffer(it, utype); InsetListingsParams const par(to_utf8(params()["lstparams"])); if (par.getParamValue("caption").empty()) {