]> git.lyx.org Git - features.git/blobdiff - src/Buffer.cpp
Clear bibfile cache when set of bibliography files change
[features.git] / src / Buffer.cpp
index ee27f8f69d8af43213d6a888e7f8348227cc333b..2809fdf8b7b45c400d5daf6c3335e03227dd1a6f 100644 (file)
@@ -279,7 +279,7 @@ public:
 
        /// A cache for the bibfiles (including bibfiles of loaded child
        /// documents), needed for appropriate update of natbib labels.
-       mutable 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
@@ -562,13 +562,13 @@ Buffer::~Buffer()
 }
 
 
-Buffer * Buffer::cloneFromMaster() const
+Buffer * Buffer::cloneWithChildren() const
 {
        BufferMap bufmap;
        cloned_buffers.push_back(new CloneList);
        CloneList * clones = cloned_buffers.back();
 
-       masterBuffer()->cloneWithChildren(bufmap, clones);
+       cloneWithChildren(bufmap, clones);
 
        // make sure we got cloned
        BufferMap::const_iterator bit = bufmap.find(this);
@@ -888,6 +888,7 @@ int Buffer::readHeader(Lexer & lex)
        params().options.erase();
        params().master.erase();
        params().float_placement.erase();
+       params().float_alignment.erase();
        params().paperwidth.erase();
        params().paperheight.erase();
        params().leftmargin.erase();
@@ -1040,6 +1041,10 @@ bool Buffer::readDocument(Lexer & lex)
                                                << absFileName()
                                                << ") does not include "
                                                "this document. Ignoring the master assignment.");
+                               // If the master has just been created, un-hide it (#11162)
+                               if (!master->fileName().exists())
+                                       lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH,
+                                                                 master->absFileName()));
                        }
                }
        }
@@ -1329,14 +1334,37 @@ Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn,
 
 
 FileName Buffer::getBackupName() const {
+       map<int, string> const file_formats = {
+         {544, "23"},
+         {508, "22"},
+         {474, "21"},
+         {413, "20"},
+         {345, "16"},
+         {276, "15"},
+         {245, "14"},
+         {221, "13"},
+         {220, "12"},
+         {218, "1163"},
+         {217, "116"},
+         {216, "115"},
+         {215, "11"},
+         {210, "010"},
+         {200, "006"}
+       };
        FileName const & fn = fileName();
        string const fname = fn.onlyFileNameWithoutExt();
        string const fext  = fn.extension() + "~";
        string const fpath = lyxrc.backupdir_path.empty() ?
                fn.onlyPath().absFileName() :
                lyxrc.backupdir_path;
-       string const fform = convert<string>(d->file_format);
-       string const backname = fname + "-lyxformat-" + fform;
+       string backup_suffix;
+       // If file format is from a stable series use version instead of file format
+       auto const it = file_formats.find(d->file_format);
+       if (it != file_formats.end())
+               backup_suffix = "-lyx" + it->second;
+       else
+               backup_suffix = "-lyxformat-" + convert<string>(d->file_format);
+       string const backname = fname + backup_suffix;
        FileName backup(addName(fpath, addExtension(backname, fext)));
 
        // limit recursion, just in case
@@ -1874,8 +1902,7 @@ Buffer::ExportStatus Buffer::writeLaTeXSource(otexstream & os,
                                            "file path name."),
                                          inputpath, uncodable_glyphs));
                        } else {
-                               string docdir =
-                                       latex_path(original_path);
+                               string docdir = os::latex_path(original_path);
                                if (contains(docdir, '#')) {
                                        docdir = subst(docdir, "#", "\\#");
                                        os << "\\catcode`\\#=11"
@@ -1886,9 +1913,20 @@ Buffer::ExportStatus Buffer::writeLaTeXSource(otexstream & os,
                                        os << "\\catcode`\\%=11"
                                              "\\def\\%{%}\\catcode`\\%=14\n";
                                }
+                               bool const detokenize = !isAscii(from_utf8(docdir));
+                               bool const quote = contains(docdir, ' ');
                                os << "\\makeatletter\n"
-                                  << "\\def\\input@path{{"
-                                  << docdir << "}}\n"
+                                  << "\\def\\input@path{{";
+                               if (detokenize)
+                                       os << "\\detokenize{";
+                               if (quote)
+                                       os << "\"";
+                               os << docdir;
+                               if (quote)
+                                       os << "\"";
+                               if (detokenize)
+                                       os << "}";
+                               os << "}}\n"
                                   << "\\makeatother\n";
                        }
                }
