X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=cb08e3c4fb9fdc2acb75a0e73a18862227ce730f;hb=40240ef6a0f5c2908c4c1f65399491582a0b5e26;hp=043f0cc9a7a37c51882a15111c94c86e2afb8170;hpb=821e10154739aa23191998b88a4bb7d9e0390628;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 043f0cc9a7..cb08e3c4fb 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -135,7 +135,22 @@ namespace { int const LYX_FORMAT = LYX_FORMAT_LYX; typedef map DepClean; -typedef map > RefCache; + +// Information about labels and their associated refs +struct LabelInfo { + /// label string + docstring label; + /// label inset + InsetLabel const * inset; + /// associated references cache + Buffer::References references; + /// whether this label is active (i.e., not deleted) + bool active; +}; + +typedef vector LabelCache; + +typedef map RefCache; } // namespace @@ -279,7 +294,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 @@ -295,6 +310,8 @@ public: /// we ran updateBuffer(), i.e., whether citation labels may need /// to be updated. mutable bool cite_labels_valid_; + /// Do we have a bibliography environment? + mutable bool have_bibitems_; /// These two hold the file name and format, written to by /// Buffer::preview and read from by LFUN_BUFFER_VIEW_CACHE. @@ -305,7 +322,11 @@ public: /// was missing). bool preview_error_; + /// Cache the references associated to a label and their positions + /// in the buffer. mutable RefCache ref_cache_; + /// Cache the label insets and their activity status. + mutable LabelCache label_cache_; /// our Text that should be wrapped in an InsetText InsetText * inset; @@ -428,7 +449,7 @@ 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), checksum_(0), wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false), - cite_labels_valid_(false), preview_error_(false), + cite_labels_valid_(false), have_bibitems_(false), preview_error_(false), inset(0), preview_loader_(0), cloned_buffer_(cloned_buffer), clone_list_(0), doing_export(false), tracked_changes_present_(0), externally_modified_(false), parent_buffer(0), @@ -450,6 +471,7 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_, bibinfo_cache_valid_ = cloned_buffer_->d->bibinfo_cache_valid_; bibfile_status_ = cloned_buffer_->d->bibfile_status_; cite_labels_valid_ = cloned_buffer_->d->cite_labels_valid_; + have_bibitems_ = cloned_buffer_->d->have_bibitems_; unnamed = cloned_buffer_->d->unnamed; internal_buffer = cloned_buffer_->d->internal_buffer; layout_position = cloned_buffer_->d->layout_position; @@ -562,13 +584,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); @@ -790,10 +812,9 @@ FileName Buffer::Impl::exportFileName() const if (branch_suffix.empty()) return filename; - string const name = filename.onlyFileNameWithoutExt() - + to_utf8(branch_suffix); + string const name = addExtension(filename.onlyFileNameWithoutExt() + + to_utf8(branch_suffix), filename.extension()); FileName res(filename.onlyPath().absFileName() + "/" + name); - res.changeExtension(filename.extension()); return res; } @@ -888,6 +909,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 +1062,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 +1355,37 @@ Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn, FileName Buffer::getBackupName() const { + map 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(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(d->file_format); + string const backname = fname + backup_suffix; FileName backup(addName(fpath, addExtension(backname, fext))); // limit recursion, just in case @@ -1415,6 +1464,9 @@ bool Buffer::save() const FileName savefile(tempfile->name()); LYXERR(Debug::FILES, "Saving to " << savefile.absFileName()); + if (!savefile.clonePermissions(fileName())) + LYXERR0("Failed to clone the permission from " << fileName().absFileName() << " to " << savefile.absFileName()); + if (!writeFile(savefile)) return false; @@ -1667,13 +1719,6 @@ Buffer::ExportStatus Buffer::makeLaTeXFile(FileName const & fname, { OutputParams runparams = runparams_in; - // 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(); LYXERR(Debug::LATEX, "makeLaTeXFile encoding: " << encoding << ", fname=" << fname.realPath()); @@ -1681,9 +1726,11 @@ Buffer::ExportStatus Buffer::makeLaTeXFile(FileName const & fname, try { ofs.reset(encoding); } catch (iconv_codecvt_facet_exception const & e) { lyxerr << "Caught iconv exception: " << e.what() << endl; - Alert::error(_("Iconv software exception Detected"), bformat(_("Please " - "verify that the support software for your encoding (%1$s) is " - "properly installed"), from_ascii(encoding))); + Alert::error(_("Iconv software exception Detected"), + bformat(_("Please verify that the 'iconv' support software is" + " properly installed and supports the selected encoding" + " (%1$s), or change the encoding in" + " Document>Settings>Language."), from_ascii(encoding))); return ExportError; } if (!openFileWrite(ofs, fname)) @@ -1771,16 +1818,6 @@ Buffer::ExportStatus Buffer::writeLaTeXSource(otexstream & os, OutputParams runparams = runparams_in; - // XeTeX with TeX fonts is only safe with ASCII encoding, - // 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 - // encoding are not converted to ASCII-representation. - // Some macros rely on font encoding runparams.main_fontenc = params().main_font_encoding(); @@ -1799,8 +1836,10 @@ Buffer::ExportStatus Buffer::writeLaTeXSource(otexstream & os, LaTeXFeatures features(*this, params(), runparams); validate(features); // This is only set once per document (in master) - if (!runparams.is_child) + if (!runparams.is_child) { runparams.use_polyglossia = features.usePolyglossia(); + runparams.use_CJK = features.mustProvide("CJK"); + } LYXERR(Debug::LATEX, " Buffer validation done."); bool const output_preamble = @@ -1874,8 +1913,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 +1924,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"; } } @@ -1904,10 +1953,14 @@ Buffer::ExportStatus Buffer::writeLaTeXSource(otexstream & os, // Biblatex bibliographies are loaded here if (params().useBiblatex()) { - vector const bibfiles = + vector> const bibfiles = prepareBibFilePaths(runparams, getBibfiles(), true); - for (docstring const & file: bibfiles) - os << "\\addbibresource{" << file << "}\n"; + for (pair const & file: bibfiles) { + os << "\\addbibresource"; + if (!file.second.empty()) + os << "[bibencoding=" << file.second << "]"; + os << "{" << file.first << "}\n"; + } } if (!runparams.dryrun && features.hasPolyglossiaExclusiveLanguages() @@ -2356,13 +2409,20 @@ 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. Buffer const * const pbuf = masterBuffer(); if (pbuf != this && scope != UpdateChildOnly) return pbuf->getBibfiles(); + + // In 2.3.x, we have: + //if (!d->bibfile_cache_valid_) + // this->updateBibfilesCache(scope); + // I think that is a leftover, but there have been so many back- + // and-forths with this, due to Windows issues, that I am not sure. + return d->bibfiles_cache_; } @@ -2382,7 +2442,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 +2452,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 +2460,31 @@ void Buffer::registerBibfiles(FileNamePairList const & bf) const { } +static map bibfileCache; + +FileName Buffer::getBibfilePath(docstring const & bibid) const +{ + map::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 @@ -2408,17 +2494,35 @@ void Buffer::checkIfBibInfoCacheIsValid() const return; } - // if we already know the cache is invalid, no need to check - // the timestamps + // If we already know the cache is invalid, stop here. + // This is important in the case when the bibliography + // environment (rather than Bib[la]TeX) is used. + // In that case, the timestamp check below gives no + // sensible result. Rather than that, the cache will + // be invalidated explicitly via invalidateBibInfoCache() + // by the Bibitem inset. + // Same applies for bib encoding changes, which trigger + // invalidateBibInfoCache() by InsetBibtex. if (!d->bibinfo_cache_valid_) return; + if (d->have_bibitems_) { + // We have a bibliography environment. + // Invalidate the bibinfo cache unconditionally. + // Cite labels will get invalidated by the inset if needed. + d->bibinfo_cache_valid_ = false; + return; + } + + // OK. This is with Bib(la)tex. We'll assume the cache + // is valid and change this if we find changes in the bibs. + d->bibinfo_cache_valid_ = true; + d->cite_labels_valid_ = true; + // 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,21 +2534,40 @@ void Buffer::checkIfBibInfoCacheIsValid() const } -void Buffer::reloadBibInfoCache() const +void Buffer::clearBibFileCache() const +{ + bibfileCache.clear(); +} + + +void Buffer::reloadBibInfoCache(bool const force) const { + // we should not need to do this for internal buffers + if (isInternal()) + return; + // 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; + } + LYXERR(Debug::FILES, "Bibinfo cache was invalid."); + // 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; + d->have_bibitems_ = false; collectBibKeys(checkedFiles); d->bibinfo_cache_valid_ = true; } @@ -2452,8 +2575,15 @@ void Buffer::reloadBibInfoCache() const void Buffer::collectBibKeys(FileNameList & checkedFiles) const { - for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) + for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { it->collectBibKeys(it, checkedFiles); + if (it->lyxCode() == BIBITEM_CODE) { + if (parent() != 0) + parent()->d->have_bibitems_ = true; + else + d->have_bibitems_ = true; + } + } } @@ -2481,7 +2611,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; } } @@ -2910,6 +3040,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) for ( ; cur ; cur.forwardPar()) cur.paragraph().anonymize(); dr.forceBufferUpdate(); + dr.screenUpdate(Update::Force); break; } @@ -3157,8 +3288,8 @@ string const Buffer::prepareFileNameForLaTeX(string const & name, } -vector const Buffer::prepareBibFilePaths(OutputParams const & runparams, - FileNamePairList const bibfilelist, +vector> const Buffer::prepareBibFilePaths(OutputParams const & runparams, + docstring_list const & bibfilelist, bool const add_extension) const { // If we are processing the LaTeX file in a temp directory then @@ -3171,7 +3302,7 @@ vector const Buffer::prepareBibFilePaths(OutputParams const & runpara // Otherwise, store the (maybe absolute) path to the original, // unmangled database name. - vector res; + vector> res; // determine the export format string const tex_format = flavor2format(runparams.flavor); @@ -3180,7 +3311,7 @@ vector 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 +3320,7 @@ vector 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)); @@ -3243,9 +3374,20 @@ vector const Buffer::prepareBibFilePaths(OutputParams const & runpara if (contains(path, ' ')) found_space = true; + string enc; + if (params().useBiblatex() && !params().bibFileEncoding(utf8input).empty()) + enc = params().bibFileEncoding(utf8input); + + bool recorded = false; + for (pair pe : res) { + if (pe.first == path) { + recorded = true; + break; + } - if (find(res.begin(), res.end(), path) == res.end()) - res.push_back(path); + } + if (!recorded) + res.push_back(make_pair(path, enc)); } // Check if there are spaces in the path and warn BibTeX users, if so. @@ -3789,13 +3931,12 @@ Buffer::References & Buffer::getReferenceCache(docstring const & label) RefCache::iterator it = d->ref_cache_.find(label); if (it != d->ref_cache_.end()) - return it->second.second; + return it->second; - static InsetLabel const * dummy_il = 0; static References const dummy_refs = References(); it = d->ref_cache_.insert( - make_pair(label, make_pair(dummy_il, dummy_refs))).first; - return it->second.second; + make_pair(label, dummy_refs)).first; + return it->second; } @@ -3812,22 +3953,43 @@ void Buffer::addReference(docstring const & label, Inset * inset, ParIterator it } -void Buffer::setInsetLabel(docstring const & label, InsetLabel const * il) +void Buffer::setInsetLabel(docstring const & label, InsetLabel const * il, + bool const active) { - masterBuffer()->d->ref_cache_[label].first = il; + LabelInfo linfo; + linfo.label = label; + linfo.inset = il; + linfo.active = active; + masterBuffer()->d->label_cache_.push_back(linfo); } -InsetLabel const * Buffer::insetLabel(docstring const & label) const +InsetLabel const * Buffer::insetLabel(docstring const & label, + bool const active) const { - return masterBuffer()->d->ref_cache_[label].first; + for (auto & rc : masterBuffer()->d->label_cache_) { + if (rc.label == label && (rc.active || !active)) + return rc.inset; + } + return nullptr; +} + + +bool Buffer::activeLabel(docstring const & label) const +{ + if (!insetLabel(label, true)) + return false; + + return true; } void Buffer::clearReferenceCache() const { - if (!d->parent()) + if (!d->parent()) { d->ref_cache_.clear(); + d->label_cache_.clear(); + } } @@ -3869,6 +4031,9 @@ unique_ptr 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; @@ -4293,9 +4458,15 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir if (!put_in_tempdir) { // Only show this alert if this is an export to a non-temporary // file (not for previewing). - Alert::error(_("Couldn't export file"), bformat( - _("No information for exporting the format %1$s."), - theFormats().prettyName(format))); + docstring s = bformat(_("No information for exporting the format %1$s."), + theFormats().prettyName(format)); + if (format == "pdf4") + s += "\n" + + bformat(_("Hint: use non-TeX fonts or set input encoding " + " to '%1$s' or '%2$s'"), + from_utf8(encodings.fromLyXName("utf8")->guiName()), + from_utf8(encodings.fromLyXName("ascii")->guiName())); + Alert::error(_("Couldn't export file"), s); } return ExportNoPathToFormat; } @@ -4366,7 +4537,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir bformat(_("The directory path to the document\n%1$s\n" "contains spaces, but your TeX installation does " "not allow them. You should save the file to a directory " - "whose name does not contain spaces."), from_ascii(filePath()))); + "whose name does not contain spaces."), from_utf8(filePath()))); return ExportTexPathHasSpaces; } else { runparams.nice = false; @@ -4606,6 +4777,32 @@ Buffer::ReadStatus Buffer::loadEmergency() _("&Remove"), _("&Keep")); if (del_emerg == 0) emergencyFile.removeFile(); + else { + // See bug #11464 + FileName newname; + string const ename = emergencyFile.absFileName(); + bool noname = true; + // Surely we can find one in 100 tries? + for (int i = 1; i < 100; ++i) { + newname.set(ename + to_string(i) + ".lyx"); + if (!newname.exists()) { + noname = false; + break; + } + } + if (!noname) { + // renameTo returns true on success. So inverting that + // will give us true if we fail. + noname = !emergencyFile.renameTo(newname); + } + if (noname) { + Alert::warning(_("Can't rename emergency file!"), + _("LyX was unable to rename the emergency file. " + "You should do so manually. Otherwise, you will be " + "asked about it again the next time you try to load " + "this file, and may over-write your own work.")); + } + } return ReadOriginal; } @@ -4728,7 +4925,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) { @@ -4792,7 +4989,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const return; // if the bibfiles changed, the cache of bibinfo is invalid - FileNamePairList new_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()); @@ -4947,16 +5144,20 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const docstring itemlabel; switch (par.itemdepth) { case 0: + // • U+2022 BULLET itemlabel = char_type(0x2022); break; case 1: + // – U+2013 EN DASH itemlabel = char_type(0x2013); break; case 2: + // ∗ U+2217 ASTERISK OPERATOR itemlabel = char_type(0x2217); break; case 3: - itemlabel = char_type(0x2219); // or 0x00b7 + // · U+00B7 MIDDLE DOT + itemlabel = char_type(0x00b7); break; } par.params().labelString(itemlabel); @@ -5058,6 +5259,11 @@ void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const // to resolve macros in it. parit.text()->setMacrocontextPosition(parit); + // Reset bibitem counter in master (#8499) + Buffer const * const master = masterBuffer(); + if (master == this && !d->ignore_parent) + master->params().documentClass().counters().reset(from_ascii("bibitem")); + depth_type maxdepth = 0; pit_type const lastpit = parit.lastpit(); for ( ; parit.pit() <= lastpit ; ++parit.pit()) {