[LyX/2.5.x] Implement LFUN_REFERENCE_TO_PARAGRAPH for mathed (#13206)
Juergen Spitzmueller <[email protected]> Thu, 23 Apr 2026 16:49:43 +0000
| Newsgroups | gmane.editors.lyx.cvs |
|---|---|
| Message-ID | <[email protected]> |
commit 4287c94d0bf5aafeed1cc1927964cbbb067c144f Author: Juergen Spitzmueller <[email protected]> Date: Sun Oct 12 13:47:06 2025 +0200 Implement LFUN_REFERENCE_TO_PARAGRAPH for mathed (#13206) This allows to enter references to numbered math formulae directly from the outliner (or the list of existing equations in the cross ref dialog), whether they already have a label or not (as for text elements). (cherry picked from commit 1b82fc4d8eb50dac7eef743a0ac95002f5709589) --- lib/ui/stdcontext.inc | 9 ++++++ src/BufferView.cpp | 72 ++++++++++++++++++++++++++++++-------------- src/TocBuilder.cpp | 28 +++++++++++++++-- src/TocBuilder.h | 4 ++- src/frontends/qt/GuiRef.cpp | 5 ++- src/mathed/InsetMathHull.cpp | 19 ++++++------ src/mathed/InsetMathHull.h | 2 +- 7 files changed, 101 insertions(+), 38 deletions(-) diff --git a/lib/ui/stdcontext.inc b/lib/ui/stdcontext.inc index ad8571d0ed..316be4031b 100644 --- a/lib/ui/stdcontext.inc +++ b/lib/ui/stdcontext.inc @@ -593,6 +593,15 @@ Menuset End +# +# Toc Equation context menu +# + + Menu "context-toc-equation" + SubMenu "Insert Cross-Reference to this Item|C" "context-toc-ref-to-par" + End + + # # Toc Footnotes context menu # diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 7dc58b000d..2a4a6707ed 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -53,6 +53,7 @@ #include "insets/InsetRef.h" #include "insets/InsetText.h" +#include "mathed/InsetMathHull.h" #include "mathed/InsetMathNest.h" #include "mathed/InsetMathRef.h" #include "mathed/MathData.h" @@ -1723,6 +1724,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) vector<string> const pids = getVectorFromString(cmd.getArg(0)); string const type = cmd.getArg(1); int id = convert<int>(pids.back()); + row_type row = -1; inserted_label_.clear(); if (id < 0) break; @@ -1735,43 +1737,69 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) ++i; continue; } - string label = dit.innerParagraph().getLabelForXRef(); + string label; + if (dit.nextInset() && dit.nextInset()->asInsetMath() && dit.nextInset()->asInsetMath()->asHullInset()) { + row = convert<row_type>(pids.front()); + label = to_utf8(dit.nextInset()->asInsetMath()->asHullInset()->label(row)); + } else + label = dit.innerParagraph().getLabelForXRef(); if (!label.empty()) { // if the paragraph has a label, we use this if (type == "forrefdialog") + // only store the label for the dialog to take it inserted_label_ = label; else { + // insert a reference to the label (e.g., from outliner) string const arg = (type.empty()) ? label : label + " " + type; lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg)); cur.forceBufferUpdate(); } break; } else { - // if there is not a label yet - // go to the paragraph (including nested insets) ... - lyx::dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0")); - for (string const & s : pids) { - id = convert<int>(s); - if (id < 0) - break; - dit = b->getParFromID(id); - lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_GOTO, s)); + // if there is not a label yet, insert one + // this categorically differes in texted and mathed + docstring new_label; + if (dit.nextInset() && dit.nextInset()->asInsetMath() && dit.nextInset()->asInsetMath()->asHullInset()) { + // in mathed, we set the label via InsetMathHull::label() + // but we need to assure it is unique + new_label = from_ascii("eq:equation"); + int j = 1; + while (buffer().activeLabel(new_label)) { + new_label = new_label + '-' + convert<docstring>(j); + ++j; + } + // record undo for the math inset next to dit + cur.buffer()->undo().recordUndoInset(CursorData(dit), dit.nextInset()); + // insert the label to the desired row of the hull inset + dit.nextInset()->asInsetMath()->asHullInset()->label(row, new_label, true); + // needed to get the new label into the buffer list + cur.buffer()->updateBuffer(); + } else { + // in texted, go to the paragraph (including nested insets) ... + lyx::dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0")); + for (string const & s : pids) { + id = convert<int>(s); + if (id < 0) + break; + dit = b->getParFromID(id); + lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_GOTO, s)); + } + // insert a new label + // we do not want to open the dialog, hence we + // do not employ LFUN_LABEL_INSERT + InsetCommandParams p(LABEL_CODE); + new_label = dit.getPossibleLabel(); + p["name"] = new_label; + string const data = InsetCommand::params2string(p); + lyx::dispatch(FuncRequest(LFUN_INSET_INSERT, data)); + // ... go back to the original position + lyx::dispatch(FuncRequest(LFUN_BOOKMARK_GOTO, "0")); } - // ... if not, insert a new label - // we do not want to open the dialog, hence we - // do not employ LFUN_LABEL_INSERT - InsetCommandParams p(LABEL_CODE); - docstring const new_label = dit.getPossibleLabel(); - p["name"] = new_label; - string const data = InsetCommand::params2string(p); - lyx::dispatch(FuncRequest(LFUN_INSET_INSERT, data)); - // ... go back to the original position - lyx::dispatch(FuncRequest(LFUN_BOOKMARK_GOTO, "0")); if (type == "forrefdialog") - // ... and save for the ref dialog to insert + // save for the ref dialog to insert inserted_label_ = to_utf8(new_label); else { - // ... or insert the ref directly (from outliner) + // or insert the ref directly (from outliner) string const arg = (type.empty()) ? to_utf8(new_label) : to_utf8(new_label) + " " + type; lyx::dispatch(FuncRequest(LFUN_REFERENCE_INSERT, arg)); diff --git a/src/TocBuilder.cpp b/src/TocBuilder.cpp index fb688bd58e..458a95db66 100644 --- a/src/TocBuilder.cpp +++ b/src/TocBuilder.cpp @@ -15,6 +15,7 @@ #include "DocIterator.h" #include "TocBackend.h" +#include "support/convert.h" #include "support/lassert.h" using namespace std; @@ -32,9 +33,16 @@ TocBuilder::TocBuilder(shared_ptr<Toc> const & toc) } void TocBuilder::pushItem(DocIterator const & dit, docstring const & s, - bool output_active, bool is_captioned) + bool output_active, bool is_captioned, int row) { - toc_->push_back(TocItem(dit, stack_.size(), s, output_active)); + TocItem item(dit, stack_.size(), s, output_active); + if (row != -1) { + docstring parID = item.parIDs(); + if (!stack_.empty()) + parID = (*toc_)[stack_.top().pos].dit().paragraphGotoArgument(true); + item.setParIDs(convert<docstring>(row) + ',' + parID); + } + toc_->push_back(item); frame f = { toc_->size() - 1, //pos is_captioned, //is_captioned @@ -87,6 +95,22 @@ void TocBuilder::argumentItem(docstring const & arg_str) stack_.top().is_captioned = true; } +void TocBuilder::mathMultilineItem(docstring const & arg_str, Toc::size_type row) +{ + if (stack_.empty() || arg_str.empty()) + return; + TocItem & item = (*toc_)[stack_.top().pos]; + docstring const & str = item.str(); + string const & delim = + (str.empty() || !stack_.top().is_captioned) ? "" : ", "; + item.str(str + from_ascii(delim) + arg_str); + docstring parID = item.parIDs(); + if (!stack_.empty()) + parID = (*toc_)[stack_.top().pos].dit().paragraphGotoArgument(true); + item.setParIDs(convert<docstring>(row) + ',' + parID); + stack_.top().is_captioned = true; +} + void TocBuilder::pop() { if (!stack_.empty()) diff --git a/src/TocBuilder.h b/src/TocBuilder.h index af9c41cb24..23d5fe8329 100644 --- a/src/TocBuilder.h +++ b/src/TocBuilder.h @@ -31,7 +31,7 @@ public: /// Open a level. /// When entering a float or flex or paragraph (with AddToToc) void pushItem(DocIterator const & dit, docstring const & s, - bool output_active, bool is_captioned = false); + bool output_active, bool is_captioned = false, int row = -1); /// Edit entry at current level. Add new entry if already captioned. /// When encountering a float caption void captionItem(DocIterator const & dit, docstring const & s, @@ -39,6 +39,8 @@ public: /// Edit entry at current level (always). /// When encountering an argument (with isTocCaption) for flex or paragraph void argumentItem(docstring const & arg_str); + /// + void mathMultilineItem(docstring const & arg_str, Toc::size_type row); /// Close a level. /// When exiting a float or flex or paragraph void pop(); diff --git a/src/frontends/qt/GuiRef.cpp b/src/frontends/qt/GuiRef.cpp index 3cf94b7ae2..86136e1cb9 100644 --- a/src/frontends/qt/GuiRef.cpp +++ b/src/frontends/qt/GuiRef.cpp @@ -566,9 +566,8 @@ void GuiRef::updateTargets() targetCO->addItem(toqstr(translateIfPossible(name.second)), toqstr(name.first)); } } -// FIXME This does not work yet with REFERENCE_TO_PARAGRAPH -// if (isTargetAvailable("equation")) -// targetCO->addItem(qt_("Equations"), "equation"); + if (isTargetAvailable("equation")) + targetCO->addItem(qt_("Equations"), "equation"); // restore previous setting int const i = targetCO->findData(target); if (i != -1) diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index 33656e12f7..b7c5749f53 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -354,8 +354,8 @@ void InsetMathHull::addToToc(DocIterator const & pit, bool output_active, TocBuilder & b = backend.builder("equation"); b.pushItem(pit, docstring(), output_active); if (first != last) - b.argumentItem(bformat(from_ascii("(%1$s-%2$s)"), - numbers_[first], numbers_[last])); + b.mathMultilineItem(bformat(from_ascii("(%1$s-%2$s)"), + numbers_[first], numbers_[last]), 0); odocstringstream ods; Encoding const * enc = encodings.fromLyXName("utf8"); @@ -373,7 +373,7 @@ void InsetMathHull::addToToc(DocIterator const & pit, bool output_active, if (first == last) { // this is the only equation plaintext(ods, ops, max_length); - b.argumentItem(label + " " + ods.str()); + b.mathMultilineItem(label + " " + ods.str(), row); } else { // insert as sub-items otexrowstream ots(ods); @@ -387,7 +387,7 @@ void InsetMathHull::addToToc(DocIterator const & pit, bool output_active, break; } } - b.pushItem(pit, label+ " " + d, output_active); + b.pushItem(pit, label+ " " + d, output_active, false, row); // clear the stringstream odocstringstream().swap(ods); b.pop(); @@ -1002,7 +1002,7 @@ docstring InsetMathHull::label(row_type row) const } -void InsetMathHull::label(row_type row, docstring const & label) +void InsetMathHull::label(row_type row, docstring const & label, bool const init) { //lyxerr << "setting label '" << label << "' for row " << row << endl; if (labels_[row]) { @@ -1022,6 +1022,9 @@ void InsetMathHull::label(row_type row, docstring const & label) labels_[row] = new InsetLabel(buffer_, p); if (buffer_) labels_[row]->setBuffer(buffer()); + if (init) + // Newly created inset so initialize it. + labels_[row]->initView(); } @@ -2087,11 +2090,9 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) if (labels_[r]) // The label will take care of the reference update. label(r, str); - else { - label(r, str); + else // Newly created inset so initialize it. - labels_[r]->initView(); - } + label(r, str, true); } cur.forceBufferUpdate(); break; diff --git a/src/mathed/InsetMathHull.h b/src/mathed/InsetMathHull.h index e25e516e0c..b5cfe92f03 100644 --- a/src/mathed/InsetMathHull.h +++ b/src/mathed/InsetMathHull.h @@ -71,7 +71,7 @@ public: /// docstring label(row_type row) const; /// - void label(row_type row, docstring const & label); + void label(row_type row, docstring const & label, bool const init = false); /// std::vector<InsetLabel *> const & getLabels() { return labels_; } /// -- lyx-cvs mailing list [email protected] https://lists.lyx.org/mailman/listinfo/lyx-cvs