commit 68109443f3738b89574cfc82bc30b14e0c31a8be
Author: Guillaume Munch <[email protected]>
Date:   Sun Jan 8 21:57:02 2017 +0100

    Implement AddToToc for paragraph layouts
    
    Enables table of Theorems & Definitions
---
 src/Paragraph.cpp        |    6 ++--
 src/Paragraph.h          |    4 +-
 src/Text.cpp             |   47 ++++++++++++++++++++++++++++++++------
 src/Text.h               |   13 ++++++++--
 src/TocBackend.cpp       |    2 +-
 src/TocBackend.h         |    9 ++++---
 src/insets/InsetFlex.cpp |    3 +-
 src/insets/InsetText.cpp |   56 +++++++++++++++++++++++++++++++++++++++++++--
 src/insets/InsetText.h   |    7 +++++
 9 files changed, 122 insertions(+), 25 deletions(-)

diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index ba101e4..6d50f27 100644
--- a/src/Paragraph.cpp
+++ b/src/Paragraph.cpp
@@ -3333,11 +3333,11 @@ docstring Paragraph::asString(pos_type beg, pos_type 
end, int options, const Out
 
 
 void Paragraph::forOutliner(docstring & os, size_t const maxlen,
-                                                       bool const shorten) 
const
+                            bool const shorten, bool const label) const
 {
        size_t tmplen = shorten ? maxlen + 1 : maxlen;
-       if (!d->params_.labelString().empty())
-               os += d->params_.labelString() + ' ';
+       if (label && !labelString().empty())
+               os += labelString() + ' ';
        for (pos_type i = 0; i < size() && os.length() < tmplen; ++i) {
                if (isDeleted(i))
                        continue;
diff --git a/src/Paragraph.h b/src/Paragraph.h
index 2133d8c..813640e 100644
--- a/src/Paragraph.h
+++ b/src/Paragraph.h
@@ -181,8 +181,8 @@ public:
                           int options = AS_STR_NONE,
                           const OutputParams *runparams = 0) const;
        ///
-       void forOutliner(docstring &, size_t const maxlen,
-                                        bool const shorten = true) const;
+       void forOutliner(docstring &, size_t maxlen, bool shorten = true,
+                        bool label = true) const;
 
        ///
        void write(std::ostream &, BufferParams const &,
diff --git a/src/Text.cpp b/src/Text.cpp
index 8e0d1be..8d08baa 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -240,6 +240,21 @@ bool Text::isFirstInSequence(pit_type par_offset) const
 }
 
 
+pit_type Text::lastInSequence(pit_type pit) const
+{
+       depth_type const depth = pars_[pit].getDepth();
+       pit_type newpit = pit;
+
+       while (size_t(newpit + 1) < pars_.size() &&
+              (pars_[newpit + 1].getDepth() > depth ||
+               (pars_[newpit + 1].getDepth() == depth &&
+                pars_[newpit + 1].layout() == pars_[pit].layout())))
+               ++newpit;
+
+       return newpit;
+}
+
+
 int Text::getTocLevel(pit_type par_offset) const
 {
        Paragraph const & par = pars_[par_offset];
@@ -2042,20 +2057,36 @@ docstring Text::asString(pit_type beg, pit_type end, 
int options) const
 void Text::shortenForOutliner(docstring & str, size_t const maxlen)
 {
        support::truncateWithEllipsis(str, maxlen);
-       docstring::iterator it = str.begin();
-       docstring::iterator end = str.end();
-       for (; it != end; ++it)
-               if ((*it) == L'\n' || (*it) == L'\t')
-                       (*it) = L' ';   
+       for (char_type & c : str)
+               if (c == L'\n' || c == L'\t')
+                       c = L' ';
 }
 
 
 void Text::forOutliner(docstring & os, size_t const maxlen,
-                                          bool const shorten) const
+                       bool const shorten) const
+{
+       pit_type end = pars_.size() - 1;
+       if (0 <= end && !pars_[0].labelString().empty())
+               os += pars_[0].labelString() + ' ';
+       forOutliner(os, maxlen, 0, end, shorten);
+}
+
+
+void Text::forOutliner(docstring & os, size_t const maxlen,
+                       pit_type pit_start, pit_type pit_end,
+                       bool const shorten) const
 {
        size_t tmplen = shorten ? maxlen + 1 : maxlen;
-       for (size_t i = 0; i != pars_.size() && os.length() < tmplen; ++i)
-               pars_[i].forOutliner(os, tmplen, false);
+       pit_type end = min(size_t(pit_end), pars_.size() - 1);
+       bool first = true;
+       for (pit_type i = pit_start; i <= end && os.length() < tmplen; ++i) {
+               if (!first)
+                       os += ' ';
+               // This function lets the first label be treated separately
+               pars_[i].forOutliner(os, tmplen, false, !first);
+               first = false;
+       }
        if (shorten)
                shortenForOutliner(os, maxlen);
 }
diff --git a/src/Text.h b/src/Text.h
index bdf2169..f49c8e2 100644
--- a/src/Text.h
+++ b/src/Text.h
@@ -130,9 +130,13 @@ public:
                
        /// Appends a possibly abbreviated representation of our text to \param 
os,
        /// where \param maxlen defines the maximum size of \param os. If \param
-       /// shorten is true, then os is shortened as above
-       void forOutliner(docstring & os, size_t const maxlen,
-                                        bool const shorten = true) const;
+       /// shorten is true, then os is shortened as above.
+       void forOutliner(docstring & os, size_t maxlen, bool shorten = true) 
const;
+       /// Appends a possibly abbreviated representation of our text, from
+       /// start to end, to \param os, where \param maxlen defines the
+       /// maximum size of \param os. Omits the label of the first paragraph.
+       void forOutliner(docstring & os, size_t maxlen, pit_type start, 
pit_type end,
+                        bool shorten = true) const;
 
        /// insert a character at cursor position
        /// FIXME: replace Cursor with DocIterator.
@@ -329,6 +333,9 @@ public:
        pit_type outerHook(pit_type pit) const;
        /// Is it the first par with same depth and layout?
        bool isFirstInSequence(pit_type pit) const;
+       /// Return the last paragraph with same depth and layout, or a strictly
+       /// greater depth
+       pit_type lastInSequence(pit_type pit) const;
        /// Is this paragraph in the table of contents?
        int getTocLevel(pit_type pit) const;
        /// Get the font of the "environment" of paragraph \p par_offset in \p 
pars.
diff --git a/src/TocBackend.cpp b/src/TocBackend.cpp
index f490c35..6c7c1f9 100644
--- a/src/TocBackend.cpp
+++ b/src/TocBackend.cpp
@@ -200,7 +200,7 @@ void TocBuilder::argumentItem(docstring const & arg_str)
        TocItem & item = (*toc_)[stack_.top().pos];
        docstring const & str = item.str();
        string const & delim =
-               str.empty() ? "" : stack_.top().is_captioned ? ", " : ": ";
+               (str.empty() || !stack_.top().is_captioned) ? "" :  ", ";
        item.str(str + from_ascii(delim) + arg_str);
        stack_.top().is_captioned = true;
 }
