After some time of investigation and thanks to two delayed flights I came up with the following solution that fixes the natbib slowness problem for me and makes LyX 1.4 usable again.
What it does is: - store the timestamp of any bibfile in the buffer - in insetcite, store the timestamp of the files at the time when the bibliographies were scanned for the last time - now only scan the files again if the timestamp of a file has changed or if a file is new. Opinions? Jürgen
Index: src/insets/insetbibtex.C =================================================================== --- src/insets/insetbibtex.C (Revision 13663) +++ src/insets/insetbibtex.C (Arbeitskopie) @@ -89,6 +89,7 @@ void InsetBibtex::doDispatch(LCursor & c setParams(p); else cur.noUpdate(); + cur.buffer().updateBibfilesCache(); break; } @@ -283,6 +284,17 @@ vector<string> const InsetBibtex::getFil } +void InsetBibtex::getFiles(Buffer const & buffer, + std::vector<std::string> & bibfiles) const +{ + vector<string> const files = getFiles(buffer); + for (vector<string>::const_iterator it = files.begin(); + it != files.end(); ++ it) { + bibfiles.push_back(it->c_str()); + } +} + + // This method returns a comma separated list of Bibtex entries void InsetBibtex::fillWithBibKeys(Buffer const & buffer, std::vector<std::pair<string, string> > & keys) const Index: src/insets/insetbibtex.h =================================================================== --- src/insets/insetbibtex.h (Revision 13663) +++ src/insets/insetbibtex.h (Arbeitskopie) @@ -39,6 +39,9 @@ public: /// std::vector<std::string> const getFiles(Buffer const &) const; /// + void getFiles(Buffer const & buffer, + std::vector<std::string> & bibfiles) const; + /// bool addDatabase(std::string const &); /// bool delDatabase(std::string const &); Index: src/insets/insetcite.C =================================================================== --- src/insets/insetcite.C (Revision 13663) +++ src/insets/insetcite.C (Arbeitskopie) @@ -24,6 +24,8 @@ #include "support/lstrings.h" +#include <boost/filesystem/operations.hpp> + using lyx::support::ascii_lowercase; using lyx::support::contains; using lyx::support::getVectorFromString; @@ -37,6 +39,7 @@ using std::vector; using std::map; namespace biblio = lyx::biblio; +namespace fs = boost::filesystem; namespace { @@ -50,26 +53,51 @@ string const getNatbibLabel(Buffer const if (!buffer.fully_loaded()) return string(); + // Cache the labels typedef std::map<Buffer const *, biblio::InfoMap> CachedMap; static CachedMap cached_keys; - // build the keylist - typedef vector<std::pair<string, string> > InfoType; - InfoType bibkeys; - buffer.fillWithBibKeys(bibkeys); - - InfoType::const_iterator bit = bibkeys.begin(); - InfoType::const_iterator bend = bibkeys.end(); + // and cache the timestamp of the bibliography files. + static std::map<string, time_t> bibfileStatus; biblio::InfoMap infomap; - for (; bit != bend; ++bit) { - infomap[bit->first] = bit->second; + + if (buffer.getBibfilesCache().empty()) + buffer.updateBibfilesCache(); + vector<string> bibfilesCache = buffer.getBibfilesCache(); + // compare the cached timestamps with the actual ones. + bool changed = false; + for (vector<string>::const_iterator it = bibfilesCache.begin(); + it != bibfilesCache.end(); ++ it) { + string const f = it->c_str(); + if (bibfileStatus[f] != fs::last_write_time(f)) { + changed = true; + bibfileStatus[f] = fs::last_write_time(f); + } } + + // build the keylist only if the bibfiles have been changed + if (cached_keys.empty() || bibfileStatus.empty() || changed) { + typedef vector<std::pair<string, string> > InfoType; + InfoType bibkeys; + buffer.fillWithBibKeys(bibkeys); + + InfoType::const_iterator bit = bibkeys.begin(); + InfoType::const_iterator bend = bibkeys.end(); + + + for (; bit != bend; ++bit) { + infomap[bit->first] = bit->second; + } + + cached_keys[&buffer] = infomap; + } else + // use the cached keys + infomap = cached_keys[&buffer]; + if (infomap.empty()) return string(); - cached_keys[&buffer] = infomap; - // the natbib citation-styles // CITET: author (year) // CITEP: (author,year) Index: src/BufferView_pimpl.C =================================================================== --- src/BufferView_pimpl.C (Revision 13663) +++ src/BufferView_pimpl.C (Arbeitskopie) @@ -1290,8 +1290,10 @@ bool BufferView::Pimpl::dispatch(FuncReq bv_funcs::findInset(tmpcur, InsetBase::BIBTEX_CODE, false); InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur, InsetBase::BIBTEX_CODE); - if (inset) - inset->addDatabase(cmd.argument); + if (inset) { + if (inset->addDatabase(cmd.argument)) + buffer_->updateBibfilesCache(); + } break; } @@ -1300,8 +1302,10 @@ bool BufferView::Pimpl::dispatch(FuncReq bv_funcs::findInset(tmpcur, InsetBase::BIBTEX_CODE, false); InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur, InsetBase::BIBTEX_CODE); - if (inset) - inset->delDatabase(cmd.argument); + if (inset) { + if (inset->delDatabase(cmd.argument)) + buffer_->updateBibfilesCache(); + } break; } Index: src/buffer.C =================================================================== --- src/buffer.C (Revision 13663) +++ src/buffer.C (Arbeitskopie) @@ -150,6 +150,8 @@ int const LYX_FORMAT = 245; typedef std::map<string, bool> DepClean; +vector<string> Buffer::bibfilesCache_; + class Buffer::Impl { @@ -1253,6 +1255,39 @@ void Buffer::fillWithBibKeys(vector<pair } +void Buffer::updateBibfilesCache() const +{ + /// if this is a child document and the parent is already loaded + /// use the parent's list instead + Buffer const * tmp = getMasterBuffer(); + BOOST_ASSERT(tmp); + if (tmp != this) { + tmp->updateBibfilesCache(); + return; + } + + bibfilesCache_.clear(); + for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { + if (it->lyxCode() == InsetBase::BIBTEX_CODE) { + InsetBibtex const & inset = + dynamic_cast<InsetBibtex const &>(*it); + vector<string> bibfiles; + inset.getFiles(*this, bibfiles); + for (vector<string>::const_iterator it = bibfiles.begin(); + it != bibfiles.end(); ++ it) { + bibfilesCache_.push_back(it->c_str()); + } + } + } +} + + +vector<string> const Buffer::getBibfilesCache() const +{ + return bibfilesCache_; +} + + bool Buffer::isDepClean(string const & name) const { DepClean::const_iterator const it = pimpl_->dep_clean.find(name); Index: src/buffer.h =================================================================== --- src/buffer.h (Revision 13663) +++ src/buffer.h (Arbeitskopie) @@ -24,6 +24,7 @@ #include <boost/signal.hpp> #include <iosfwd> +#include <string> #include <map> #include <utility> #include <vector> @@ -249,6 +250,10 @@ public: /// return all bibkeys from buffer and its childs void fillWithBibKeys(std::vector<std::pair<std::string, std::string> > & keys) const; + /// update the cache with all bibfiles in use + void updateBibfilesCache() const; + /// return the cache with all bibfiles in use + std::vector<std::string> const Buffer::getBibfilesCache() const; /// void getLabelList(std::vector<std::string> &) const; @@ -352,6 +357,9 @@ private: /// it's BufferView, this should be FIXED in future. StableDocIterator cursor_; StableDocIterator anchor_; + /// a cache for the bibfiles, needed for appropriate + /// update of natbib labels. + static std::vector<std::string> bibfilesCache_; }; #endif