/// A cache for the bibfiles (including bibfiles of loaded child
/// documents), needed for appropriate update of natbib labels.
- mutable support::FileNamePairList bibfiles_cache_;
+ mutable docstring_list bibfiles_cache_;
// FIXME The caching mechanism could be improved. At present, we have a
// cache for each Buffer, that caches all the bibliography info for that
LYXERR0("Warning: a buffer should not have two parents!");
parent_buffer = pb;
if (!cloned_buffer_ && parent_buffer) {
- parent_buffer->invalidateBibfileCache();
parent_buffer->invalidateBibinfoCache();
}
}
// Biblatex bibliographies are loaded here
if (params().useBiblatex()) {
vector<docstring> const bibfiles =
- prepareBibFilePaths(runparams, getBibfilesCache(), true);
+ prepareBibFilePaths(runparams, getBibfiles(), true);
for (docstring const & file: bibfiles)
os << "\\addbibresource{" << file << "}\n";
}
for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
if (it->lyxCode() == BIBTEX_CODE) {
InsetBibtex const & inset = static_cast<InsetBibtex const &>(*it);
- support::FileNamePairList const bibfiles = inset.getBibFiles();
+ docstring_list const bibfiles = inset.getBibFiles();
d->bibfiles_cache_.insert(d->bibfiles_cache_.end(),
bibfiles.begin(),
bibfiles.end());
Buffer const * const incbuf = inset.getChildBuffer();
if (!incbuf)
continue;
- support::FileNamePairList const & bibfiles =
- incbuf->getBibfilesCache(UpdateChildOnly);
+ docstring_list const & bibfiles =
+ incbuf->getBibfiles(UpdateChildOnly);
if (!bibfiles.empty()) {
d->bibfiles_cache_.insert(d->bibfiles_cache_.end(),
bibfiles.begin(),
}
-void Buffer::invalidateBibfileCache() const
-{
- d->bibfile_cache_valid_ = false;
- d->bibinfo_cache_valid_ = false;
- d->cite_labels_valid_ = false;
- // also invalidate the cache for the parent buffer
- Buffer const * const pbuf = d->parent();
- if (pbuf)
- pbuf->invalidateBibfileCache();
-}
-
-
-support::FileNamePairList const & Buffer::getBibfilesCache(UpdateScope scope) const
+docstring_list const & Buffer::getBibfiles(UpdateScope scope) const
{
// FIXME This is probably unnecessary, given where we call this.
// If this is a child document, use the master's cache instead.
Buffer const * const pbuf = masterBuffer();
if (pbuf != this && scope != UpdateChildOnly)
- return pbuf->getBibfilesCache();
+ return pbuf->getBibfiles();
if (!d->bibfile_cache_valid_)
this->updateBibfilesCache(scope);
}
+void Buffer::registerBibfiles(const docstring_list & bf) const
+{
+ // We register the bib files in the master buffer,
+ // if there is one, but also in every single buffer,
+ // in case a child is compiled alone.
+ Buffer const * const tmp = masterBuffer();
+ if (tmp != this)
+ tmp->registerBibfiles(bf);
+
+ for (auto const & p : bf) {
+ docstring_list::const_iterator temp =
+ find(d->bibfiles_cache_.begin(), d->bibfiles_cache_.end(), p);
+ if (temp == d->bibfiles_cache_.end())
+ d->bibfiles_cache_.push_back(p);
+ }
+}
+
+
+static map<docstring, FileName> bibfileCache;
+
+FileName Buffer::getBibfilePath(docstring const & bibid) const
+{
+ map<docstring, FileName>::const_iterator it =
+ bibfileCache.find(bibid);
+ if (it != bibfileCache.end()) {
+ // i.e., bibfileCache[bibid]
+ return it->second;
+ }
+
+ LYXERR(Debug::FILES, "Reading file location for " << bibid);
+ string texfile = changeExtension(to_utf8(bibid), "bib");
+ // note that, if the filename can be found directly from the path,
+ // findtexfile will just return a FileName object for that path.
+ FileName file(findtexfile(texfile, "bib"));
+ if (file.empty())
+ file = FileName(makeAbsPath(texfile, filePath()));
+ LYXERR(Debug::FILES, "Found at: " << file);
+
+ bibfileCache[bibid] = file;
+ return bibfileCache[bibid];
+}
+
+
void Buffer::checkIfBibInfoCacheIsValid() const
{
// use the master's cache
}
// compare the cached timestamps with the actual ones.
- FileNamePairList const & bibfiles_cache = getBibfilesCache();
- FileNamePairList::const_iterator ei = bibfiles_cache.begin();
- FileNamePairList::const_iterator en = bibfiles_cache.end();
- for (; ei != en; ++ ei) {
- FileName const fn = ei->second;
+ docstring_list const & bibfiles_cache = getBibfiles();
+ for (auto const & bf : bibfiles_cache) {
+ FileName const fn = getBibfilePath(bf);
time_t lastw = fn.lastModified();
time_t prevw = d->bibfile_status_[fn];
if (lastw != prevw) {
if (d->bibinfo_cache_valid_)
return;
+ // re-read file locations when this info changes
+ // FIXME Is this sufficient? Or should we also force that
+ // in some other cases? If so, then it is easy enough to
+ // add the following line in some other places.
+ bibfileCache.clear();
d->bibinfo_.clear();
FileNameList checkedFiles;
collectBibKeys(checkedFiles);
vector<docstring> const Buffer::prepareBibFilePaths(OutputParams const & runparams,
- FileNamePairList const bibfilelist,
+ docstring_list const & bibfilelist,
bool const add_extension) const
{
// If we are processing the LaTeX file in a temp directory then
// check for spaces in paths
bool found_space = false;
- FileNamePairList::const_iterator it = bibfilelist.begin();
- FileNamePairList::const_iterator en = bibfilelist.end();
- for (; it != en; ++it) {
- string utf8input = to_utf8(it->first);
+ for (auto const & bit : bibfilelist) {
+ string utf8input = to_utf8(bit);
string database =
prepareFileNameForLaTeX(utf8input, ".bib", runparams.nice);
FileName try_in_file =
// If the file has not been found, try with the real file name
// (it might come from a child in a sub-directory)
if (!not_from_texmf) {
- try_in_file = it->second;
+ try_in_file = getBibfilePath(bit);
if (try_in_file.isReadableFile()) {
// Check if the file is in texmf
FileName kpsefile(findtexfile(changeExtension(utf8input, "bib"), "bib", true));
Buffer const * const master = masterBuffer();
DocumentClass const & textclass = master->params().documentClass();
- // do this only if we are the top-level Buffer
- if (master == this) {
+ docstring_list old_bibfiles;
+ // Do this only if we are the top-level Buffer. We also need to account
+ // for the case of a previewed child with ignored parent here.
+ if (master == this && !d->ignore_parent) {
textclass.counters().reset(from_ascii("bibitem"));
reloadBibInfoCache();
}
// in InsetInclude::addToToc.
return;
- d->bibinfo_cache_valid_ = true;
+ // if the bibfiles changed, the cache of bibinfo is invalid
+ docstring_list new_bibfiles = d->bibfiles_cache_;
+ // this is a trick to determine whether the two vectors have
+ // the same elements.
+ sort(new_bibfiles.begin(), new_bibfiles.end());
+ sort(old_bibfiles.begin(), old_bibfiles.end());
+ if (old_bibfiles != new_bibfiles) {
+ LYXERR(Debug::FILES, "Reloading bibinfo cache.");
+ invalidateBibinfoCache();
+ reloadBibInfoCache();
+ // We relied upon the bibinfo cache when recalculating labels. But that
+ // cache was invalid, although we didn't find that out until now. So we
+ // have to do it all again.
+ // That said, the only thing we really need to do is update the citation
+ // labels. Nothing else will have changed. So we could create a new
+ // UpdateType that would signal that fact, if we needed to do so.
+ parit = cbuf.par_iterator_begin();
+ // we will be re-doing the counters and references and such.
+ textclass.counters().reset();
+ clearReferenceCache();
+ // we should not need to do this again?
+ // updateMacros();
+ setChangesPresent(false);
+ updateBuffer(parit, utype);
+ // this will already have been done by reloadBibInfoCache();
+ // d->bibinfo_cache_valid_ = true;
+ }
+ else {
+ LYXERR(Debug::FILES, "Bibfiles unchanged.");
+ // this is also set to true on the other path, by reloadBibInfoCache.
+ d->bibinfo_cache_valid_ = true;
+ }
d->cite_labels_valid_ = true;
/// FIXME: Perf
cbuf.tocBackend().update(true, utype);
#include "support/convert.h"
#include "support/debug.h"
#include "support/docstream.h"
+#include "support/docstring_list.h"
#include "support/ExceptionMessage.h"
#include "support/FileNameList.h"
#include "support/filetools.h"
InsetBibtex::InsetBibtex(Buffer * buf, InsetCommandParams const & p)
: InsetCommand(buf, p)
{
- buffer().invalidateBibfileCache();
buffer().removeBiblioTempFiles();
}
/* 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();
buffer_->removeBiblioTempFiles();
}
}
cur.recordUndo();
setParams(p);
- buffer().invalidateBibfileCache();
buffer().removeBiblioTempFiles();
cur.forceBufferUpdate();
break;
vector<docstring>::const_iterator it = bibfilelist.begin();
vector<docstring>::const_iterator en = bibfilelist.end();
for (; it != en; ++it) {
- FileName const bibfile = getBibTeXPath(*it, buffer());
+ FileName const bibfile = buffer().getBibfilePath(*it);
theFormats().edit(buffer(), bibfile,
theFormats().getFormatFromFile(bibfile));
}
}
-support::FileNamePairList InsetBibtex::getBibFiles() const
+docstring_list InsetBibtex::getBibFiles() const
{
- FileName path(buffer().filePath());
- support::PathChanger p(path);
-
- // We need to store both the real FileName and the way it is entered
- // (with full path, rel path or as a single file name).
- // The latter is needed for biblatex's central bibfile macro.
- support::FileNamePairList vec;
-
- vector<docstring> bibfilelist = getVectorFromString(getParam("bibfiles"));
- vector<docstring>::const_iterator it = bibfilelist.begin();
- vector<docstring>::const_iterator en = bibfilelist.end();
- for (; it != en; ++it) {
- FileName const file = getBibTeXPath(*it, buffer());
-
- if (!file.empty())
- vec.push_back(make_pair(*it, file));
- else
- LYXERR0("Couldn't find " + to_utf8(*it) + " in InsetBibtex::getBibFiles()!");
- }
-
- return vec;
-
+ return getVectorFromString(getParam("bibfiles"));
}
namespace {
BiblioInfo keylist;
- support::FileNamePairList const files = getBibFiles();
- support::FileNamePairList::const_iterator it = files.begin();
- support::FileNamePairList::const_iterator en = files.end();
- for (; it != en; ++ it) {
- FileName const bibfile = it->second;
+ docstring_list const files = getBibFiles();
+ for (auto const & bf : files) {
+ FileName const bibfile = buffer().getBibfilePath(bf);
+ if (bibfile.empty()) {
+ LYXERR0("Unable to find path for " << bf << "!");
+ continue;
+ }
if (find(checkedFiles.begin(), checkedFiles.end(), bibfile) != checkedFiles.end())
// already checked this one. Skip.
continue;
VarMap strings;
while (ifs) {
-
ifs.get(ch);
if (!ifs)
break;
}
-FileName InsetBibtex::getBibTeXPath(docstring const & filename, Buffer const & buf)
-{
- string texfile = changeExtension(to_utf8(filename), "bib");
- // note that, if the filename can be found directly from the path,
- // findtexfile will just return a FileName object for that path.
- FileName file(findtexfile(texfile, "bib"));
- if (file.empty())
- file = FileName(makeAbsPath(texfile, buf.filePath()));
- return file;
-}
-
-
bool InsetBibtex::addDatabase(docstring const & db)
{
docstring bibfiles = getParam("bibfiles");