X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetInclude.cpp;h=88153c6d2d35941ad375977036d292062b5f6756;hb=3d4076b598deb18660e50ec9c327efc3b15f15d0;hp=b3e78d7954ce846d17b4405f421b88de62910ade;hpb=35f3f7cbc4c4bda01aee68cdd5c24abd53365954;p=lyx.git diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index b3e78d7954..88153c6d2d 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" @@ -32,6 +34,7 @@ #include "LyXRC.h" #include "Lexer.h" #include "MetricsInfo.h" +#include "output_plaintext.h" #include "output_xhtml.h" #include "OutputParams.h" #include "TextClass.h" @@ -47,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" @@ -160,7 +165,7 @@ 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) { @@ -169,7 +174,8 @@ InsetInclude::InsetInclude(Buffer * buf, InsetCommandParams const & p) 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(); } @@ -187,6 +193,8 @@ InsetInclude::InsetInclude(InsetInclude const & other) InsetInclude::~InsetInclude() { + if (isBufferLoaded()) + buffer().invalidateBibfileCache(); delete label_; } @@ -240,10 +248,11 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) // 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"])); @@ -263,7 +272,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", "{" + @@ -273,6 +282,7 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) } } } + cur.recordUndo(); setParams(p); cur.forceBufferUpdate(); } else @@ -378,7 +388,8 @@ docstring InsetInclude::screenLabel() const temp = listings_label_; break; case NONE: - LASSERT(false, /**/); + LASSERT(false, temp = buffer().B_("Unknown")); + break; } temp += ": "; @@ -438,31 +449,46 @@ Buffer * InsetInclude::loadIfNeeded() const // 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()); @@ -476,7 +502,7 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const 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(); @@ -489,44 +515,124 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const 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; + exportfile = exppath; mangled = DocFileName(included_file).mangledFileName(); } else { - exportfile = changeExtension(incfile, ".tex"); + 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)) { 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, 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; + string const tex_format = flavor2format(runparams.flavor); - Buffer * tmp = theBufferList().getBuffer(included_file); + switch (type(params())) { + case VERB: + case VERBAST: { + incfile = latex_path(incfile); + // FIXME UNICODE + 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())) { + incfile = latex_path(incfile); + // FIXME UNICODE + os << '\\' << from_ascii(params().getCmdName()) + << '{' << from_utf8(incfile) << '}'; + } else { + 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. + InsetListingsParams params(opt); + if (!params.params().empty()) + os << "[" << from_utf8(params.params()) << "]"; + os << '{' << from_utf8(incfile) << '}'; + break; + } + case INCLUDE: { + runparams.exportdata->addExternalFile(tex_format, writefile, + exportfile); + + // \include don't want extension and demands that the + // file really have .tex + incfile = changeExtension(incfile, string()); + incfile = latex_path(incfile); + // FIXME UNICODE + os << '\\' << from_ascii(params().getCmdName()) << '{' + << from_utf8(incfile) << '}'; + break; + } + case NONE: + break; + } + + 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) { + 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 (tmp->params().baseClass() != masterBuffer->params().baseClass()) { // FIXME UNICODE @@ -561,27 +667,68 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const 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 - // 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(); + // If the master has full unicode flavor (XeTeX, LuaTeX), + // the children must be encoded in plain utf8! + runparams.encoding = runparams.isFullUnicode() ? + encodings.fromLyXName("utf8-plain") + : &tmp->params().encoding(); runparams.master_language = buffer().params().language; - tmp->makeLaTeXFile(writefile, - masterFileName(buffer()).onlyPath().absFileName(), - runparams, false); + 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)) { + docstring msg = bformat(_("Included file `%1$s' " + "was not exported correctly.\nWarning: " + "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); + Alert::warning(_("Export failure"), 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) { + docstring msg = bformat(_("Included file `%1$s' " + "was not exported correctly.\nWarning: " + "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); + Alert::warning(_("Export failure"), 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 input@path, see ../Buffer.cpp. + // 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(); @@ -590,75 +737,16 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const // 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; + "into the temporary directory."), + from_utf8(included_file.absFileName())))); + return; } } } - - string const tex_format = (runparams.flavor == OutputParams::LATEX) ? - "latex" : "pdflatex"; - switch (type(params())) { - case VERB: - case VERBAST: { - incfile = latex_path(incfile); - // FIXME UNICODE - 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())) { - incfile = latex_path(incfile); - // FIXME UNICODE - os << '\\' << from_ascii(params().getCmdName()) - << '{' << from_utf8(incfile) << '}'; - } else { - incfile = changeExtension(incfile, ".tex"); - incfile = latex_path(incfile); - // FIXME UNICODE - os << '\\' << from_ascii(params().getCmdName()) - << '{' << from_utf8(incfile) << '}'; - } - break; - } - case LISTINGS: { - os << '\\' << from_ascii(params().getCmdName()); - string const opt = to_utf8(params()["lstparams"]); - // opt is set in QInclude dialog and should have passed validation. - InsetListingsParams params(opt); - if (!params.params().empty()) - os << "[" << from_utf8(params.params()) << "]"; - os << '{' << from_utf8(incfile) << '}'; - break; - } - case INCLUDE: { - runparams.exportdata->addExternalFile(tex_format, writefile, - exportfile); - - // \include don't want extension and demands that the - // file really have .tex - incfile = changeExtension(incfile, string()); - incfile = latex_path(incfile); - // FIXME UNICODE - os << '\\' << from_ascii(params().getCmdName()) << '{' - << from_utf8(incfile) << '}'; - break; - } - case NONE: - break; - } - - return 0; } -docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const &rp) const +docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const & rp) const { if (rp.inComment) return docstring(); @@ -702,24 +790,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; } @@ -744,13 +862,18 @@ 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)); - + Buffer * tmp = loadIfNeeded(); + if (tmp) { string const mangled = writefile.mangledFileName(); writefile = makeAbsPath(mangled, buffer().masterBuffer()->temppath()); @@ -761,7 +884,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, @@ -782,14 +905,13 @@ 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(); + string writefile; if (isLyXFileName(included_file)) writefile = changeExtension(included_file, ".sgml"); else @@ -803,6 +925,7 @@ void InsetInclude::validate(LaTeXFeatures & features) const features.includeFile(include_label, writefile); + features.useInsetLayout(getLayout()); if (isVerbatim(params())) features.require("verbatim"); else if (isListings(params())) @@ -811,9 +934,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 @@ -823,29 +946,27 @@ void InsetInclude::validate(LaTeXFeatures & features) const // otherwise it would always be the master buffer, // and nested includes would not work. features.setBuffer(*tmp); + features.runparams().is_child = true; tmp->validate(features); + features.runparams().is_child = false; features.setBuffer(buffer()); } } } -void InsetInclude::fillWithBibKeys(BiblioInfo & keys) 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); - } + Buffer * child = loadIfNeeded(); + if (!child) + 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) { @@ -871,7 +992,7 @@ 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) { @@ -887,9 +1008,9 @@ void InsetInclude::draw(PainterInfo & pi, int x, int y) const } -docstring InsetInclude::contextMenu(BufferView const &, int, int) const +string InsetInclude::contextMenuName() const { - return from_ascii("context-include"); + return "context-include"; } @@ -899,6 +1020,13 @@ Inset::DisplayType InsetInclude::display() const } +docstring InsetInclude::layoutName() const +{ + if (isListings(params())) + return from_ascii("IncludeListings"); + return InsetCommand::layoutName(); +} + // // preview stuff @@ -929,14 +1057,16 @@ bool preview_wanted(InsetCommandParams const & params, Buffer const & buffer) docstring latexString(InsetInclude const & inset) { - odocstringstream os; + TexRow texrow; + odocstringstream ods; + otexstream os(ods, texrow); // We don't need to set runparams.encoding since this will be done // by latex() anyway. OutputParams runparams(0); runparams.flavor = OutputParams::LATEX; inset.latex(os, runparams); - return os.str(); + return ods.str(); } @@ -967,13 +1097,13 @@ void InsetInclude::addPreview(DocIterator const & /*inset_pos*/, } -void InsetInclude::addToToc(DocIterator const & cpit) +void InsetInclude::addToToc(DocIterator const & cpit, bool output_active) const { TocBackend & backend = buffer().tocBackend(); if (isListings(params())) { if (label_) - label_->addToToc(cpit); + label_->addToToc(cpit, output_active); InsetListingsParams p(to_utf8(params()["lstparams"])); string caption = p.getParamValue("caption"); @@ -983,7 +1113,7 @@ void InsetInclude::addToToc(DocIterator const & cpit) docstring str = convert(toc.size() + 1) + ". " + from_utf8(caption); DocIterator pit = cpit; - toc.push_back(TocItem(pit, 0, str)); + toc.push_back(TocItem(pit, 0, str, output_active)); return; } Buffer const * const childbuffer = getChildBuffer(); @@ -992,10 +1122,10 @@ void InsetInclude::addToToc(DocIterator const & cpit) Toc & toc = backend.toc("child"); docstring str = childbuffer->fileName().displayName(); - toc.push_back(TocItem(cpit, 0, str)); + toc.push_back(TocItem(cpit, 0, str, output_active)); TocList & toclist = backend.tocs(); - childbuffer->tocBackend().update(); + childbuffer->tocBackend().update(output_active); TocList const & childtoclist = childbuffer->tocBackend().tocs(); TocList::const_iterator it = childtoclist.begin(); TocList::const_iterator const end = childtoclist.end(); @@ -1011,7 +1141,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) @@ -1026,8 +1156,11 @@ void InsetInclude::updateCommand() setParams(p); } + void InsetInclude::updateBuffer(ParIterator const & it, UpdateType utype) { + button_.update(screenLabel(), true); + Buffer const * const childbuffer = getChildBuffer(); if (childbuffer) { childbuffer->updateBuffer(Buffer::UpdateChildOnly, utype);