X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetInclude.cpp;h=f966fbcf3046899c1e6a7bb28584730f86ee10b4;hb=b73879691f816b0874d9dec0c09e2db7889c4e8e;hp=4e44ec8c87800f1825b2d65da6991fb9b6a1d837;hpb=5fdc577badb1cb133d6a0dc7d831bb1f82576adb;p=lyx.git diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index 4e44ec8c87..f966fbcf30 100644 --- a/src/insets/InsetInclude.cpp +++ b/src/insets/InsetInclude.cpp @@ -99,7 +99,7 @@ Types type(string const & s) return VERB; if (s == "verbatiminput*") return VERBAST; - if (s == "lstinputlisting") + if (s == "lstinputlisting" || s == "inputminted") return LISTINGS; if (s == "include") return INCLUDE; @@ -165,15 +165,15 @@ InsetLabel * createLabel(Buffer * buf, docstring const & label_str) return new InsetLabel(buf, icp); } -} // namespace anon +} // namespace InsetInclude::InsetInclude(Buffer * buf, InsetCommandParams const & p) : InsetCommand(buf, p), include_label(uniqueID()), - preview_(new RenderMonitoredPreview(this)), failedtoload_(false), + preview_(make_unique(this)), failedtoload_(false), set_label_(false), label_(0), child_buffer_(0) { - preview_->fileChanged(bind(&InsetInclude::fileChanged, this)); + preview_->connect([=](){ fileChanged(); }); if (isListings(params())) { InsetListingsParams listing_params(to_utf8(p["lstparams"])); @@ -185,10 +185,10 @@ InsetInclude::InsetInclude(Buffer * buf, InsetCommandParams const & p) InsetInclude::InsetInclude(InsetInclude const & other) : InsetCommand(other), include_label(other.include_label), - preview_(new RenderMonitoredPreview(this)), failedtoload_(false), + preview_(make_unique(this)), failedtoload_(false), set_label_(false), label_(0), child_buffer_(0) { - preview_->fileChanged(bind(&InsetInclude::fileChanged, this)); + preview_->connect([=](){ fileChanged(); }); if (other.label_) label_ = new InsetLabel(*other.label_); @@ -198,7 +198,10 @@ InsetInclude::InsetInclude(InsetInclude const & other) InsetInclude::~InsetInclude() { if (isBufferLoaded()) - buffer().invalidateBibfileCache(); + /* We do not use buffer() because Coverity believes that this + * may throw an exception. Actually this code path is not + * taken when buffer_ == 0 */ + buffer_->invalidateBibfileCache(); delete label_; } @@ -262,24 +265,24 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) InsetListingsParams new_params(to_utf8(p["lstparams"])); docstring const new_label = from_utf8(new_params.getParamValue("label")); - + if (new_label.empty()) { delete label_; label_ = 0; } else { docstring old_label; - if (label_) + if (label_) old_label = label_->getParam("name"); else { label_ = createLabel(buffer_, new_label); label_->setBuffer(buffer()); - } + } if (new_label != old_label) { label_->updateLabelAndRefs(new_label, &cur); // the label might have been adapted (duplicate) if (new_label != label_->getParam("name")) { - new_params.addParam("label", "{" + + new_params.addParam("label", "{" + to_utf8(label_->getParam("name")) + "}", true); p["lstparams"] = from_utf8(new_params.params()); } @@ -310,7 +313,7 @@ void InsetInclude::editIncluded(string const & file) lyx::dispatch(fr); } else // tex file or other text file in verbatim mode - formats.edit(buffer(), + theFormats().edit(buffer(), support::makeAbsPath(file, support::onlyPath(buffer().absFileName())), "text"); } @@ -409,7 +412,7 @@ docstring InsetInclude::screenLabel() const Buffer * InsetInclude::getChildBuffer() const { - Buffer * childBuffer = loadIfNeeded(); + Buffer * childBuffer = loadIfNeeded(); // FIXME RECURSIVE INCLUDE // This isn't sufficient, as the inclusion could be downstream. @@ -424,7 +427,7 @@ Buffer * InsetInclude::loadIfNeeded() const // 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; @@ -595,15 +598,87 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const break; } case LISTINGS: { + // Here, listings and minted have sligthly different behaviors. + // Using listings, it is always possible to have a caption, + // even for non-floats. Using minted, only floats can have a + // caption. So, with minted we use the following strategy. + // If a caption was specified but the float parameter was not, + // we ourselves add a caption above the listing (because the + // listing comes from a file and might span several pages). + // Otherwise, if float was specified, the floating listing + // environment provided by minted is used. In either case, the + // label parameter is taken as the label by which the float + // can be referenced, otherwise it will have the meaning + // intended by minted. In this last case, the label will + // serve as a sort of caption that, however, will be shown + // by minted only if the frame parameter is also specified. + bool const use_minted = buffer().params().use_minted; 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) << '}'; + InsetListingsParams lstparams(opt); + string parameters = lstparams.params(); + string language; + string caption; + string label; + string placement; + bool isfloat = lstparams.isFloat(); + if (use_minted) { + // Get float placement, language, caption, and + // label, then remove the relative options. + vector opts = + getVectorFromString(parameters, ",", false); + for (size_t i = 0; i < opts.size(); ++i) { + if (prefixIs(opts[i], "float")) { + if (prefixIs(opts[i], "float=")) + placement = opts[i].substr(6); + opts.erase(opts.begin() + i--); + } else if (prefixIs(opts[i], "language=")) { + language = opts[i].substr(9); + opts.erase(opts.begin() + i--); + } else if (prefixIs(opts[i], "caption=")) { + caption = opts[i].substr(8); + opts.erase(opts.begin() + i--); + } else if (prefixIs(opts[i], "label=")) { + label = opts[i].substr(6); + opts.erase(opts.begin() + i--); + } + } + if (!label.empty()) { + if (isfloat || !caption.empty()) + label = trim(label, "{}"); + else + opts.push_back("label=" + label); + } + parameters = getStringFromVector(opts, ","); + } + if (language.empty()) + language = "TeX"; + if (use_minted && isfloat) { + os << breakln << "\\begin{listing}"; + if (!placement.empty()) + os << '[' << placement << "]"; + os << breakln; + } else if (use_minted && !caption.empty()) { + os << breakln << "\\lyxmintcaption[t]{" << caption; + if (!label.empty()) + os << "\\label{" << label << "}"; + os << "}\n"; + } + os << (use_minted ? "\\inputminted" : "\\lstinputlisting"); + if (!parameters.empty()) + os << "[" << parameters << "]"; + if (use_minted) + os << '{' << ascii_lowercase(language) << '}'; + os << '{' << incfile << '}'; + if (use_minted && isfloat) { + if (!caption.empty()) + os << breakln << "\\caption{" << caption << "}"; + if (!label.empty()) + os << breakln << "\\label{" << label << "}"; + os << breakln << "\\end{listing}\n"; + } break; } case INCLUDE: { @@ -640,7 +715,8 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const "file\n`%1$s'\n" "Please, check whether it actually exists."), included_file.displayName()); - Alert::warning(_("Missing included file"), text); + throw ExceptionMessage(ErrorException, _("Error: "), + text); } return; } @@ -695,7 +771,7 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const // 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))); + theFormats().extension(inc_format))); // FIXME: handle non existing files // The included file might be written in a different encoding @@ -822,20 +898,20 @@ docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const & rp) const return docstring(); // are we generating only some paragraphs, or all of them? - bool const all_pars = !rp.dryrun || - (rp.par_begin == 0 && + 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(); } @@ -958,8 +1034,16 @@ void InsetInclude::validate(LaTeXFeatures & features) const features.useInsetLayout(getLayout()); if (isVerbatim(params())) features.require("verbatim"); - else if (isListings(params())) - features.require("listings"); + else if (isListings(params())) { + if (buffer().params().use_minted) { + features.require("minted"); + string const opts = to_utf8(params()["lstparams"]); + InsetListingsParams lstpars(opts); + if (!lstpars.isFloat() && contains(opts, "caption=")) + features.require("lyxmintcaption"); + } else + features.require("listings"); + } // Here we must do the fun stuff... // Load the file in the include if it needs @@ -1018,7 +1102,7 @@ void InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const } else { if (!set_label_) { set_label_ = true; - button_.update(screenLabel(), true); + button_.update(screenLabel(), true, false); } button_.metrics(mi, dim); } @@ -1125,7 +1209,7 @@ void add_preview(RenderMonitoredPreview & renderer, InsetInclude const & inset, } } -} // namespace anon +} // namespace void InsetInclude::addPreview(DocIterator const & /*inset_pos*/, @@ -1141,12 +1225,12 @@ void InsetInclude::addPreview(DocIterator const & /*inset_pos*/, void InsetInclude::addToToc(DocIterator const & cpit, bool output_active, - UpdateType utype) const + UpdateType utype, TocBackend & backend) const { if (isListings(params())) { if (label_) - label_->addToToc(cpit, output_active, utype); - TocBuilder & b = buffer().tocBackend().builder("listing"); + label_->addToToc(cpit, output_active, utype, backend); + TocBuilder & b = backend.builder("listing"); b.pushItem(cpit, screenLabel(), output_active); InsetListingsParams p(to_utf8(params()["lstparams"])); b.argumentItem(from_utf8(p.getParamValue("caption"))); @@ -1154,7 +1238,7 @@ void InsetInclude::addToToc(DocIterator const & cpit, bool output_active, } else { Buffer const * const childbuffer = getChildBuffer(); - TocBuilder & b = buffer().tocBackend().builder("child"); + TocBuilder & b = backend.builder("child"); docstring str = childbuffer ? childbuffer->fileName().displayName() : from_ascii("?"); b.pushItem(cpit, str, output_active); @@ -1163,14 +1247,18 @@ void InsetInclude::addToToc(DocIterator const & cpit, bool output_active, if (!childbuffer) return; - // Include Tocs from children + // 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); - 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()); - } + // 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). + for (pair const & name + : childbuffer->params().documentClass().outlinerNames()) + backend.addName(name.first, translateIfPossible(name.second)); } } @@ -1193,13 +1281,13 @@ void InsetInclude::updateCommand() InsetListingsParams par(to_utf8(params()["lstparams"])); par.addParam("label", "{" + to_utf8(new_label) + "}", true); p["lstparams"] = from_utf8(par.params()); - setParams(p); + setParams(p); } void InsetInclude::updateBuffer(ParIterator const & it, UpdateType utype) { - button_.update(screenLabel(), true); + button_.update(screenLabel(), true, false); Buffer const * const childbuffer = getChildBuffer(); if (childbuffer) {