Do not consider deleted labels in ambiguity check

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.

Cherry-picked from:

    [3ae6bff538/lyxgit]
    [a550a613e8/lyxgit]
    [c457ea90e/lyxgit]
    [5cfd25697/lyxgit]
    [5afacb144/lyxgit]
    [54366c38e/lyxgit]

Fixes: #6563
This commit is contained in:
Juergen Spitzmueller 2019-01-09 09:06:53 +01:00
parent 5f3c0d5aca
commit bfd86a947a
7 changed files with 124 additions and 41 deletions

View File

@ -135,7 +135,22 @@ namespace {
int const LYX_FORMAT = LYX_FORMAT_LYX; int const LYX_FORMAT = LYX_FORMAT_LYX;
typedef map<string, bool> DepClean; 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> LabelCache;
typedef map<docstring, Buffer::References> RefCache;
} // namespace } // namespace
@ -309,7 +324,11 @@ public:
/// was missing). /// was missing).
bool preview_error_; bool preview_error_;
/// Cache the references associated to a label and their positions
/// in the buffer.
mutable RefCache ref_cache_; 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 /// our Text that should be wrapped in an InsetText
InsetText * inset; InsetText * inset;
@ -3915,13 +3934,12 @@ Buffer::References & Buffer::getReferenceCache(docstring const & label)
RefCache::iterator it = d->ref_cache_.find(label); RefCache::iterator it = d->ref_cache_.find(label);
if (it != d->ref_cache_.end()) 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(); static References const dummy_refs = References();
it = d->ref_cache_.insert( it = d->ref_cache_.insert(
make_pair(label, make_pair(dummy_il, dummy_refs))).first; make_pair(label, dummy_refs)).first;
return it->second.second; return it->second;
} }
@ -3938,22 +3956,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 void Buffer::clearReferenceCache() const
{ {
if (!d->parent()) if (!d->parent()) {
d->ref_cache_.clear(); d->ref_cache_.clear();
d->label_cache_.clear();
}
} }

View File

@ -707,18 +707,28 @@ public:
/// ///
bool isExporting() const; bool isExporting() const;
/// /// A collection of InsetRef insets and their position in the buffer
typedef std::vector<std::pair<Inset *, ParIterator> > References; 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; 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); void addReference(docstring const & label, Inset * inset, ParIterator it);
/// /// Clear the whole reference cache
void clearReferenceCache() const; void clearReferenceCache() const;
/// /// Set the InsetLabel for a given \p label string. \p active
void setInsetLabel(docstring const & label, InsetLabel const * il); /// determines whether this is an active label (see @ref activeLabel)
/// void setInsetLabel(docstring const & label, InsetLabel const * il,
InsetLabel const * insetLabel(docstring const & label) const; bool const active);
/// \return the InsetLabel associated with this \p label string
/// If \p active is true we only return active labels
/// (see @ref activeLabel)
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) /// return a list of all used branches (also in children)
void getUsedBranches(std::list<docstring> &, bool const from_master = false) const; void getUsedBranches(std::list<docstring> &, bool const from_master = false) const;

View File

@ -2507,6 +2507,8 @@ bool BufferView::setCursorFromInset(Inset const * inset)
void BufferView::gotoLabel(docstring const & label) void BufferView::gotoLabel(docstring const & label)
{ {
FuncRequest action;
bool have_inactive = false;
ListOfBuffers bufs = buffer().allRelatives(); ListOfBuffers bufs = buffer().allRelatives();
ListOfBuffers::iterator it = bufs.begin(); ListOfBuffers::iterator it = bufs.begin();
for (; it != bufs.end(); ++it) { for (; it != bufs.end(); ++it) {
@ -2517,12 +2519,21 @@ void BufferView::gotoLabel(docstring const & label)
Toc::const_iterator toc_it = toc->begin(); Toc::const_iterator toc_it = toc->begin();
Toc::const_iterator end = toc->end(); Toc::const_iterator end = toc->end();
for (; toc_it != end; ++toc_it) { for (; toc_it != end; ++toc_it) {
if (label == toc_it->str()) { if (label == toc_it->str() && toc_it->isOutput()) {
lyx::dispatch(toc_it->action()); lyx::dispatch(toc_it->action());
return; return;
} }
// If we find an inactive label, save it for the case
// that no active one is there
if (label == toc_it->str() && !have_inactive) {
have_inactive = true;
action = toc_it->action();
}
} }
} }
// We only found an inactive label. Go there.
if (have_inactive)
lyx::dispatch(action);
} }

View File

@ -2041,7 +2041,7 @@ docstring Text::getPossibleLabel(Cursor const & cur) const
// We need a unique label // We need a unique label
docstring label = text; docstring label = text;
int i = 1; int i = 1;
while (cur.buffer()->insetLabel(label)) { while (cur.buffer()->activeLabel(label)) {
label = text + '-' + convert<docstring>(i); label = text + '-' + convert<docstring>(i);
++i; ++i;
} }

View File

