X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=3652e7af12eff8927f559c37711f8a4f2b1a5cd8;hb=2de30c62f8d671a8c8d4d52a6a7310e2c5ca84de;hp=431f3f6c920c0a6769031b0e1bbe1ee5125e3e9f;hpb=ca8709aaf5f5f14aae1978403e13aac3a93506aa;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 431f3f6c92..3652e7af12 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -57,6 +57,7 @@ #include "PDFOptions.h" #include "SpellChecker.h" #include "sgml.h" +#include "texstream.h" #include "TexRow.h" #include "Text.h" #include "TextClass.h" @@ -78,6 +79,7 @@ #include "mathed/MathMacroTemplate.h" #include "mathed/MathSupport.h" +#include "graphics/GraphicsCache.h" #include "graphics/PreviewLoader.h" #include "frontends/alert.h" @@ -107,12 +109,12 @@ #include "support/types.h" #include "support/bind.h" -#include "support/shared_ptr.h" #include #include #include #include +#include #include #include #include @@ -236,8 +238,8 @@ public: /// positions of child buffers in the buffer typedef map BufferPositionMap; struct ScopeBuffer { - ScopeBuffer() {} - ScopeBuffer(DocIterator const & s,Buffer const * b) + ScopeBuffer() : buffer(0) {} + ScopeBuffer(DocIterator const & s, Buffer const * b) : scope(s), buffer(b) {} DocIterator scope; Buffer const * buffer; @@ -419,9 +421,9 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_, file_fully_loaded(false), file_format(LYX_FORMAT), need_format_backup(false), ignore_parent(false), toc_backend(owner), macro_lock(false), timestamp_(0), checksum_(0), wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false), - bibfile_cache_valid_(false), cite_labels_valid_(false), inset(0), - preview_loader_(0), cloned_buffer_(cloned_buffer), clone_list_(0), - doing_export(false), parent_buffer(0), + bibfile_cache_valid_(false), cite_labels_valid_(false), preview_error_(false), + inset(0), preview_loader_(0), cloned_buffer_(cloned_buffer), + clone_list_(0), doing_export(false), parent_buffer(0), word_count_(0), char_count_(0), blank_count_(0) { if (!cloned_buffer_) { @@ -908,8 +910,8 @@ int Buffer::readHeader(Lexer & lex) params().html_latex_end.clear(); params().html_math_img_scale = 1.0; params().output_sync_macro.erase(); - params().setLocalLayout(string(), false); - params().setLocalLayout(string(), true); + params().setLocalLayout(docstring(), false); + params().setLocalLayout(docstring(), true); for (int i = 0; i < 4; ++i) { params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i]; @@ -948,15 +950,13 @@ int Buffer::readHeader(Lexer & lex) "%1$s %2$s\n"), from_utf8(token), lex.getDocString()); - errorList.push_back(ErrorItem(_("Document header error"), - s, -1, 0, 0)); + errorList.push_back(ErrorItem(_("Document header error"), s)); } } } if (begin_header_line) { docstring const s = _("\\begin_header is missing"); - errorList.push_back(ErrorItem(_("Document header error"), - s, -1, 0, 0)); + errorList.push_back(ErrorItem(_("Document header error"), s)); } params().makeDocumentClass(); @@ -978,8 +978,7 @@ bool Buffer::readDocument(Lexer & lex) if (!lex.checkFor("\\begin_document")) { docstring const s = _("\\begin_document is missing"); - errorList.push_back(ErrorItem(_("Document header error"), - s, -1, 0, 0)); + errorList.push_back(ErrorItem(_("Document header error"), s)); } readHeader(lex); @@ -1321,7 +1320,7 @@ Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn, FileName Buffer::getBackupName() const { FileName const & fn = fileName(); string const fname = fn.onlyFileNameWithoutExt(); - string const fext = fn.extension(); + string const fext = fn.extension() + "~"; string const fpath = lyxrc.backupdir_path.empty() ? fn.onlyPath().absFileName() : lyxrc.backupdir_path; @@ -1659,9 +1658,11 @@ bool Buffer::makeLaTeXFile(FileName const & fname, { OutputParams runparams = runparams_in; - // XeTeX with TeX fonts is only safe with ASCII encoding, - // but the "flavor" is not known in BufferParams::encoding(). - if (!params().useNonTeXFonts && (runparams.flavor == OutputParams::XETEX)) + // XeTeX with TeX fonts is only safe with ASCII encoding (see also #9740), + // Check here, because the "flavor" is not known in BufferParams::encoding() + // (power users can override this safety measure selecting "utf8-plain"). + if (!params().useNonTeXFonts && (runparams.flavor == OutputParams::XETEX) + && (runparams.encoding->name() != "utf8-plain")) runparams.encoding = encodings.fromLyXName("ascii"); string const encoding = runparams.encoding->iconvName(); @@ -1682,7 +1683,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname, ErrorList & errorList = d->errorLists["Export"]; errorList.clear(); bool failed_export = false; - otexstream os(ofs, d->texrow); + otexstream os(ofs); // make sure we are ready to export // this needs to be done before we validate @@ -1692,7 +1693,6 @@ bool Buffer::makeLaTeXFile(FileName const & fname, updateMacroInstances(OutputUpdate); try { - os.texrow().reset(); writeLaTeXSource(os, original_path, runparams, output); } catch (EncodingException const & e) { @@ -1705,17 +1705,17 @@ bool Buffer::makeLaTeXFile(FileName const & fname, 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.pos + 1)); + {e.par_id, e.pos}, {e.par_id, e.pos + 1})); failed_export = true; } catch (iconv_codecvt_facet_exception const & e) { errorList.push_back(ErrorItem(_("iconv conversion failed"), - _(e.what()), -1, 0, 0)); + _(e.what()))); failed_export = true; } catch (exception const & e) { errorList.push_back(ErrorItem(_("conversion failed"), - _(e.what()), -1, 0, 0)); + _(e.what()))); failed_export = true; } catch (...) { @@ -1723,6 +1723,8 @@ bool Buffer::makeLaTeXFile(FileName const & fname, lyx_exit(1); } + d->texrow = move(os.texrow()); + ofs.close(); if (ofs.fail()) { failed_export = true; @@ -1747,8 +1749,10 @@ void Buffer::writeLaTeXSource(otexstream & os, OutputParams runparams = runparams_in; // XeTeX with TeX fonts is only safe with ASCII encoding, - // but the "flavor" is not known in BufferParams::encoding(). - if (!params().useNonTeXFonts && (runparams.flavor == OutputParams::XETEX)) + // Check here, because the "flavor" is not known in BufferParams::encoding() + // (power users can override this safety measure selecting "utf8-plain"). + if (!params().useNonTeXFonts && (runparams.flavor == OutputParams::XETEX) + && (runparams.encoding->name() != "utf8-plain")) runparams.encoding = encodings.fromLyXName("ascii"); // FIXME: when only the current paragraph is shown, this is ignored // (or not reached) and characters encodable in the current @@ -1871,6 +1875,47 @@ void Buffer::writeLaTeXSource(otexstream & os, // Write the preamble runparams.use_babel = params().writeLaTeX(os, features, d->filename.onlyPath()); + + if (!runparams.dryrun && features.hasPolyglossiaExclusiveLanguages() + && !features.hasOnlyPolyglossiaLanguages()) { + docstring blangs; + docstring plangs; + vector bll = features.getBabelExclusiveLanguages(); + vector pll = features.getPolyglossiaExclusiveLanguages(); + if (!bll.empty()) { + docstring langs; + for (vector::const_iterator it = bll.begin(); it != bll.end(); ++it) { + if (!langs.empty()) + langs += ", "; + langs += _(*it); + } + blangs = bll.size() > 1 ? + support::bformat(_("The languages %1$s are only supported by Babel."), langs) + : support::bformat(_("The language %1$s is only supported by Babel."), langs); + } + if (!pll.empty()) { + docstring langs; + for (vector::const_iterator it = pll.begin(); it != pll.end(); ++it) { + if (!langs.empty()) + langs += ", "; + langs += _(*it); + } + plangs = pll.size() > 1 ? + support::bformat(_("The languages %1$s are only supported by Polyglossia."), langs) + : support::bformat(_("The language %1$s is only supported by Polyglossia."), langs); + if (!blangs.empty()) + plangs += "\n"; + } + + frontend::Alert::warning( + _("Incompatible Languages!"), + support::bformat( + _("You cannot use the following languages " + "together in one LaTeX document because " + "they require conflicting language packages:\n" + "%1$s%2$s"), + plangs, blangs)); + } // Japanese might be required only in some children of a document, // but once required, we must keep use_japanese true. @@ -1884,8 +1929,14 @@ void Buffer::writeLaTeXSource(otexstream & os, } // make the body. + // mark the beginning of the body to separate it from InPreamble insets + os.texrow().start(TexRow::beginDocument()); os << "\\begin{document}\n"; + // mark the start of a new paragraph by simulating a newline, + // so that os.afterParbreak() returns true at document start + os.lastChar('\n'); + // output the parent macros MacroSet::iterator it = parentMacros.begin(); MacroSet::iterator end = parentMacros.end(); @@ -1896,8 +1947,6 @@ void Buffer::writeLaTeXSource(otexstream & os, } // output_preamble - os.texrow().start(paragraphs().begin()->id(), 0); - LYXERR(Debug::INFO, "preamble finished, now the body."); // the real stuff @@ -1918,8 +1967,6 @@ void Buffer::writeLaTeXSource(otexstream & os, } runparams_in.encoding = runparams.encoding; - os.texrow().finalize(); - LYXERR(Debug::INFO, "Finished making LaTeX file."); LYXERR(Debug::INFO, "Row count was " << os.texrow().rows() - 1 << '.'); } @@ -1955,7 +2002,7 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, LaTeXFeatures features(*this, params(), runparams); validate(features); - d->texrow.reset(false); + d->texrow.reset(); DocumentClass const & tclass = params().documentClass(); string const & top_element = tclass.latexname(); @@ -1981,7 +2028,7 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, else os << " PUBLIC \"-//OASIS//DTD DocBook V4.2//EN\""; - docstring preamble = from_utf8(params().preamble); + docstring preamble = params().preamble; if (runparams.flavor != OutputParams::XML ) { preamble += "\n"; preamble += "\n"; @@ -2084,14 +2131,14 @@ void Buffer::writeLyXHTMLSource(odocstream & os, if (!styles.empty()) os << "\n\n" << styles << '\n'; - styles = from_utf8(features.getPreambleSnippets()); + styles = features.getPreambleSnippets().str; if (!styles.empty()) os << "\n\n" << styles << '\n'; // we will collect CSS information in a stream, and then output it // either here, as part of the header, or else in a separate file. odocstringstream css; - styles = from_utf8(features.getCSSSnippets()); + styles = features.getCSSSnippets(); if (!styles.empty()) css << "/* LyX Provided Styles */\n" << styles << '\n'; @@ -2146,7 +2193,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os, if (output_body) { bool const output_body_tag = (output != IncludedFile); if (output_body_tag) - os << "\n"; + os << "\n"; XHTMLStream xs(os); if (output != IncludedFile) // if we're an included file, the counters are in the master. @@ -2214,8 +2261,8 @@ void Buffer::validate(LaTeXFeatures & features) const if (!features.runparams().is_child) params().validate(features); - for_each(paragraphs().begin(), paragraphs().end(), - bind(&Paragraph::validate, _1, ref(features))); + for (Paragraph const & p : paragraphs()) + p.validate(features); if (lyxerr.debugging(Debug::LATEX)) { features.showStruct(); @@ -2477,7 +2524,7 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) size_t pos = format.find(' '); if (pos != string::npos) format = format.substr(0, pos); - enable = params().isExportable(format); + enable = params().isExportable(format, false); if (!enable) flag.message(bformat( _("Don't know how to export to format: %1$s"), arg)); @@ -2489,7 +2536,7 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; case LFUN_BUILD_PROGRAM: - enable = params().isExportable("program"); + enable = params().isExportable("program", false); break; case LFUN_BRANCH_ACTIVATE: @@ -2871,11 +2918,9 @@ void Buffer::getLanguages(std::set & languages) const DocIterator Buffer::getParFromID(int const id) const { Buffer * buf = const_cast(this); - if (id < 0) { - // John says this is called with id == -1 from undo - lyxerr << "getParFromID(), id: " << id << endl; + if (id < 0) + // This means non-existent return doc_iterator_end(buf); - } for (DocIterator it = doc_iterator_begin(buf); !it.atEnd(); it.forwardPar()) if (it.paragraph().id() == id) @@ -3511,7 +3556,7 @@ void Buffer::updateMacroInstances(UpdateType utype) const MacroContext mc = MacroContext(this, it); for (DocIterator::idx_type i = 0; i < n; ++i) { MathData & data = minset->cell(i); - data.updateMacros(0, mc, utype); + data.updateMacros(0, mc, utype, 0); } } } @@ -3709,17 +3754,15 @@ unique_ptr Buffer::getSourceCode(odocstream & os, string const & format, // in order to know if we should output polyglossia // macros (instead of babel macros) LaTeXFeatures features(*this, params(), runparams); - params().validate(features); + validate(features); runparams.use_polyglossia = features.usePolyglossia(); - texrow = make_unique(); - texrow->newline(); - texrow->newline(); // latex or literate - otexstream ots(os, *texrow); - + otexstream ots(os); + // output above + ots.texrow().newlines(2); // the real stuff latexParagraphs(*this, text(), ots, runparams); - texrow->finalize(); + texrow = ots.releaseTexRow(); // Restore the parenthood if (!master) @@ -3754,14 +3797,13 @@ unique_ptr Buffer::getSourceCode(odocstream & os, string const & format, writeDocBookSource(os, absFileName(), runparams, output); } else { // latex or literate - texrow = make_unique(); - texrow->newline(); - texrow->newline(); - otexstream ots(os, *texrow); + otexstream ots(os); + // output above + ots.texrow().newlines(2); if (master) runparams.is_child = true; writeLaTeXSource(ots, string(), runparams, output); - texrow->finalize(); + texrow = ots.releaseTexRow(); } } return texrow; @@ -3847,7 +3889,7 @@ public: /// virtual shared_ptr clone() const { - return shared_ptr(new AutoSaveBuffer(*this)); + return make_shared(*this); } /// int start() @@ -4310,26 +4352,22 @@ Buffer::ExportStatus Buffer::preview(string const & format, bool includeall) con ExportStatus const status = doExport(format, true, false, result_file); FileName const previewFile(result_file); - LATTEST (isClone()); - d->cloned_buffer_->d->preview_file_ = previewFile; - d->cloned_buffer_->d->preview_format_ = format; - d->cloned_buffer_->d->preview_error_ = (status != ExportSuccess); + Impl * theimpl = isClone() ? d->cloned_buffer_->d : d; + theimpl->preview_file_ = previewFile; + theimpl->preview_format_ = format; + theimpl->preview_error_ = (status != ExportSuccess); if (status != ExportSuccess) return status; - if (previewFile.exists()) { - if (!formats.view(*this, previewFile, format)) - return PreviewError; - else - return PreviewSuccess; - } - else { - // Successful export but no output file? - // Probably a bug in error detection. - LATTEST (status != ExportSuccess); - return status; - } + if (previewFile.exists()) + return formats.view(*this, previewFile, format) ? + PreviewSuccess : PreviewError; + + // Successful export but no output file? + // Probably a bug in error detection. + LATTEST(status != ExportSuccess); + return status; } @@ -4481,56 +4519,33 @@ Buffer::ReadStatus Buffer::loadThisLyXFile(FileName const & fn) void Buffer::bufferErrors(TeXErrors const & terr, ErrorList & errorList) const { - TeXErrors::Errors::const_iterator it = terr.begin(); - TeXErrors::Errors::const_iterator end = terr.end(); - ListOfBuffers clist = getDescendents(); - ListOfBuffers::const_iterator cen = clist.end(); - - for (; it != end; ++it) { - int id_start = -1; - int pos_start = -1; - int errorRow = it->error_in_line; + for (auto const & err : terr) { + TexRow::TextEntry start, end = TexRow::text_none; + int errorRow = err.error_in_line; Buffer const * buf = 0; Impl const * p = d; - if (it->child_name.empty()) - p->texrow.getIdFromRow(errorRow, id_start, pos_start); + if (err.child_name.empty()) + tie(start, end) = p->texrow.getEntriesFromRow(errorRow); else { // The error occurred in a child - ListOfBuffers::const_iterator cit = clist.begin(); - for (; cit != cen; ++cit) { + for (Buffer const * child : getDescendents()) { string const child_name = - DocFileName(changeExtension( - (*cit)->absFileName(), "tex")). - mangledFileName(); - if (it->child_name != child_name) + DocFileName(changeExtension(child->absFileName(), "tex")). + mangledFileName(); + if (err.child_name != child_name) continue; - (*cit)->d->texrow.getIdFromRow(errorRow, - id_start, pos_start); - if (id_start != -1) { + tie(start, end) = child->d->texrow.getEntriesFromRow(errorRow); + if (!TexRow::isNone(start)) { buf = d->cloned_buffer_ - ? (*cit)->d->cloned_buffer_->d->owner_ - : (*cit)->d->owner_; - p = (*cit)->d; + ? child->d->cloned_buffer_->d->owner_ + : child->d->owner_; + p = child->d; break; } } } - int id_end = -1; - int pos_end = -1; - bool found; - do { - ++errorRow; - found = p->texrow.getIdFromRow(errorRow, id_end, pos_end); - } while (found && id_start == id_end && pos_start == pos_end); - - if (id_start != id_end) { - // Next registered position is outside the inset where - // the error occurred, so signal end-of-paragraph - pos_end = 0; - } - - errorList.push_back(ErrorItem(it->error_desc, - it->error_text, id_start, pos_start, pos_end, buf)); + errorList.push_back(ErrorItem(err.error_desc, err.error_text, + start, end, buf)); } } @@ -4618,6 +4633,11 @@ static depth_type getDepth(DocIterator const & it) if (!it[i].inset().inMathed()) depth += it[i].paragraph().getDepth() + 1; // remove 1 since the outer inset does not count + // we should have at least one non-math inset, so + // depth should nevery be 0. but maybe it is worth + // marking this, just in case. + LATTEST(depth > 0); + // coverity[INTEGER_OVERFLOW] return depth - 1; } @@ -4673,7 +4693,7 @@ static bool needEnumCounterReset(ParIterator const & it) --prev_it.top().pit(); Paragraph const & prev_par = *prev_it; if (prev_par.getDepth() <= cur_depth) - return prev_par.layout().labeltype != LABEL_ENUMERATE; + return prev_par.layout().name() != par.layout().name(); } // start of nested inset: reset return true; @@ -4757,8 +4777,12 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const break; } + // Increase the master counter? + if (layout.stepmastercounter && needEnumCounterReset(it)) + counters.stepMaster(enumcounter, utype); + // Maybe we have to reset the enumeration counter. - if (needEnumCounterReset(it)) + if (!layout.resumecounter && needEnumCounterReset(it)) counters.reset(enumcounter); counters.step(enumcounter, utype);