]> git.lyx.org Git - features.git/commitdiff
Do not consider deleted labels in ambiguity check
authorJuergen Spitzmueller <spitz@lyx.org>
Sat, 29 Dec 2018 09:08:02 +0000 (10:08 +0100)
committerJean-Marc Lasgouttes <lasgouttes@lyx.org>
Thu, 18 Jun 2020 12:39:54 +0000 (14:39 +0200)
This adds a new (boolean) parameter "active" to the label cache, where
we track whether a label is deleted in ct mode (the same could be done,
if wanted, for labels in notes and inactive branches).

Deleted (inactive) labels are neither considered in the uniqueness check
nor added to the outliner. This also means that undeleted references to
deleted labels are now (correctly) marked as BROKEN.

Fixes: #6563
src/Buffer.cpp
src/Buffer.h
src/Text.cpp
src/insets/InsetLabel.cpp
src/insets/InsetRef.cpp

index b7f8b679f225933737c3e7c3c396b6d57b9aaf36..fc27823c1f0efc163239aa429dc5a158aea519cc 100644 (file)
@@ -135,7 +135,20 @@ namespace {
 int const LYX_FORMAT = LYX_FORMAT_LYX;
 
 typedef map<string, bool> DepClean;
-typedef map<docstring, pair<InsetLabel const *, Buffer::References> > 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<LabelInfo> RefCache;
 
 } // namespace
 
@@ -305,6 +318,8 @@ public:
        /// was missing).
        bool preview_error_;
 
+       /// Cache the insets, their associated refs (with positions),
+       /// and whether the insets are active.
        mutable RefCache ref_cache_;
 
        /// our Text that should be wrapped in an InsetText
@@ -3882,15 +3897,33 @@ Buffer::References & Buffer::getReferenceCache(docstring const & label)
        if (d->parent())
                return const_cast<Buffer *>(masterBuffer())->getReferenceCache(label);
 
-       RefCache::iterator it = d->ref_cache_.find(label);
-       if (it != d->ref_cache_.end())
-               return it->second.second;
+       // In what follows, we look whether we find an active label
+       // with the given string in the cache. If so, return its
+       // references cache. If we only find an inactive one, return
+       // that (the last we find, coincidentally). If we find noting,
+       // return an empty references cache.
+       static LabelInfo linfo;
+       linfo.inset = nullptr;
+       linfo.references = References();
+       linfo.active = false;
+       bool have_inactive = false;
+       for (auto & rc : d->ref_cache_) {
+               if (rc.label == label) {
+                       if (rc.active)
+                               return rc.references;
+                       else {
+                               linfo = rc;
+                               have_inactive = true;
+                       }
+               }
+       }
+
+       if (!have_inactive)
+               // We found nothing, so insert the empty one to the cache
+               // for further processing
+               d->ref_cache_.push_back(linfo);
 
-       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;
+       return linfo.references;
 }
 
 
@@ -3907,15 +3940,39 @@ 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;
+       static LabelInfo linfo;
+       linfo.label = label;
+       linfo.inset = il;
+       linfo.references = References();
+       linfo.active = active;
+       masterBuffer()->d->ref_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->ref_cache_) {
+               if (rc.label == label && (rc.active || !active))
+                       return rc.inset;
+       }
+       return nullptr;
+}
+
+
+bool Buffer::activeLabel(docstring const & label) const
+{
+       if (!insetLabel(label))
+               return false;
+
+       for (auto & rc : masterBuffer()->d->ref_cache_) {
+               if (rc.label == label && rc.active)
+                       return true;
+       }
+       return false;
 }
 
 
index 4037e5a1e60861b711e6728fa3ace1c6f50f6168..a6cbd572d364d907e44e5be4ce5f998a4df60df5 100644 (file)
@@ -698,18 +698,27 @@ public:
        ///
        bool isExporting() const;
 
-       ///
+       /// A collection of InsetRef insets and their position in the buffer
        typedef std::vector<std::pair<Inset *, ParIterator> > References;
-       ///
+       /// Get all InsetRef insets and their positions associated with
+       /// the InsetLabel with the label string \p label
        References const & references(docstring const & label) const;
-       ///
+       /// Add an InsetRef at position \p it to the Insetlabel
+       /// with the label string \p label
        void addReference(docstring const & label, Inset * inset, ParIterator it);
-       ///
+       /// Clear the whole reference cache
        void clearReferenceCache() const;