@ -67,11 +67,13 @@ void InsetLabel::uniqueLabel(docstring & label) const
{ {
docstring const new_label = label; docstring const new_label = label;
int i = 1; int i = 1;
while (buffer().insetLabel(label)) { bool ambiguous = false;
while (buffer().activeLabel(label)) {
label = new_label + '-' + convert<docstring>(i); label = new_label + '-' + convert<docstring>(i);
++i; ++i;
ambiguous = true;
} }
if (label != new_label) { if (ambiguous) {
// Warn the user that the label has been changed to something else. // Warn the user that the label has been changed to something else.
frontend::Alert::warning(_("Label names must be unique!"), frontend::Alert::warning(_("Label names must be unique!"),
bformat(_("The label %1$s already exists,\n" bformat(_("The label %1$s already exists,\n"
@ -146,12 +148,27 @@ docstring InsetLabel::screenLabel() const
void InsetLabel::updateBuffer(ParIterator const & par, UpdateType utype) void InsetLabel::updateBuffer(ParIterator const & par, UpdateType utype)
{ {
docstring const & label = getParam("name"); 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 active = !para.isDeleted(par.pos());
// If not, check whether we are in a deleted inset
if (active) {
for (size_type sl = 0 ; sl < par.depth() ; ++sl) {
Paragraph const & outer_par = par[sl].paragraph();
if (outer_par.isDeleted(par[sl].pos())) {
active = false;
break;
}
}
}
if (buffer().activeLabel(label) && active) {
// Problem: We already have an active InsetLabel with the same name!
screen_label_ = _("DUPLICATE: ") + label; screen_label_ = _("DUPLICATE: ") + label;
return; return;
} }
buffer().setInsetLabel(label, this); buffer().setInsetLabel(label, this, active);
screen_label_ = label; screen_label_ = label;
if (utype == OutputUpdate) { if (utype == OutputUpdate) {
@ -175,23 +192,25 @@ void InsetLabel::addToToc(DocIterator const & cpit, bool output_active,
UpdateType, TocBackend & backend) const UpdateType, TocBackend & backend) const
{ {
docstring const & label = getParam("name"); docstring const & label = getParam("name");
// inactive labels get a cross mark
if (buffer().insetLabel(label, true) != this)
output_active = false;
// We put both active and inactive labels to the outliner
shared_ptr<Toc> toc = backend.toc("label"); shared_ptr<Toc> toc = backend.toc("label");
if (buffer().insetLabel(label) != this) { toc->push_back(TocItem(cpit, 0, screen_label_, output_active));
toc->push_back(TocItem(cpit, 0, screen_label_, output_active)); // The refs get assigned only to the active label. If no active one exists,
} else { // assign the (BROKEN) refs to the first inactive one.
toc->push_back(TocItem(cpit, 0, screen_label_, output_active)); if (buffer().insetLabel(label, true) == this || !buffer().activeLabel(label)) {
Buffer::References const & refs = buffer().references(label); for (auto const & p : buffer().references(label)) {
Buffer::References::const_iterator it = refs.begin(); DocIterator const ref_pit(p.second);
Buffer::References::const_iterator end = refs.end(); if (p.first->lyxCode() == MATH_REF_CODE)
for (; it != end; ++it) {
DocIterator const ref_pit(it->second);
if (it->first->lyxCode() == MATH_REF_CODE)
toc->push_back(TocItem(ref_pit, 1, toc->push_back(TocItem(ref_pit, 1,
it->first->asInsetMath()->asRefInset()->screenLabel(), p.first->asInsetMath()->asRefInset()->screenLabel(),
output_active)); output_active));
else else
toc->push_back(TocItem(ref_pit, 1, toc->push_back(TocItem(ref_pit, 1,
static_cast<InsetRef *>(it->first)->getTOCString(), static_cast<InsetRef *>(p.first)->getTOCString(),
output_active)); output_active));
} }
} }

View File

@ -303,7 +303,7 @@ int InsetRef::docbook(odocstream & os, OutputParams const & runparams) const
docstring InsetRef::xhtml(XHTMLStream & xs, OutputParams const & op) const docstring InsetRef::xhtml(XHTMLStream & xs, OutputParams const & op) const
{ {
docstring const & ref = getParam("reference"); docstring const & ref = getParam("reference");
InsetLabel const * il = buffer().insetLabel(ref); InsetLabel const * il = buffer().insetLabel(ref, true);
string const & cmd = params().getCmdName(); string const & cmd = params().getCmdName();
docstring display_string; docstring display_string;
@ -423,9 +423,11 @@ void InsetRef::addToToc(DocIterator const & cpit, bool output_active,
UpdateType, TocBackend & backend) const UpdateType, TocBackend & backend) const
{ {
docstring const & label = getParam("reference"); docstring const & label = getParam("reference");
if (buffer().insetLabel(label)) if (buffer().insetLabel(label)) {
broken_ = !buffer().activeLabel(label);
// This InsetRef has already been taken care of in InsetLabel::addToToc(). // This InsetRef has already been taken care of in InsetLabel::addToToc().
return; return;
}
// It seems that this reference does not point to any valid label. // It seems that this reference does not point to any valid label.

View File

@ -134,6 +134,8 @@ What's new
- Fix display of gather environment in leqno mode (bug 11324). - Fix display of gather environment in leqno mode (bug 11324).
- Fix handling of labels with change tracking (bug 6563).
* INTERNALS * INTERNALS