diff --git a/src/TocBackend.h b/src/TocBackend.h
index b851d68..08754b9 100644
--- a/src/TocBackend.h
+++ b/src/TocBackend.h
@@ -56,6 +56,7 @@ enum TocType {
        MATH_MACRO,//"math-macro"
        EXTERNAL,//"external"
        SENSELESS,//"senseless"
+       USER_DEFINED,//any value defined in the layouts
        TOC_TYPE_COUNT
 }
  */
@@ -119,16 +120,16 @@ private:
 class TocBuilder
 {
 public:
-       TocBuilder(std::shared_ptr<Toc> const toc);
-       /// When entering a float or flex (AddToToc)
+       TocBuilder(std::shared_ptr<Toc> toc);
+       /// 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);
        /// When encountering a float caption
        void captionItem(DocIterator const & dit, docstring const & s,
                         bool output_active);
-       /// When encountering an argument (isTocCaption)
+       /// When encountering an argument (with isTocCaption) for flex or 
paragraph
        void argumentItem(docstring const & arg_str);
-       /// When exiting a float or flex
+       /// When exiting a float or flex or paragraph
        void pop();
 private:
        TocBuilder(){}
diff --git a/src/insets/InsetFlex.cpp b/src/insets/InsetFlex.cpp
index 05cbb29..ee3b7c8 100644
--- a/src/insets/InsetFlex.cpp
+++ b/src/insets/InsetFlex.cpp
@@ -175,7 +175,8 @@ void InsetFlex::addToToc(DocIterator const & cpit, bool 
output_active,
                // Cursor inside the inset
                DocIterator pit = cpit;
                pit.push_back(CursorSlice(const_cast<InsetFlex &>(*this)));
-               b.pushItem(pit, getLabel(), output_active);
+               docstring const label = getLabel();
+               b.pushItem(pit, label + (label.empty() ? "" : ": "), 
output_active);
                // Proceed with the rest of the inset.
                InsetCollapsable::addToToc(cpit, output_active, utype);
                if (layout.isTocCaption()) {
diff --git a/src/insets/InsetText.cpp b/src/insets/InsetText.cpp
index 607f7f5..db6b744 100644
--- a/src/insets/InsetText.cpp
+++ b/src/insets/InsetText.cpp
@@ -851,13 +851,29 @@ void InsetText::iterateForToc(DocIterator const & cdit, 
bool output_active,
        // can't hurt too much to do it again
        bool const doing_output = output_active && producesOutput();
 
-       // For each paragraph, traverse its insets and let them add
-       // their toc items
+       // For each paragraph,
+       // * Add a toc item for the paragraph if it is AddToToc--merging 
adjacent
+       //   paragraphs as needed.
+       // * Traverse its insets and let them add their toc items
+       // * Compute the main table of contents (this is hardcoded)
+       // * Add the list of changes
        ParagraphList const & pars = paragraphs();
        pit_type pend = paragraphs().size();
+       // Record pairs {start,end} of where a toc item was opened for a 
paragraph
+       // and where it must be closed
+       stack<pair<pit_type, pit_type>> addtotoc_stack;
+
        for (pit_type pit = 0; pit != pend; ++pit) {
                Paragraph const & par = pars[pit];
                dit.pit() = pit;
+               dit.pos() = 0;
+
+               // Custom AddToToc in paragraph layouts (i.e. theorems)
+               if (par.layout().addToToc() && text().isFirstInSequence(pit)) {
+                       pit_type end = openAddToTocForParagraph(pit, dit, 
output_active);
+                       addtotoc_stack.push({pit, end});
+               }
+
                // if we find an optarg, we'll save it for use later.
                InsetText const * arginset = 0;
                InsetList::const_iterator it  = par.insetList().begin();
@@ -870,7 +886,16 @@ void InsetText::iterateForToc(DocIterator const & cdit, 
bool output_active,
                        if (inset.lyxCode() == ARG_CODE)
                                arginset = inset.asInsetText();
                }
-               // now the toc entry for the paragraph
+
+               // End custom AddToToc in paragraph layouts
+               while (!addtotoc_stack.empty() && addtotoc_stack.top().second 
== pit) {
+                       // execute the closing function
+                       closeAddToTocForParagraph(addtotoc_stack.top().first,
+                                                 addtotoc_stack.top().second);
+                       addtotoc_stack.pop();
+               }
+
+               // now the toc entry for the paragraph in the main table of 
contents
                int const toclevel = text().getTocLevel(pit);
                if (toclevel != Layout::NOT_IN_TOC && toclevel >= min_toclevel) 
{
                        // insert this into the table of contents
@@ -895,6 +920,31 @@ void InsetText::iterateForToc(DocIterator const & cdit, 
bool output_active,
 }
 
 
+pit_type InsetText::openAddToTocForParagraph(pit_type pit,
+                                             DocIterator const & dit,
+                                             bool output_active) const
+{
+       Paragraph const & par = paragraphs()[pit];
+       TocBuilder & b = buffer().tocBackend().builder(par.layout().tocType());
+       docstring const label = par.labelString();
+       b.pushItem(dit, label + (label.empty() ? "" : " "), output_active);
+       return text().lastInSequence(pit);
+}
+
+
+void InsetText::closeAddToTocForParagraph(pit_type start, pit_type end) const
+{
+       Paragraph const & par = paragraphs()[start];
+       TocBuilder & b = buffer().tocBackend().builder(par.layout().tocType());
+       if (par.layout().isTocCaption()) {
+               docstring str;
+               text().forOutliner(str, TOC_ENTRY_LENGTH, start, end);
+               b.argumentItem(str);
+       }
+       b.pop();
+}
+
+
 bool InsetText::notifyCursorLeaves(Cursor const & old, Cursor & cur)
 {
        if (buffer().isClean())
diff --git a/src/insets/InsetText.h b/src/insets/InsetText.h
index 5bc7c52..8c647fb 100644
--- a/src/insets/InsetText.h
+++ b/src/insets/InsetText.h
@@ -223,6 +223,13 @@ protected:
        void iterateForToc(DocIterator const & cdit, bool output_active,
                                           UpdateType utype) const;
 private:
+       /// Open the toc item for paragraph pit. Returns the paragraph index 
where
+       /// it should end.
+       pit_type openAddToTocForParagraph(pit_type pit,
+                                         DocIterator const & dit,
+                                         bool output_active) const;
+       /// Close a toc item opened in start and closed in end
+       void closeAddToTocForParagraph(pit_type start, pit_type end) const;
        ///
        bool drawFrame_;
        ///

Reply via email to