-       ///
-       void setInsetLabel(docstring const & label, InsetLabel const * il);
-       ///
-       InsetLabel const * insetLabel(docstring const & label) const;
+       /// Set the InsetLabel for a given \p label string. \p active
+       /// determines whether this is an active label (see @ref activeLabel)
+       void setInsetLabel(docstring const & label, InsetLabel const * il,
+                          bool const active);
+       /// \return the InsetLabel associated with this \p label string
+       /// If \p active is true we only return active labels.
+       InsetLabel const * insetLabel(docstring const & label,
+                                     bool const active = false) const;
+       /// \return true if this \param label is an active label.
+       /// Inactive labels are currently deleted labels (in ct mode)
+       bool activeLabel(docstring const & label) const;
 
        /// return a list of all used branches (also in children)
        void getUsedBranches(std::list<docstring> &, bool const from_master = false) const;
index 70f8eaa4723fb229dda2f96ac794bba2ef393f9b..c3c21084727b7eb6f83165ff1832f638d0394ecf 100644 (file)
@@ -2047,7 +2047,7 @@ docstring Text::getPossibleLabel(DocIterator const & cur) const
        // We need a unique label
        docstring label = text;
        int i = 1;
-       while (cur.buffer()->insetLabel(label)) {
+       while (cur.buffer()->activeLabel(label)) {
                        label = text + '-' + convert<docstring>(i);
                        ++i;
                }
index 4dd0713730e921e74f444c2462bc6b90326000ec..f6538f4c45429b45b676a24aa3c50f00a4e77af6 100644 (file)
@@ -67,11 +67,13 @@ void InsetLabel::uniqueLabel(docstring & label) const
 {
        docstring const new_label = label;
        int i = 1;
-       while (buffer().insetLabel(label)) {
+       bool ambiguous = false;
+       while (buffer().activeLabel(label)) {
                label = new_label + '-' + convert<docstring>(i);
                ++i;
+               ambiguous = true;
        }
-       if (label != new_label) {
+       if (ambiguous) {
                // Warn the user that the label has been changed to something else.
                frontend::Alert::warning(_("Label names must be unique!"),
                        bformat(_("The label %1$s already exists,\n"
@@ -143,12 +145,17 @@ docstring InsetLabel::screenLabel() const
 void InsetLabel::updateBuffer(ParIterator const & par, UpdateType utype)
 {
        docstring const & label = getParam("name");
-       if (buffer().insetLabel(label)) {
-               // Problem: We already have an InsetLabel with the same name!
+
+       // Check if this one is deleted (ct)
+       Paragraph const & para = par.paragraph();
+       bool const active = !para.isDeleted(par.pos());
+
+       if (buffer().activeLabel(label) && active) {
+               // Problem: We already have an active InsetLabel with the same name!
                screen_label_ = _("DUPLICATE: ") + label;
                return;
        }
-       buffer().setInsetLabel(label, this);
+       buffer().setInsetLabel(label, this, active);
        screen_label_ = label;
 
        if (utype == OutputUpdate) {
@@ -172,8 +179,11 @@ void InsetLabel::addToToc(DocIterator const & cpit, bool output_active,
                                                  UpdateType, TocBackend & backend) const
 {
        docstring const & label = getParam("name");
+       if (!buffer().activeLabel(label))
+               return;
+
        shared_ptr<Toc> toc = backend.toc("label");
-       if (buffer().insetLabel(label) != this) {
+       if (buffer().insetLabel(label, true) != this) {
                toc->push_back(TocItem(cpit, 0, screen_label_, output_active));
        } else {
                toc->push_back(TocItem(cpit, 0, screen_label_, output_active));
index 124738daf7a88d6e0bea4584527eaf2d5d72a545..9f23ca46848b6e178ea0d3843b3666a903292064 100644 (file)
@@ -303,7 +303,7 @@ int InsetRef::docbook(odocstream & os, OutputParams const & runparams) const
 docstring InsetRef::xhtml(XHTMLStream & xs, OutputParams const & op) const
 {
        docstring const & ref = getParam("reference");
-       InsetLabel const * il = buffer().insetLabel(ref);
+       InsetLabel const * il = buffer().insetLabel(ref, true);
        string const & cmd = params().getCmdName();
        docstring display_string;
 
@@ -423,7 +423,7 @@ void InsetRef::addToToc(DocIterator const & cpit, bool output_active,
                                                UpdateType, TocBackend & backend) const
 {
        docstring const & label = getParam("reference");
-       if (buffer().insetLabel(label))
+       if (buffer().activeLabel(label))
                // This InsetRef has already been taken care of in InsetLabel::addToToc().
                return;