Implement AddToToc for paragraph layouts

Enables table of Theorems & Definitions
This commit is contained in:
Guillaume Munch 2017-01-08 21:57:02 +01:00
parent d6b1dc4724
commit 68109443f3
9 changed files with 122 additions and 25 deletions

View File

@ -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;

View File

@ -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 &,

View File

@ -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);
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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(){}

View File

@ -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()) {

View File

@ -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())

View File

@ -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_;
///