X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=d68ef97c7a48c9eccce5515598ecdc983665eb51;hb=0011f47885e070cf36e92d3a2f11f29ce1d4fdf4;hp=5fac06411b0f9d537e34255dc023ba7983fa5921;hpb=4ab6f265e992c7e2e9ecf47acd6e43893d98ae58;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 5fac06411b..d68ef97c7a 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -14,6 +14,7 @@ #include "Buffer.h" #include "Author.h" +#include "LayoutFile.h" #include "BiblioInfo.h" #include "BranchList.h" #include "buffer_funcs.h" @@ -50,16 +51,16 @@ #include "ParagraphParameters.h" #include "ParIterator.h" #include "PDFOptions.h" -#include "Session.h" #include "sgml.h" #include "TexRow.h" #include "TexStream.h" -#include "TextClassList.h" #include "Text.h" +#include "TextClass.h" #include "TocBackend.h" #include "Undo.h" #include "VCBackend.h" #include "version.h" +#include "WordList.h" #include "insets/InsetBibitem.h" #include "insets/InsetBibtex.h" @@ -98,10 +99,12 @@ #include #include +#include #include -#include +#include #include -#include +#include +#include using namespace std; using namespace lyx::support; @@ -113,12 +116,12 @@ namespace os = support::os; namespace { -int const LYX_FORMAT = 315; // Richard Heck: column separation - -} // namespace anon - +int const LYX_FORMAT = 321; typedef map DepClean; +typedef map > RefCache; + +} // namespace anon class Buffer::Impl { @@ -163,9 +166,6 @@ public: */ bool file_fully_loaded; - /// our Text that should be wrapped in an InsetText - InsetText inset; - /// mutable TocBackend toc_backend; @@ -173,6 +173,8 @@ public: typedef pair ScopeMacro; typedef map PositionScopeMacroMap; typedef map NamePositionScopeMacroMap; + /// map from the macro name to the position map, + /// which maps the macro definition position to the scope and the MacroData. NamePositionScopeMacroMap macros; bool macro_lock; @@ -180,7 +182,9 @@ public: typedef map BufferPositionMap; typedef pair ScopeBuffer; typedef map PositionScopeBufferMap; + /// position of children buffers in this buffer BufferPositionMap children_positions; + /// map from children inclusion positions to their scope and their buffer PositionScopeBufferMap position_to_children; /// Container for all sort of Buffer dependant errors. @@ -203,6 +207,11 @@ public: /// A cache for the bibfiles (including bibfiles of loaded child /// documents), needed for appropriate update of natbib labels. mutable EmbeddedFileList bibfilesCache_; + + mutable RefCache ref_cache_; + + /// our Text that should be wrapped in an InsetText + InsetText inset; }; /// Creates the per buffer temporary directory @@ -227,12 +236,11 @@ static FileName createBufferTmpDir() Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_) : parent_buffer(0), lyx_clean(true), bak_clean(true), unnamed(false), read_only(readonly_), filename(file), file_fully_loaded(false), - inset(params), toc_backend(&parent), macro_lock(false), + toc_backend(&parent), macro_lock(false), embedded_files(), timestamp_(0), checksum_(0), wa_(0), undo_(parent) { temppath = createBufferTmpDir(); - inset.setAutoBreakRows(true); lyxvc.setBuffer(&parent); if (use_gui) wa_ = new frontend::WorkAreaManager; @@ -244,6 +252,9 @@ Buffer::Buffer(string const & file, bool readonly) { LYXERR(Debug::INFO, "Buffer::Buffer()"); + d->inset.setBuffer(*this); + d->inset.initParagraphs(*this); + d->inset.setAutoBreakRows(true); d->inset.getText(0)->setMacrocontextPosition(par_iterator_begin()); } @@ -257,16 +268,9 @@ Buffer::~Buffer() // GuiView already destroyed gui_ = 0; - Buffer const * master = masterBuffer(); - if (master != this && use_gui) { - // We are closing buf which was a child document so we - // must update the labels and section numbering of its master - // Buffer. - updateLabels(*master); - master->updateMacros(); - } - - resetChildDocuments(false); + // clear references to children in macro tables + d->children_positions.clear(); + d->position_to_children.clear(); if (!d->temppath.destroyDirectory()) { Alert::warning(_("Could not remove temporary directory"), @@ -497,7 +501,8 @@ int Buffer::readHeader(Lexer & lex) LYXERR(Debug::PARSER, "Handling document header token: `" << token << '\''); - string unknown = params().readToken(lex, token, d->filename.onlyPath()); + string unknown = params().readToken(lex, token, d->filename.onlyPath(), + d->temppath); if (!unknown.empty()) { if (unknown[0] != '\\' && token == "\\textclass") { Alert::warning(_("Unknown document class"), @@ -520,7 +525,7 @@ int Buffer::readHeader(Lexer & lex) s, -1, 0, 0)); } - params().makeTextClass(); + params().makeDocumentClass(); return unknown_tokens; } @@ -570,6 +575,22 @@ bool Buffer::readDocument(Lexer & lex) // read main text bool const res = text().read(*this, lex, errorList, &(d->inset)); + // Enable embeded files, which will set temp path and move + // inconsistent inzip files if needed. + try { + embeddedFiles().validate(*this); + embeddedFiles().enable(params().embedded, *this, false); + } catch (ExceptionMessage const & message) { + Alert::error(message.title_, message.details_); + Alert::warning(_("Failed to read embedded files"), + _("Due to most likely a bug, LyX failed to locate all embedded " + "file. If you unzip the LyX file, you should be able to see and " + "open content.lyx which is your main text. You may also be able " + "to recover some embedded files. Please report this bug to the " + "lyx-devel mailing list.")); + return false; + } + updateMacros(); updateMacroInstances(); return res; @@ -591,7 +612,7 @@ void Buffer::insertStringAsLines(ParagraphList & pars, if (*cit == '\n') { if (autobreakrows && (!par.empty() || par.allowEmpty())) { breakParagraph(params(), pars, pit, pos, - par.layout()->isEnvironment()); + par.layout().isEnvironment()); ++pit; pos = 0; space_inserted = true; @@ -904,18 +925,18 @@ bool Buffer::writeFile(FileName const & fname) const } if (!retval) { - message(str + _(" could not write file!.")); + message(str + _(" could not write file!")); return false; } removeAutosaveFile(d->filename.absFilename()); if (params().embedded) { - message(str + _(" writing embedded files!.")); + message(str + _(" writing embedded files.")); // if embedding is enabled, write file.lyx and all the embedded files // to the zip file fname. if (!d->embedded_files.writeFile(fname, *this)) { - message(str + _(" could not write embedded files!.")); + message(str + _(" could not write embedded files!")); return false; } } @@ -1061,6 +1082,8 @@ void Buffer::writeLaTeXSource(odocstream & os, OutputParams const & runparams_in, bool const output_preamble, bool const output_body) const { + // The child documents, if any, shall be already loaded at this point. + OutputParams runparams = runparams_in; // validate the buffer. @@ -1125,12 +1148,10 @@ void Buffer::writeLaTeXSource(odocstream & os, LYXERR(Debug::INFO, "preamble finished, now the body."); - // load children, if not already done. - // This includes an updateMacro() call. // Don't move this behind the parent_buffer=0 code below, // because then the macros will not get the right "redefinition" // flag as they don't see the parent macros which are output before. - loadChildDocuments(); + updateMacros(); // fold macros if possible, still with parent buffer as the // macros will be put in the prefix anyway. @@ -1184,19 +1205,19 @@ void Buffer::writeLaTeXSource(odocstream & os, bool Buffer::isLatex() const { - return params().getTextClass().outputType() == LATEX; + return params().documentClass().outputType() == LATEX; } bool Buffer::isLiterate() const { - return params().getTextClass().outputType() == LITERATE; + return params().documentClass().outputType() == LITERATE; } bool Buffer::isDocBook() const { - return params().getTextClass().outputType() == DOCBOOK; + return params().documentClass().outputType() == DOCBOOK; } @@ -1227,7 +1248,7 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, d->texrow.reset(); - TextClass const & tclass = params().getTextClass(); + DocumentClass const & tclass = params().documentClass(); string const top_element = tclass.latexname(); if (!only_body) { @@ -1282,9 +1303,9 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, << " file was created by LyX " << lyx_version << "\n See http://www.lyx.org/ for more information -->\n"; - params().getTextClass().counters().reset(); + params().documentClass().counters().reset(); - loadChildDocuments(); + updateMacros(); sgml::openTag(os, top); os << '\n'; @@ -1338,7 +1359,7 @@ void Buffer::validate(LaTeXFeatures & features) const { params().validate(features); - loadChildDocuments(); + updateMacros(); for_each(paragraphs().begin(), paragraphs().end(), boost::bind(&Paragraph::validate, _1, boost::ref(features))); @@ -1351,33 +1372,28 @@ void Buffer::validate(LaTeXFeatures & features) const void Buffer::getLabelList(vector & list) const { - /// if this is a child document and the parent is already loaded - /// Use the parent's list instead [ale990407] - Buffer const * tmp = masterBuffer(); - if (!tmp) { - lyxerr << "masterBuffer() failed!" << endl; - BOOST_ASSERT(tmp); - } - if (tmp != this) { - tmp->getLabelList(list); + // If this is a child document, use the parent's list instead. + if (d->parent_buffer) { + d->parent_buffer->getLabelList(list); return; } - loadChildDocuments(); - - for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) - it.nextInset()->getLabelList(*this, list); + list.clear(); + Toc & toc = d->toc_backend.toc("label"); + TocIterator toc_it = toc.begin(); + TocIterator end = toc.end(); + for (; toc_it != end; ++toc_it) { + if (toc_it->depth() == 0) + list.push_back(toc_it->str()); + } } void Buffer::updateBibfilesCache() const { - // if this is a child document and the parent is already loaded - // update the parent's cache instead - Buffer const * tmp = masterBuffer(); - BOOST_ASSERT(tmp); - if (tmp != this) { - tmp->updateBibfilesCache(); + // If this is a child document, use the parent's cache instead. + if (d->parent_buffer) { + d->parent_buffer->updateBibfilesCache(); return; } @@ -1386,14 +1402,14 @@ void Buffer::updateBibfilesCache() const if (it->lyxCode() == BIBTEX_CODE) { InsetBibtex const & inset = static_cast(*it); - EmbeddedFileList const bibfiles = inset.getFiles(*this); + EmbeddedFileList const bibfiles = inset.embeddedFiles(); d->bibfilesCache_.insert(d->bibfilesCache_.end(), bibfiles.begin(), bibfiles.end()); } else if (it->lyxCode() == INCLUDE_CODE) { InsetInclude & inset = static_cast(*it); - inset.updateBibfilesCache(*this); + inset.updateBibfilesCache(); EmbeddedFileList const & bibfiles = inset.getBibfilesCache(*this); d->bibfilesCache_.insert(d->bibfilesCache_.end(), @@ -1406,12 +1422,9 @@ void Buffer::updateBibfilesCache() const EmbeddedFileList const & Buffer::getBibfilesCache() const { - // if this is a child document and the parent is already loaded - // use the parent's cache instead - Buffer const * tmp = masterBuffer(); - BOOST_ASSERT(tmp); - if (tmp != this) - return tmp->getBibfilesCache(); + // If this is a child document, use the parent's cache instead. + if (d->parent_buffer) + return d->parent_buffer->getBibfilesCache(); // We update the cache when first used instead of at loading time. if (d->bibfilesCache_.empty()) @@ -1776,8 +1789,8 @@ MacroData const * Buffer::getMacro(docstring const & name, // If there is a master buffer, query that if (d->parent_buffer) { d->macro_lock = true; - MacroData const * macro - = d->parent_buffer->getMacro(name, *this, false); + MacroData const * macro = d->parent_buffer->getMacro( + name, *this, false); d->macro_lock = false; if (macro) return macro; @@ -1803,11 +1816,11 @@ MacroData const * Buffer::getMacro(docstring const & name, bool global) const } -MacroData const * Buffer::getMacro(docstring const & name, Buffer const & child, bool global) const +MacroData const * Buffer::getMacro(docstring const & name, + Buffer const & child, bool global) const { // look where the child buffer is included first - Impl::BufferPositionMap::iterator it - = d->children_positions.find(&child); + Impl::BufferPositionMap::iterator it = d->children_positions.find(&child); if (it == d->children_positions.end()) return 0; @@ -1816,28 +1829,14 @@ MacroData const * Buffer::getMacro(docstring const & name, Buffer const & child, } -void Buffer::updateEnvironmentMacros(DocIterator & it, - pit_type lastpit, - DocIterator & scope) const +void Buffer::updateMacros(DocIterator & it, DocIterator & scope) const { - Paragraph & par = it.paragraph(); - depth_type depth - = par.params().depth(); - Length const & leftIndent - = par.params().leftIndent(); + pit_type lastpit = it.lastpit(); // look for macros in each paragraph while (it.pit() <= lastpit) { Paragraph & par = it.paragraph(); - // increased depth? - if ((par.params().depth() > depth - || par.params().leftIndent() != leftIndent) - && par.layout()->isEnvironment()) { - updateBlockMacros(it, scope); - continue; - } - // iterate over the insets of the current paragraph InsetList const & insets = par.insetList(); InsetList::const_iterator iit = insets.begin(); @@ -1850,15 +1849,15 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, // Inset needs its own scope? InsetText const * itext = iit->inset->asInsetText(); - bool newScope = itext->isMacroScope(*this); + bool newScope = itext->isMacroScope(); - // scope which ends just behind die inset + // scope which ends just behind the inset DocIterator insetScope = it; - insetScope.pos()++; + ++insetScope.pos(); // collect macros in inset it.push_back(CursorSlice(*iit->inset)); - updateInsetMacros(it, newScope ? insetScope : scope); + updateMacros(it, newScope ? insetScope : scope); it.pop_back(); continue; } @@ -1867,7 +1866,7 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, if (iit->inset->lyxCode() == INCLUDE_CODE) { // get buffer of external file InsetCommand const & inset - = static_cast(*iit->inset); + = static_cast(*iit->inset); InsetCommandParams const & ip = inset.params(); d->macro_lock = true; Buffer * child = loadIfNeeded(*this, ip); @@ -1878,12 +1877,11 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, // register its position, but only when it is // included first in the buffer if (d->children_positions.find(child) - == d->children_positions.end()) + == d->children_positions.end()) d->children_positions[child] = it; // register child with its scope d->position_to_children[it] = Impl::ScopeBuffer(scope, child); - continue; } @@ -1905,8 +1903,8 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, continue; // register macro - d->macros[macroTemplate.name()][it] - = Impl::ScopeMacro(scope, MacroData(*this, it)); + d->macros[macroTemplate.name()][it] = + Impl::ScopeMacro(scope, MacroData(*this, it)); } // next paragraph @@ -1916,48 +1914,6 @@ void Buffer::updateEnvironmentMacros(DocIterator & it, } -void Buffer::updateBlockMacros(DocIterator & it, DocIterator & scope) const -{ - Paragraph & par = it.paragraph(); - - // set scope for macros in this paragraph: - // * either the "old" outer scope - // * or the scope ending after the environment - if (par.layout()->isEnvironment()) { - // find end of environment block, - DocIterator envEnd = it; - pit_type n = it.lastpit() + 1; - depth_type depth = par.params().depth(); - Length const & length = par.params().leftIndent(); - // looping through the paragraph, basically until - // the layout changes or the depth gets smaller. - // (the logic of output_latex.cpp's TeXEnvironment) - do { - envEnd.pit()++; - if (envEnd.pit() == n) - break; - } while (par.layout() == envEnd.paragraph().layout() - || depth < envEnd.paragraph().params().depth() - || length != envEnd.paragraph().params().leftIndent()); - - // collect macros from environment block - updateEnvironmentMacros(it, envEnd.pit() - 1, envEnd); - } else { - // collect macros from paragraph - updateEnvironmentMacros(it, it.pit(), scope); - } -} - - -void Buffer::updateInsetMacros(DocIterator & it, DocIterator & scope) const -{ - // look for macros in each paragraph - pit_type n = it.lastpit() + 1; - while (it.pit() < n) - updateBlockMacros(it, scope); -} - - void Buffer::updateMacros() const { if (d->macro_lock) @@ -1977,7 +1933,7 @@ void Buffer::updateMacros() const DocIterator it = par_iterator_begin(); DocIterator outerScope = it; outerScope.pit() = outerScope.lastpit() + 2; - updateInsetMacros(it, outerScope); + updateMacros(it, outerScope); } @@ -2016,18 +1972,14 @@ void Buffer::listMacroNames(MacroNameSet & macros) const d->macro_lock = true; // loop over macro names - Impl::NamePositionScopeMacroMap::iterator nameIt - = d->macros.begin(); - Impl::NamePositionScopeMacroMap::iterator nameEnd - = d->macros.end(); + Impl::NamePositionScopeMacroMap::iterator nameIt = d->macros.begin(); + Impl::NamePositionScopeMacroMap::iterator nameEnd = d->macros.end(); for (; nameIt != nameEnd; ++nameIt) macros.insert(nameIt->first); // loop over children - Impl::BufferPositionMap::iterator it - = d->children_positions.begin(); - Impl::BufferPositionMap::iterator end - = d->children_positions.end(); + Impl::BufferPositionMap::iterator it = d->children_positions.begin(); + Impl::BufferPositionMap::iterator end = d->children_positions.end(); for (; it != end; ++it) it->first->listMacroNames(macros); @@ -2061,29 +2013,65 @@ void Buffer::writeParentMacros(odocstream & os) const } +Buffer::References & Buffer::references(docstring const & label) +{ + if (d->parent_buffer) + return const_cast(masterBuffer())->references(label); + + RefCache::iterator it = d->ref_cache_.find(label); + if (it != d->ref_cache_.end()) + return it->second.second; + + static InsetLabel const * dummy_il = 0; + static References const dummy_refs; + it = d->ref_cache_.insert( + make_pair(label, make_pair(dummy_il, dummy_refs))).first; + return it->second.second; +} + + +Buffer::References const & Buffer::references(docstring const & label) const +{ + return const_cast(this)->references(label); +} + + +void Buffer::setInsetLabel(docstring const & label, InsetLabel const * il) +{ + masterBuffer()->d->ref_cache_[label].first = il; +} + + +InsetLabel const * Buffer::insetLabel(docstring const & label) const +{ + return masterBuffer()->d->ref_cache_[label].first; +} + + +void Buffer::clearReferenceCache() const +{ + if (!d->parent_buffer) + d->ref_cache_.clear(); +} + + void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to, InsetCode code) { //FIXME: This does not work for child documents yet. - BOOST_ASSERT(code == CITE_CODE || code == REF_CODE); + BOOST_ASSERT(code == CITE_CODE); // Check if the label 'from' appears more than once vector labels; - string paramName; - if (code == CITE_CODE) { - BiblioInfo keys; - keys.fillWithBibKeys(this); - BiblioInfo::const_iterator bit = keys.begin(); - BiblioInfo::const_iterator bend = keys.end(); + BiblioInfo keys; + keys.fillWithBibKeys(this); + BiblioInfo::const_iterator bit = keys.begin(); + BiblioInfo::const_iterator bend = keys.end(); - for (; bit != bend; ++bit) - // FIXME UNICODE - labels.push_back(bit->first); - paramName = "key"; - } else { - getLabelList(labels); - paramName = "reference"; - } + for (; bit != bend; ++bit) + // FIXME UNICODE + labels.push_back(bit->first); + paramName = "key"; if (count(labels.begin(), labels.end(), from) > 1) return; @@ -2116,31 +2104,30 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, d->texrow.newline(); if (isLatex()) writeLaTeXSource(os, filePath(), runparams, true, true); - else { + else writeDocBookSource(os, absFileName(), runparams, false); - } } else { runparams.par_begin = par_begin; runparams.par_end = par_end; - if (par_begin + 1 == par_end) + if (par_begin + 1 == par_end) { os << "% " << bformat(_("Preview source code for paragraph %1$d"), par_begin) << "\n\n"; - else + } else { os << "% " << bformat(_("Preview source code from paragraph %1$s to %2$s"), convert(par_begin), convert(par_end - 1)) << "\n\n"; + } d->texrow.newline(); d->texrow.newline(); // output paragraphs - if (isLatex()) { + if (isLatex()) latexParagraphs(*this, text(), os, d->texrow, runparams); - } else { + else // DocBook docbookParagraphs(paragraphs(), *this, os, runparams); - } } } @@ -2310,49 +2297,6 @@ void Buffer::autoSave() const } -void Buffer::resetChildDocuments(bool close_them) const -{ - for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { - if (it->lyxCode() != INCLUDE_CODE) - continue; - InsetCommand const & inset = static_cast(*it); - InsetCommandParams const & ip = inset.params(); - - resetParentBuffer(this, ip, close_them); - } - - if (use_gui && masterBuffer() == this) - updateLabels(*this); - - // clear references to children in macro tables - d->children_positions.clear(); - d->position_to_children.clear(); -} - - -void Buffer::loadChildDocuments() const -{ - bool parse_error = false; - - for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { - if (it->lyxCode() != INCLUDE_CODE) - continue; - InsetCommand const & inset = static_cast(*it); - InsetCommandParams const & ip = inset.params(); - Buffer * child = loadIfNeeded(*this, ip); - if (!child) - continue; - parse_error |= !child->errorList("Parse").empty(); - child->loadChildDocuments(); - } - - if (use_gui && masterBuffer() == this) - updateLabels(*this); - - updateMacros(); -} - - string Buffer::bufferFormat() const { if (isDocBook()) @@ -2530,7 +2474,7 @@ vector Buffer::exportableFormats(bool only_viewable) const vector Buffer::backends() const { vector v; - if (params().getTextClass().isTeXClassAvailable()) { + if (params().baseClass()->isTeXClassAvailable()) { v.push_back(bufferFormat()); // FIXME: Don't hardcode format names here, but use a flag if (v.back() == "latex")