@@ -2356,7 +2394,7 @@ void Buffer::invalidateBibinfoCache() const
 }
 
 
-FileNamePairList const & Buffer::getBibfiles(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 instead.
@@ -2382,7 +2420,8 @@ BiblioInfo const & Buffer::bibInfo() const
 }
 
 
-void Buffer::registerBibfiles(FileNamePairList const & bf) const {
+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.
@@ -2391,7 +2430,7 @@ void Buffer::registerBibfiles(FileNamePairList const & bf) const {
                tmp->registerBibfiles(bf);
 
        for (auto const & p : bf) {
-               FileNamePairList::const_iterator temp =
+               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);
@@ -2399,6 +2438,31 @@ void Buffer::registerBibfiles(FileNamePairList const & bf) const {
 }
 
 
+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
@@ -2414,11 +2478,9 @@ void Buffer::checkIfBibInfoCacheIsValid() const
                return;
 
        // compare the cached timestamps with the actual ones.
-       FileNamePairList const & bibfiles_cache = getBibfiles();
-       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) {
@@ -2430,19 +2492,32 @@ void Buffer::checkIfBibInfoCacheIsValid() const
 }
 
 
-void Buffer::reloadBibInfoCache() const
+void Buffer::clearBibFileCache() const
+{
+       bibfileCache.clear();
+}
+
+
+void Buffer::reloadBibInfoCache(bool const force) const
 {
        // use the master's cache
        Buffer const * const tmp = masterBuffer();
        if (tmp != this) {
-               tmp->reloadBibInfoCache();
+               tmp->reloadBibInfoCache(force);
                return;
        }
 
-       checkIfBibInfoCacheIsValid();
-       if (d->bibinfo_cache_valid_)
-               return;
+       if (!force) {
+               checkIfBibInfoCacheIsValid();
+               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.
+       clearBibFileCache();
        d->bibinfo_.clear();
        FileNameList checkedFiles;
        collectBibKeys(checkedFiles);
@@ -2481,7 +2556,7 @@ void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bin) const
        bi[key] = bin;
 
        if (parent() != 0) {
-               BiblioInfo & masterbi = parent()->d->bibinfo_;
+               BiblioInfo & masterbi = masterBuffer()->d->bibinfo_;
                masterbi[key] = bin;
        }
 }
@@ -3158,7 +3233,7 @@ string const Buffer::prepareFileNameForLaTeX(string const & name,
 
 
 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
@@ -3180,7 +3255,7 @@ vector<docstring> const Buffer::prepareBibFilePaths(OutputParams const & runpara
        bool found_space = false;
 
        for (auto const & bit : bibfilelist) {
-               string utf8input = to_utf8(bit.first);
+               string utf8input = to_utf8(bit);
                string database =
                        prepareFileNameForLaTeX(utf8input, ".bib", runparams.nice);
                FileName try_in_file =
@@ -3189,7 +3264,7 @@ vector<docstring> const Buffer::prepareBibFilePaths(OutputParams const & runpara
                // 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 = bit.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));
@@ -3869,6 +3944,9 @@ unique_ptr<TexRow> Buffer::getSourceCode(odocstream & os, string const & format,
        // No side effect of file copying and image conversion
        runparams.dryrun = true;
 
+       // Some macros rely on font encoding
+       runparams.main_fontenc = params().main_font_encoding();
+
        if (output == CurrentParagraph) {
                runparams.par_begin = par_begin;
                runparams.par_end = par_end;
@@ -4365,7 +4443,8 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
                Alert::error(_("File name error"),
                        bformat(_("The directory path to the document\n%1$s\n"
                            "contains spaces, but your TeX installation does "
-                           "not allow them."), from_ascii(filePath())));
+                           "not allow them. You should save the file to a directory "
+                                       "whose name does not contain spaces."), from_ascii(filePath())));
                return ExportTexPathHasSpaces;
        } else {
                runparams.nice = false;
@@ -4727,7 +4806,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
        Buffer const * const master = masterBuffer();
        DocumentClass const & textclass = master->params().documentClass();
 
-       FileNamePairList old_bibfiles;
+       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) {
@@ -4791,9 +4870,13 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
                return;
 
        // if the bibfiles changed, the cache of bibinfo is invalid
-       sort(d->bibfiles_cache_.begin(), d->bibfiles_cache_.end());
-       // the old one should already be sorted
-       if (old_bibfiles != d->bibfiles_cache_) {
+       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
@@ -4810,8 +4893,11 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
                // 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;
        }