PassThruChars @|!
End
+InsetLayout IndexMacro:see
+ LabelString See
+ Decoration classic
+ Font
+ Size Small
+ EndFont
+ LabelFont
+ Color indexlabel
+ Size Small
+ EndFont
+ MultiPar false
+ CustomPars false
+ ForcePlain true
+End
+
+InsetLayout IndexMacro:seealso
+ CopyStyle IndexMacro:see
+ LabelString "See also"
+End
+
+InsetLayout IndexMacro:sortkey
+ CopyStyle IndexMacro:see
+ LabelString "Sort as"
+End
+
+InsetLayout IndexMacro:subindex
+ CopyStyle IndexMacro:see
+ LabelString "Subindex"
+End
+
InsetLayout Box
LabelFont
Color foreground
Menu "context-index"
IndicesContext
End
+
+ Menu "context-edit-index"
+ OptItem "Insert Subentry|b" "indexmacro-insert subindex"
+ OptItem "Insert Sortkey|k" "indexmacro-insert sortkey"
+ OptItem "Insert See Reference|e" "indexmacro-insert see"
+ OptItem "Insert See also Reference|a" "indexmacro-insert seealso"
+ End
+
+#
+# IndexMacro context menu
+#
+
+ Menu "context-indexmacro"
+ OptItem "See|e" "inset-modify changetype see"
+ OptItem "See also|a" "inset-modify changetype seealso"
+ End
+
#
# Index Lists context menu
Item "Label...|L" "label-insert"
Captions
Indices
+ OptSubmenu "Index Properties" "index_properties"
Item "Nomenclature Entry...|y" "nomencl-insert"
Separator
Item "Table...|T" "tabular-insert"
Item "Double Frame|u" "box-insert Doublebox"
End
+ Menu "index_properties"
+ OptItem "Subentry|b" "indexmacro-insert subindex"
+ OptItem "Sortkey|k" "indexmacro-insert sortkey"
+ OptItem "See|e" "indexmacro-insert see"
+ OptItem "See also|a" "indexmacro-insert seealso"
+ End
+
Menu "insert_note"
Item "LyX Note|N" "note-insert Note"
Item "Comment|C" "note-insert Comment"
LFUN_FINISHED_DOWN, // lasgouttes 20210629
LFUN_FINISHED_UP, // lasgouttes 20210629
LFUN_BRANCH_SYNC_ALL, // sanda 20220415
+ LFUN_INDEXMACRO_INSERT, // spitz 20220220
+ // 395
LFUN_LASTACTION // end of the table
};
*/
{ LFUN_IN_MATHMACROTEMPLATE, "in-mathmacrotemplate", Noop, Math },
+/*!
+ * \var lyx::FuncCode lyx::LFUN_INDEXMACRO_INSERT
+ * \li Action: Inserts special Index macros into the document.
+ * \li Syntax: indexmacro-insert <type>
+ * \li Params: <type>: see, seealso, subindex, sortkey.
+ * \li Origin: spitz, 20 Feb 2022
+ * \endvar
+ */
+ { LFUN_INDEXMACRO_INSERT, "indexmacro-insert", Noop, Edit },
+
/*!
* \var lyx::FuncCode lyx::LFUN_IPAMACRO_INSERT
insets/InsetHyperlink.cpp \
insets/InsetInclude.cpp \
insets/InsetIndex.cpp \
+ insets/InsetIndexMacro.cpp \
insets/InsetInfo.cpp \
insets/InsetIPA.cpp \
insets/InsetIPAMacro.cpp \
#include "insets/InsetGraphics.h"
#include "insets/InsetGraphicsParams.h"
#include "insets/InsetInfo.h"
+#include "insets/InsetIndexMacro.h"
#include "insets/InsetIPAMacro.h"
#include "insets/InsetNewline.h"
#include "insets/InsetQuotes.h"
case LFUN_BRANCH_INSERT:
case LFUN_PHANTOM_INSERT:
case LFUN_ERT_INSERT:
+ case LFUN_INDEXMACRO_INSERT:
case LFUN_LISTING_INSERT:
case LFUN_MARGINALNOTE_INSERT:
case LFUN_ARGUMENT_INSERT:
}
code = HYPERLINK_CODE;
break;
+ case LFUN_INDEXMACRO_INSERT: {
+ string const arg = cmd.getArg(0);
+ if (arg == "sortkey")
+ code = INDEXMACRO_SORTKEY_CODE;
+ else
+ code = INDEXMACRO_CODE;
+ break;
+ }
case LFUN_IPAMACRO_INSERT: {
string const arg = cmd.getArg(0);
if (arg == "deco")
#include "insets/InsetHyperlink.h"
#include "insets/InsetInclude.h"
#include "insets/InsetIndex.h"
+#include "insets/InsetIndexMacro.cpp"
#include "insets/InsetInfo.h"
#include "insets/InsetIPA.h"
#include "insets/InsetIPAMacro.h"
return new InsetIPADeco(buf, arg2);
}
+ case LFUN_INDEXMACRO_INSERT: {
+ string const arg = cmd.getArg(0);
+ if (arg != "see" && arg != "seealso"
+ && arg != "subindex" && arg != "sortkey") {
+ LYXERR0("LFUN_IPAMACRO_INSERT: wrong argument");
+ return nullptr;
+ }
+ return new InsetIndexMacro(buf, arg);
+ }
+
case LFUN_ERT_INSERT:
return new InsetERT(buf);
inset.reset(new InsetCaption(buf, s));
} else if (tmptok == "Index") {
inset.reset(new InsetIndex(buf, InsetIndexParams()));
+ } else if (tmptok == "IndexMacro") {
+ string s = lex.getString();
+ inset.reset(new InsetIndexMacro(buf, s));
} else if (tmptok == "FloatList") {
inset.reset(new InsetFloatList(buf));
} else if (tmptok == "Info") {
#include "BufferParams.h"
#include "FuncRequest.h"
#include "IndicesList.h"
+#include "insets/InsetIndex.h"
#include <QPushButton>
this, SLOT(slotButtonBox(QAbstractButton *)));
connect(indicesCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
+ rangeCO->addItem(qt_("None"), InsetIndexParams::None);
+ rangeCO->addItem(qt_("Start"), InsetIndexParams::Start);
+ rangeCO->addItem(qt_("End"), InsetIndexParams::End);
+ connect(rangeCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
+
+ pageFormatCO->addItem(qt_("Default"), toqstr("default"));
+ pageFormatCO->addItem(qt_("Bold"), toqstr("textbf"));
+ pageFormatCO->addItem(qt_("Italic"), toqstr("textit"));
+ pageFormatCO->addItem(qt_("Emphasized"), toqstr("emph"));
+ pageFormatCO->addItem(qt_("Custom"), toqstr("custom"));
+ connect(pageFormatCO, SIGNAL(activated(int)), this, SLOT(pageFormatChanged(int)));
+
bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
}
+void GuiIndex::pageFormatChanged(int i)
+{
+ QString const pf = pageFormatCO->itemData(i).toString();
+ pageFormatLE->setEnabled(pf == "custom");
+ change_adaptor();
+}
+
+
void GuiIndex::updateContents()
{
typedef IndicesList::const_iterator const_iterator;
- IndicesList const & indiceslist = buffer().params().indiceslist();
+ BufferParams const & bp = buffer().masterBuffer()->params();
+ indicesGB->setEnabled(bp.use_indices);
+
+ QString const pf = pageFormatCO->itemData(
+ pageFormatCO->currentIndex()).toString();
+ pageFormatLE->setEnabled(pf == "custom");
+
+ IndicesList const & indiceslist = bp.indiceslist();
docstring const cur_index = params_.index;
indicesCO->clear();
indicesCO->addItem(toqstr(it->index()),
QVariant(toqstr(it->shortcut())));
- int const pos = indicesCO->findData(toqstr(cur_index));
+ int pos = indicesCO->findData(toqstr(cur_index));
indicesCO->setCurrentIndex(pos);
+
+ pos = pageFormatCO->findData(toqstr(params_.pagefmt));
+ if (pos == -1) {
+ pos = pageFormatCO->findData("custom");
+ pageFormatLE->setText(toqstr(params_.pagefmt));
+ } else
+ pageFormatLE->clear();
+ pageFormatCO->setCurrentIndex(pos);
+
+ pos = rangeCO->findData(params_.range);
+ rangeCO->setCurrentIndex(pos);
}
{
QString const index = indicesCO->itemData(
indicesCO->currentIndex()).toString();
+ int const range = rangeCO->itemData(
+ rangeCO->currentIndex()).toInt();
+ QString const pagefmt = pageFormatCO->itemData(
+ pageFormatCO->currentIndex()).toString();
params_.index = qstring_to_ucs4(index);
+ params_.range = InsetIndexParams::PageRange(range);
+ params_.pagefmt = (pagefmt == "custom")
+ ? fromqstr(pageFormatLE->text())
+ : fromqstr(pagefmt);
}
private Q_SLOTS:
void change_adaptor();
+ void pageFormatChanged(int);
private:
/// Apply changes
<rect>
<x>0</x>
<y>0</y>
- <width>262</width>
- <height>121</height>
+ <width>384</width>
+ <height>288</height>
</rect>
</property>
<property name="windowTitle">
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
- <layout class="QGridLayout" name="gridLayout">
+ <layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
+ <widget class="QGroupBox" name="indicesGB">
+ <property name="title">
+ <string>Available I&ndexes</string>
</property>
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <widget class="QLabel" name="indicesLA">
- <property name="text">
- <string>Available I&ndexes:</string>
- </property>
- <property name="buddy">
- <cstring>indicesCO</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="indicesCO">
- <property name="toolTip">
- <string>Select the index this entry should be listed in.</string>
- </property>
- </widget>
- </item>
- </layout>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QComboBox" name="indicesCO">
+ <property name="toolTip">
+ <string>Select the index this entry should be listed in.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
</item>
<item row="1" column="0">
+ <widget class="QGroupBox" name="paginationGB">
+ <property name="title">
+ <string>&Pagination</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="rangeLA">
+ <property name="text">
+ <string>Page &Range:</string>
+ </property>
+ <property name="buddy">
+ <cstring>rangeCO</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="rangeCO">
+ <property name="toolTip">
+ <string>If the entry spans multiple pages, you can start or end the range here</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>112</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="pageFormatLA">
+ <property name="text">
+ <string>&Format:</string>
+ </property>
+ <property name="buddy">
+ <cstring>pageFormatCO</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="pageFormatCO">
+ <property name="toolTip">
+ <string>Customize the format of the page number here. Note that the format is not used with "See" and "See also" references.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QLineEdit" name="pageFormatLE">
+ <property name="toolTip">
+ <string>Enter custom command here (without leading backslash).</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
+ <item row="2" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
<tabstops>
///
COUNTER_CODE,
///
+ INDEXMACRO_CODE, // 110
+ ///
+ INDEXMACRO_SORTKEY_CODE,
+ ///
INSET_CODE_SIZE
};
#include <config.h>
#include "InsetIndex.h"
+#include "InsetIndexMacro.h"
#include "Buffer.h"
#include "BufferParams.h"
#include "Cursor.h"
#include "DispatchResult.h"
#include "Encoding.h"
+#include "ErrorList.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
#include "IndicesList.h"
+#include "InsetList.h"
#include "Language.h"
+#include "LaTeX.h"
#include "LaTeXFeatures.h"
#include "Lexer.h"
#include "output_latex.h"
#include "support/FileName.h"
#include "support/gettext.h"
#include "support/lstrings.h"
+#include "support/Translator.h"
#include "frontends/alert.h"
namespace lyx {
+namespace {
+
+typedef Translator<string, InsetIndexParams::PageRange> PageRangeTranslator;
+typedef Translator<docstring, InsetIndexParams::PageRange> PageRangeTranslatorLoc;
+
+PageRangeTranslator const init_insetindexpagerangetranslator()
+{
+ PageRangeTranslator translator("none", InsetIndexParams::None);
+ translator.addPair("start", InsetIndexParams::Start);
+ translator.addPair("end", InsetIndexParams::End);
+ return translator;
+}
+
+PageRangeTranslator const init_insetindexpagerangetranslator_latex()
+{
+ PageRangeTranslator translator("", InsetIndexParams::None);
+ translator.addPair("(", InsetIndexParams::Start);
+ translator.addPair(")", InsetIndexParams::End);
+ return translator;
+}
+
+
+PageRangeTranslatorLoc const init_insetindexpagerangetranslator_loc()
+{
+ PageRangeTranslatorLoc translator(docstring(), InsetIndexParams::None);
+ translator.addPair(_("Starts page range"), InsetIndexParams::Start);
+ translator.addPair(_("Ends page range"), InsetIndexParams::End);
+ return translator;
+}
+
+
+PageRangeTranslator const & insetindexpagerangetranslator()
+{
+ static PageRangeTranslator const prtranslator =
+ init_insetindexpagerangetranslator();
+ return prtranslator;
+}
+
+
+PageRangeTranslatorLoc const & insetindexpagerangetranslator_loc()
+{
+ static PageRangeTranslatorLoc const translator =
+ init_insetindexpagerangetranslator_loc();
+ return translator;
+}
+
+
+PageRangeTranslator const & insetindexpagerangetranslator_latex()
+{
+ static PageRangeTranslator const lttranslator =
+ init_insetindexpagerangetranslator_latex();
+ return lttranslator;
+}
+
+} // namespace anon
+
/////////////////////////////////////////////////////////////////////
//
// InsetIndex
InsetIndex::InsetIndex(Buffer * buf, InsetIndexParams const & params)
- : InsetCollapsible(buf), params_(params)
+ : InsetCollapsible(buf), params_(params)
{}
return;
}
- // For the sorting key, we use the plaintext version
- odocstringstream ourplain;
- InsetText::plaintext(ourplain, runparams);
-
- // These are the LaTeX and plaintext representations
- docstring latexstr = ourlatex.str();
- docstring plainstr = ourplain.str();
-
- // This will get what follows | if anything does,
- // the command (e.g., see, textbf) for pagination
- // formatting
- docstring cmd;
-
- // Check for the | separator to strip the cmd.
- // This goes wrong on an escaped "|", but as the escape
- // character can be changed in style files, we cannot
- // prevent that.
- size_t pos = latexstr.find(from_ascii("|"));
- if (pos != docstring::npos) {
- // Put the bit after "|" into cmd...
- cmd = latexstr.substr(pos + 1);
- // ...and erase that stuff from latexstr
- latexstr = latexstr.erase(pos);
- // ...as well as from plainstr
- size_t ppos = plainstr.find(from_ascii("|"));
- if (ppos < plainstr.size())
- plainstr.erase(ppos);
- else
- LYXERR0("The `|' separator was not found in the plaintext version!");
- }
+ if (hasSortKey()) {
+ getSortkey(os, runparams);
+ os << "@";
+ os << ourlatex.str();
+ getSubentries(os, runparams);
+ if (hasSeeRef()) {
+ os << "|";
+ os << insetindexpagerangetranslator_latex().find(params_.range);
+ getSeeRefs(os, runparams);
+ }
+ } else {
+ // We check whether we need a sort key.
+ // If so, we use the plaintext version
+ odocstringstream ourplain;
+ InsetText::plaintext(ourplain, runparams);
+
+ // These are the LaTeX and plaintext representations
+ docstring latexstr = ourlatex.str();
+ docstring plainstr = ourplain.str();
+
+ // This will get what follows | if anything does,
+ // the command (e.g., see, textbf) for pagination
+ // formatting
+ docstring cmd;
+
+ if (hasSeeRef()) {
+ odocstringstream seeref;
+ otexstream otsee(seeref);
+ getSeeRefs(otsee, runparams);
+ cmd = seeref.str();
+ } else if (!params_.pagefmt.empty() && params_.pagefmt != "default") {
+ cmd = from_utf8(params_.pagefmt);
+ } else {
+ // Check for the | separator to strip the cmd.
+ // This goes wrong on an escaped "|", but as the escape
+ // character can be changed in style files, we cannot
+ // prevent that.
+ size_t pos = latexstr.find(from_ascii("|"));
+ if (pos != docstring::npos) {
+ // Put the bit after "|" into cmd...
+ cmd = latexstr.substr(pos + 1);
+ // ...and erase that stuff from latexstr
+ latexstr = latexstr.erase(pos);
+ // ...as well as from plainstr
+ size_t ppos = plainstr.find(from_ascii("|"));
+ if (ppos < plainstr.size())
+ plainstr.erase(ppos);
+ else
+ LYXERR0("The `|' separator was not found in the plaintext version!");
+ }
+ }
- // Separate the entries and subentries, i.e., split on "!".
- // This goes wrong on an escaped "!", but as the escape
- // character can be changed in style files, we cannot
- // prevent that.
- std::vector<docstring> const levels =
- getVectorFromString(latexstr, from_ascii("!"), true);
- std::vector<docstring> const levels_plain =
- getVectorFromString(plainstr, from_ascii("!"), true);
-
- vector<docstring>::const_iterator it = levels.begin();
- vector<docstring>::const_iterator end = levels.end();
- vector<docstring>::const_iterator it2 = levels_plain.begin();
- bool first = true;
- for (; it != end; ++it) {
- // The separator needs to be put back when
- // writing the levels, except for the first level
- if (!first)
- os << '!';
- else
- first = false;
-
- // Now here comes the reason for this whole procedure:
- // We try to correctly sort macros and formatted strings.
- // If we find a command, prepend a plain text
- // version of the content to get sorting right,
- // e.g. \index{LyX@\LyX}, \index{text@\textbf{text}}.
- // We do this on all levels.
- // We don't do it if the level already contains a '@', though.
- if (contains(*it, '\\') && !contains(*it, '@')) {
- // Plaintext might return nothing (e.g. for ERTs).
- // In that case, we use LaTeX.
- docstring const spart =
- (it2 < levels_plain.end() && !(*it2).empty())
- ? *it2 : *it;
- // Now we need to validate that all characters in
- // the sorting part are representable in the current
- // encoding. If not try the LaTeX macro which might
- // or might not be a good choice, and issue a warning.
- pair<docstring, docstring> spart_latexed =
- runparams.encoding->latexString(spart, runparams.dryrun);
- if (!spart_latexed.second.empty())
- LYXERR0("Uncodable character in index entry. Sorting might be wrong!");
- if (spart != spart_latexed.first && !runparams.dryrun) {
- // FIXME: warning should be passed to the error dialog
- frontend::Alert::warning(_("Index sorting failed"),
- bformat(_("LyX's automatic index sorting algorithm faced\n"
- "problems with the entry '%1$s'.\n"
- "Please specify the sorting of this entry manually, as\n"
- "explained in the User Guide."), spart));
+ odocstringstream subentries;
+ otexstream otsub(subentries);
+ getSubentries(otsub, runparams);
+ if (subentries.str().empty()) {
+ // Separate the entries and subentries, i.e., split on "!".
+ // This goes wrong on an escaped "!", but as the escape
+ // character can be changed in style files, we cannot
+ // prevent that.
+ std::vector<docstring> const levels =
+ getVectorFromString(latexstr, from_ascii("!"), true);
+ std::vector<docstring> const levels_plain =
+ getVectorFromString(plainstr, from_ascii("!"), true);
+
+ vector<docstring>::const_iterator it = levels.begin();
+ vector<docstring>::const_iterator end = levels.end();
+ vector<docstring>::const_iterator it2 = levels_plain.begin();
+ bool first = true;
+ for (; it != end; ++it) {
+ // The separator needs to be put back when
+ // writing the levels, except for the first level
+ if (!first)
+ os << '!';
+ else
+ first = false;
+
+ // Now here comes the reason for this whole procedure:
+ // We try to correctly sort macros and formatted strings.
+ // If we find a command, prepend a plain text
+ // version of the content to get sorting right,
+ // e.g. \index{LyX@\LyX}, \index{text@\textbf{text}}.
+ // We do this on all levels.
+ // We don't do it if the level already contains a '@', though.
+ // Plaintext might return nothing (e.g. for ERTs).
+ // In that case, we use LaTeX.
+ docstring const spart = (levels_plain.empty() || (*it2).empty()) ? *it : *it2;
+ processLatexSorting(os, runparams, *it, spart);
+ if (it2 < levels_plain.end())
+ ++it2;
}
- // Remove remaining \'s from the sort key
- docstring ppart = subst(spart_latexed.first, from_ascii("\\"), docstring());
- // Plain quotes need to be escaped, however (#10649), as this
- // is the default escape character
- ppart = subst(ppart, from_ascii("\""), from_ascii("\\\""));
-
- // Now insert the sortkey, separated by '@'.
- os << ppart;
- os << '@';
+ } else {
+ processLatexSorting(os, runparams, latexstr, plainstr);
+ os << subentries.str();
+ }
+
+ // At last, re-insert the command, separated by "|"
+ if (!cmd.empty()) {
+ os << "|"
+ << insetindexpagerangetranslator_latex().find(params_.range)
+ << cmd;
}
- // Insert the actual level text
- docstring const tpart = *it;
- os << tpart;
- if (it2 < levels_plain.end())
- ++it2;
- }
- // At last, re-insert the command, separated by "|"
- if (!cmd.empty()) {
- os << "|" << cmd;
}
os << '}';
}
+void InsetIndex::processLatexSorting(otexstream & os, OutputParams const & runparams,
+ docstring const latex, docstring const spart) const
+{
+ if (contains(latex, '\\') && !contains(latex, '@')) {
+ // Now we need to validate that all characters in
+ // the sorting part are representable in the current
+ // encoding. If not try the LaTeX macro which might
+ // or might not be a good choice, and issue a warning.
+ pair<docstring, docstring> spart_latexed =
+ runparams.encoding->latexString(spart, runparams.dryrun);
+ if (!spart_latexed.second.empty())
+ LYXERR0("Uncodable character in index entry. Sorting might be wrong!");
+ if (spart != spart_latexed.first && !runparams.dryrun) {
+ TeXErrors terr;
+ ErrorList & errorList = buffer().errorList("Export");
+ docstring const s = bformat(_("LyX's automatic index sorting algorithm faced "
+ "problems with the entry '%1$s'.\n"
+ "Please specify the sorting of this entry manually, as "
+ "explained in the User Guide."), spart);
+ Paragraph const & par = buffer().paragraphs().front();
+ errorList.push_back(ErrorItem(_("Index sorting failed"), s,
+ {par.id(), 0}, {par.id(), -1}));
+ buffer().bufferErrors(terr, errorList);
+ }
+ // Remove remaining \'s from the sort key
+ docstring ppart = subst(spart_latexed.first, from_ascii("\\"), docstring());
+ // Plain quotes need to be escaped, however (#10649), as this
+ // is the default escape character
+ ppart = subst(ppart, from_ascii("\""), from_ascii("\\\""));
+
+ // Now insert the sortkey, separated by '@'.
+ os << ppart;
+ os << '@';
+ }
+ // Insert the actual level text
+ os << latex;
+}
+
+
void InsetIndex::docbook(XMLStream & xs, OutputParams const & runparams) const
{
// Get the content of the inset as LaTeX, as some things may be encoded as ERT (like {}).
InsetIndex::string2params(to_utf8(cmd.argument()), params);
cur.recordUndoInset(this);
params_.index = params.index;
+ params_.range = params.range;
+ params_.pagefmt = params.pagefmt;
// what we really want here is a TOC update, but that means
// a full buffer update
cur.forceBufferUpdate();
flag.setEnabled(realbuffer.params().use_indices);
return true;
}
+
+ case LFUN_INDEXMACRO_INSERT:
+ return macrosPossible(cmd.getArg(0));
default:
return InsetCollapsible::getStatus(cur, cmd, flag);
}
+void InsetIndex::getSortkey(otexstream & os, OutputParams const & runparams) const
+{
+ Paragraph const & par = paragraphs().front();
+ InsetList::const_iterator it = par.insetList().begin();
+ for (; it != par.insetList().end(); ++it) {
+ Inset & inset = *it->inset;
+ if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE) {
+ InsetIndexMacro const & iim =
+ static_cast<InsetIndexMacro const &>(inset);
+ iim.getLatex(os, runparams);
+ return;
+ }
+ }
+}
+
+
+void InsetIndex::getSubentries(otexstream & os, OutputParams const & runparams) const
+{
+ Paragraph const & par = paragraphs().front();
+ InsetList::const_iterator it = par.insetList().begin();
+ int i = 0;
+ for (; it != par.insetList().end(); ++it) {
+ Inset & inset = *it->inset;
+ if (inset.lyxCode() == INDEXMACRO_CODE) {
+ InsetIndexMacro const & iim =
+ static_cast<InsetIndexMacro const &>(inset);
+ if (iim.params().type == InsetIndexMacroParams::Subindex) {
+ ++i;
+ if (i > 2)
+ return;
+ os << "!";
+ iim.getLatex(os, runparams);
+ }
+ }
+ }
+}
+
+
+void InsetIndex::getSeeRefs(otexstream & os, OutputParams const & runparams) const
+{
+ Paragraph const & par = paragraphs().front();
+ InsetList::const_iterator it = par.insetList().begin();
+ for (; it != par.insetList().end(); ++it) {
+ Inset & inset = *it->inset;
+ if (inset.lyxCode() == INDEXMACRO_CODE) {
+ InsetIndexMacro const & iim =
+ static_cast<InsetIndexMacro const &>(inset);
+ if (iim.params().type == InsetIndexMacroParams::See
+ || iim.params().type == InsetIndexMacroParams::Seealso) {
+ iim.getLatex(os, runparams);
+ return;
+ }
+ }
+ }
+}
+
+
+bool InsetIndex::hasSeeRef() const
+{
+ Paragraph const & par = paragraphs().front();
+ InsetList::const_iterator it = par.insetList().begin();
+ for (; it != par.insetList().end(); ++it) {
+ Inset & inset = *it->inset;
+ if (inset.lyxCode() == INDEXMACRO_CODE) {
+ InsetIndexMacro const & iim =
+ static_cast<InsetIndexMacro const &>(inset);
+ if (iim.params().type == InsetIndexMacroParams::See
+ || iim.params().type == InsetIndexMacroParams::Seealso)
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool InsetIndex::hasSortKey() const
+{
+ Paragraph const & par = paragraphs().front();
+ InsetList::const_iterator it = par.insetList().begin();
+ for (; it != par.insetList().end(); ++it) {
+ Inset & inset = *it->inset;
+ if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE)
+ return true;
+ }
+ return false;
+}
+
+
+bool InsetIndex::macrosPossible(string const type) const
+{
+ if (type != "see" && type != "seealso"
+ && type != "sortkey" && type != "subindex")
+ return false;
+
+ Paragraph const & par = paragraphs().front();
+ InsetList::const_iterator it = par.insetList().begin();
+ int subidxs = 0;
+ for (; it != par.insetList().end(); ++it) {
+ Inset & inset = *it->inset;
+ if (type == "sortkey" && inset.lyxCode() == INDEXMACRO_SORTKEY_CODE)
+ return false;
+ if (inset.lyxCode() == INDEXMACRO_CODE) {
+ InsetIndexMacro const & iim = static_cast<InsetIndexMacro const &>(inset);
+ if ((type == "see" || type == "seealso")
+ && (iim.params().type == InsetIndexMacroParams::See
+ || iim.params().type == InsetIndexMacroParams::Seealso))
+ return false;
+ if (type == "subindex"
+ && iim.params().type == InsetIndexMacroParams::Subindex) {
+ ++subidxs;
+ if (subidxs > 1)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
ColorCode InsetIndex::labelColor() const
{
if (params_.index.empty() || params_.index == from_ascii("idx"))
tip += ")";
}
tip += ": ";
- return toolTipText(tip);
+ docstring res = toolTipText(tip);
+ if (!insetindexpagerangetranslator_loc().find(params_.range).empty())
+ res += "\n" + insetindexpagerangetranslator_loc().find(params_.range);
+ if (!params_.pagefmt.empty() && params_.pagefmt != "default") {
+ res += "\n" + _("Pagination format:") + " ";
+ if (params_.pagefmt == "textbf")
+ res += _("bold");
+ else if (params_.pagefmt == "textit")
+ res += _("italic");
+ else if (params_.pagefmt == "emph")
+ res += _("emphasized");
+ else
+ res += from_utf8(params_.pagefmt);
+ }
+ return res;
}
label += ")";
}
+ docstring res;
if (!il.contentaslabel() || geometry(bv) != ButtonOnly)
- return label;
- return getNewLabel(label);
+ res = label;
+ else
+ res = getNewLabel(label);
+ if (!insetindexpagerangetranslator_latex().find(params_.range).empty())
+ res += " " + from_ascii(insetindexpagerangetranslator_latex().find(params_.range));
+ return res;
}
}
+string InsetIndex::contextMenu(BufferView const & bv, int x, int y) const
+{
+ // We override the implementation of InsetCollapsible,
+ // because we have eytra entries.
+ string owncm = "context-edit-index;";
+ return owncm + InsetCollapsible::contextMenu(bv, x, y);
+}
+
+
bool InsetIndex::hasSettings() const
{
- return buffer().masterBuffer()->params().use_indices;
+ return true;
}
+bool InsetIndex::insetAllowed(InsetCode code) const
+{
+ switch (code) {
+ case INDEXMACRO_CODE:
+ case INDEXMACRO_SORTKEY_CODE:
+ return true;
+ case INDEX_CODE:
+ return false;
+ default:
+ return InsetCollapsible::insetAllowed(code);
+ }
+}
/////////////////////////////////////////////////////////////////////
else
os << "idx";
os << '\n';
+ os << "range "
+ << insetindexpagerangetranslator().find(range)
+ << '\n';
+ os << "pageformat "
+ << pagefmt
+ << '\n';
}
index = lex.getDocString();
else
index = from_ascii("idx");
+ if (lex.checkFor("range")) {
+ string st = lex.getString();
+ if (lex.eatLine()) {
+ st = lex.getString();
+ range = insetindexpagerangetranslator().find(lex.getString());
+ }
+ }
+ if (lex.checkFor("pageformat") && lex.eatLine()) {
+ pagefmt = lex.getString();
+ }
}
class InsetIndexParams {
public:
+ enum PageRange {
+ None,
+ Start,
+ End
+ };
///
explicit InsetIndexParams(docstring const & b = docstring())
- : index(b) {}
+ : index(b), range(None), pagefmt("default") {}
///
void write(std::ostream & os) const;
///
void read(Lexer & lex);
///
docstring index;
+ ///
+ PageRange range;
+ ///
+ std::string pagefmt;
};
///
void latex(otexstream &, OutputParams const &) const override;
///
+ void processLatexSorting(otexstream &, OutputParams const &,
+ docstring const, docstring const) const;
+ ///
bool showInsetDialog(BufferView *) const override;
///
bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const override;
/// Updates needed features for this inset.
void validate(LaTeXFeatures & features) const override;
///
+ void getSortkey(otexstream &, OutputParams const &) const;
+ ///
+ void getSubentries(otexstream &, OutputParams const &) const;
+ ///
+ void getSeeRefs(otexstream &, OutputParams const &) const;
+ ///
+ bool hasSeeRef() const;
+ ///
+ bool hasSortKey() const;
+ ///
+ bool macrosPossible(std::string const type) const;
+ ///
std::string contextMenuName() const override;
///
+ std::string contextMenu(BufferView const &, int, int) const override;
+ ///
Inset * clone() const override { return new InsetIndex(*this); }
/// Is the content of this inset part of the immediate text sequence?
bool isPartOfTextSequence() const override { return false; }
+ ///
+ bool insetAllowed(InsetCode code) const override;
///
friend class InsetIndexParams;
--- /dev/null
+/**
+ * \file InsetIndexMacro.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Jürgen Spitzmüller
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "InsetIndexMacro.h"
+
+#include "Buffer.h"
+#include "BufferParams.h"
+#include "Cursor.h"
+#include "Dimension.h"
+#include "Encoding.h"
+#include "ErrorList.h"
+#include "FontInfo.h"
+#include "FuncRequest.h"
+#include "FuncStatus.h"
+#include "InsetLayout.h"
+#include "InsetList.h"
+#include "LaTeX.h"
+#include "LaTeXFeatures.h"
+#include "Lexer.h"
+#include "MetricsInfo.h"
+#include "xml.h"
+#include "texstream.h"
+
+#include "frontends/alert.h"
+
+#include "support/debug.h"
+#include "support/docstream.h"
+#include "support/gettext.h"
+#include "support/lstrings.h"
+#include "support/Translator.h"
+
+using namespace std;
+using namespace lyx::support;
+
+namespace lyx {
+
+namespace {
+
+typedef Translator<string, InsetIndexMacroParams::Type> InsetIndexMacroTranslator;
+typedef Translator<docstring, InsetIndexMacroParams::Type> InsetIndexMacroTranslatorLoc;
+
+InsetIndexMacroTranslator const init_insetindexmacrotranslator()
+{
+ InsetIndexMacroTranslator translator("see", InsetIndexMacroParams::See);
+ translator.addPair("seealso", InsetIndexMacroParams::Seealso);
+ translator.addPair("subindex", InsetIndexMacroParams::Subindex);
+ translator.addPair("sortkey", InsetIndexMacroParams::Sortkey);
+ return translator;
+}
+
+
+InsetIndexMacroTranslatorLoc const init_insetindexmacrotranslator_loc()
+{
+ InsetIndexMacroTranslatorLoc translator(_("See"), InsetIndexMacroParams::See);
+ translator.addPair(_("See also"), InsetIndexMacroParams::Seealso);
+ translator.addPair(_("Subindex"), InsetIndexMacroParams::Subindex);
+ translator.addPair(_("Sort as"), InsetIndexMacroParams::Sortkey);
+ return translator;
+}
+
+
+InsetIndexMacroTranslator const & insetindexmacrotranslator()
+{
+ static InsetIndexMacroTranslator const macrotranslator =
+ init_insetindexmacrotranslator();
+ return macrotranslator;
+}
+
+
+InsetIndexMacroTranslatorLoc const & insetindexmacrotranslator_loc()
+{
+ static InsetIndexMacroTranslatorLoc const translator =
+ init_insetindexmacrotranslator_loc();
+ return translator;
+}
+
+} // namespace
+
+
+InsetIndexMacroParams::InsetIndexMacroParams()
+ : type(See)
+{}
+
+
+void InsetIndexMacroParams::write(ostream & os) const
+{
+ string const label = insetindexmacrotranslator().find(type);
+ os << "IndexMacro " << label << "\n";
+}
+
+
+void InsetIndexMacroParams::read(Lexer & lex)
+{
+ string label;
+ lex >> label;
+ if (lex)
+ type = insetindexmacrotranslator().find(label);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// InsetIndexMacro
+//
+/////////////////////////////////////////////////////////////////////
+
+InsetIndexMacro::InsetIndexMacro(Buffer * buf, string const & label)
+ : InsetCollapsible(buf)
+{
+ setDrawFrame(true);
+ setFrameColor(Color_insetframe);
+ params_.type = insetindexmacrotranslator().find(label);
+}
+
+
+InsetIndexMacro::~InsetIndexMacro()
+{}
+
+
+docstring InsetIndexMacro::layoutName() const
+{
+ return from_ascii("IndexMacro:" + insetindexmacrotranslator().find(params_.type));
+}
+
+InsetCode InsetIndexMacro::lyxCode() const
+{
+ return params_.type == InsetIndexMacroParams::Sortkey
+ ? INDEXMACRO_SORTKEY_CODE
+ : INDEXMACRO_CODE;
+}
+
+
+void InsetIndexMacro::write(ostream & os) const
+{
+ params_.write(os);
+ InsetCollapsible::write(os);
+}
+
+
+void InsetIndexMacro::read(Lexer & lex)
+{
+ params_.read(lex);
+ InsetCollapsible::read(lex);
+}
+
+
+void InsetIndexMacro::getLatex(otexstream & os, OutputParams const & runparams) const
+{
+ if (params_.type == InsetIndexMacroParams::Subindex) {
+ if (hasSortKey()) {
+ getSortkey(os, runparams);
+ os << "@";
+ } else {
+ odocstringstream ourlatex;
+ otexstream ots(ourlatex);
+ InsetText::latex(ots, runparams);
+ odocstringstream ourplain;
+ InsetText::plaintext(ourplain, runparams);
+ // These are the LaTeX and plaintext representations
+ docstring latexstr = ourlatex.str();
+ docstring plainstr = ourplain.str();
+ processLatexSorting(os, runparams, latexstr, plainstr);
+ }
+ return;
+ }
+
+ if (params_.type == InsetIndexMacroParams::See)
+ os << "see{";
+ else if (params_.type == InsetIndexMacroParams::Seealso)
+ os << "seealso{";
+
+ InsetCollapsible::latex(os, runparams);
+
+ if (params_.type == InsetIndexMacroParams::See
+ || params_.type == InsetIndexMacroParams::Seealso)
+ os << "}";
+}
+
+
+int InsetIndexMacro::getPlaintext(odocstringstream & os,
+ OutputParams const & runparams, size_t max_length) const
+{
+ return InsetText::plaintext(os, runparams, max_length);
+}
+
+
+void InsetIndexMacro::getDocbook(XMLStream & xs, OutputParams const & runparams) const
+{
+ InsetText::docbook(xs, runparams);
+}
+
+
+docstring InsetIndexMacro::getXhtml(XMLStream & xs, OutputParams const & runparams) const
+{
+ return InsetText::xhtml(xs, runparams);
+}
+
+
+void InsetIndexMacro::doDispatch(Cursor & cur, FuncRequest & cmd)
+{
+ switch (cmd.action()) {
+
+ case LFUN_INSET_MODIFY: {
+ if (cmd.getArg(0) == "changetype") {
+ cur.recordUndoInset(this);
+ params_.type = insetindexmacrotranslator().find(cmd.getArg(1));
+ break;
+ }
+ InsetCollapsible::doDispatch(cur, cmd);
+ break;
+ }
+
+ default:
+ InsetCollapsible::doDispatch(cur, cmd);
+ break;
+ }
+}
+
+
+bool InsetIndexMacro::getStatus(Cursor & cur, FuncRequest const & cmd,
+ FuncStatus & flag) const
+{
+ switch (cmd.action()) {
+
+ case LFUN_INSET_MODIFY:
+ if (cmd.getArg(0) == "changetype") {
+ docstring const newtype = from_utf8(cmd.getArg(1));
+ bool const enabled = (params_.type == InsetIndexMacroParams::See
+ || params_.type == InsetIndexMacroParams::Seealso)
+ && (newtype == "see" || newtype == "seealso");
+ flag.setEnabled(enabled);
+ flag.setOnOff(
+ newtype == from_ascii(insetindexmacrotranslator().find(params_.type)));
+ return true;
+ }
+ return InsetCollapsible::getStatus(cur, cmd, flag);
+
+ default:
+ return InsetCollapsible::getStatus(cur, cmd, flag);
+ }
+}
+
+
+void InsetIndexMacro::processLatexSorting(otexstream & os, OutputParams const & runparams,
+ docstring const latex, docstring const plain) const
+{
+ if (contains(latex, '\\') && !contains(latex, '@')) {
+ // Plaintext might return nothing (e.g. for ERTs).
+ // In that case, we use LaTeX.
+ docstring const spart = (plain.empty()) ? latex : plain;
+ // Now we need to validate that all characters in
+ // the sorting part are representable in the current
+ // encoding. If not try the LaTeX macro which might
+ // or might not be a good choice, and issue a warning.
+ pair<docstring, docstring> spart_latexed =
+ runparams.encoding->latexString(spart, runparams.dryrun);
+ if (!spart_latexed.second.empty())
+ LYXERR0("Uncodable character in index entry. Sorting might be wrong!");
+ if (spart != spart_latexed.first && !runparams.dryrun) {
+ TeXErrors terr;
+ ErrorList & errorList = buffer().errorList("Export");
+ docstring const s = bformat(_("LyX's automatic index sorting algorithm faced "
+ "problems with the sub-entry '%1$s'.\n"
+ "Please specify the sorting of this entry manually, as "
+ "explained in the User Guide."), spart);
+ Paragraph const & par = buffer().paragraphs().front();
+ errorList.push_back(ErrorItem(_("Index sorting failed"), s,
+ {par.id(), 0}, {par.id(), -1}));
+ buffer().bufferErrors(terr, errorList);
+ }
+ // Remove remaining \'s from the sort key
+ docstring ppart = subst(spart_latexed.first, from_ascii("\\"), docstring());
+ // Plain quotes need to be escaped, however (#10649), as this
+ // is the default escape character
+ ppart = subst(ppart, from_ascii("\""), from_ascii("\\\""));
+
+ // Now insert the sortkey, separated by '@'.
+ os << ppart;
+ os << '@';
+ }
+ // Insert the actual level text
+ os << latex;
+}
+
+
+docstring InsetIndexMacro::toolTip(BufferView const &, int, int) const
+{
+ return insetindexmacrotranslator_loc().find(params_.type);
+}
+
+
+string InsetIndexMacro::params2string(InsetIndexMacroParams const & params)
+{
+ ostringstream data;
+ data << "IndexMacro" << ' ';
+ params.write(data);
+ return data.str();
+}
+
+
+void InsetIndexMacro::string2params(string const & in, InsetIndexMacroParams & params)
+{
+ params = InsetIndexMacroParams();
+
+ if (in.empty())
+ return;
+
+ istringstream data(in);
+ Lexer lex;
+ lex.setStream(data);
+ lex.setContext("InsetIndexMacro::string2params");
+ lex >> "IndexMacro" >> "see";
+
+ params.read(lex);
+}
+
+
+bool InsetIndexMacro::hasSortKey() const
+{
+ Paragraph const & par = paragraphs().front();
+ InsetList::const_iterator it = par.insetList().begin();
+ for (; it != par.insetList().end(); ++it) {
+ Inset & inset = *it->inset;
+ if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE)
+ return true;
+ }
+ return false;
+}
+
+
+void InsetIndexMacro::getSortkey(otexstream & os, OutputParams const & runparams) const
+{
+ Paragraph const & par = paragraphs().front();
+ InsetList::const_iterator it = par.insetList().begin();
+ for (; it != par.insetList().end(); ++it) {
+ Inset & inset = *it->inset;
+ if (inset.lyxCode() == INDEXMACRO_SORTKEY_CODE) {
+ InsetIndexMacro const & iim =
+ static_cast<InsetIndexMacro const &>(inset);
+ iim.getLatex(os, runparams);
+ return;
+ }
+ }
+}
+
+
+string InsetIndexMacro::contextMenuName() const
+{
+ return "context-indexmacro";
+}
+
+
+string InsetIndexMacro::contextMenu(BufferView const & bv, int x, int y) const
+{
+ // We override the implementation of InsetCollapsible,
+ // because we have eytra entries.
+ string owncm = "context-edit-index;";
+ return owncm + InsetCollapsible::contextMenu(bv, x, y);
+}
+
+
+bool InsetIndexMacro::insetAllowed(InsetCode code) const
+{
+ switch (code) {
+ case INDEX_CODE:
+ return false;
+ case INDEXMACRO_SORTKEY_CODE:
+ return (params_.type == InsetIndexMacroParams::Subindex
+ && !hasSortKey());
+ default:
+ return InsetCollapsible::insetAllowed(code);
+ }
+}
+
+} // namespace lyx
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file InsetIndexMacro.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Jürgen Spitzmüller
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef INSET_INSETMACRO_H
+#define INSET_INSETMACRO_H
+
+
+#include "Inset.h"
+#include "InsetCollapsible.h"
+
+
+namespace lyx {
+
+class LaTeXFeatures;
+
+class InsetIndexMacroParams
+{
+public:
+ enum Type {
+ See,
+ Seealso,
+ Subindex,
+ Sortkey
+ };
+ ///
+ InsetIndexMacroParams();
+ ///
+ void write(std::ostream & os) const;
+ ///
+ void read(Lexer & lex);
+ ///
+ Type type;
+};
+
+/////////////////////////////////////////////////////////////////////////
+//
+// InsetIndexMacro
+//
+/////////////////////////////////////////////////////////////////////////
+
+/// Used to insert index references
+class InsetIndexMacro : public InsetCollapsible
+{
+public:
+ ///
+ InsetIndexMacro(Buffer *, std::string const &);
+ ///
+ ~InsetIndexMacro();
+ ///
+ static std::string params2string(InsetIndexMacroParams const &);
+ ///
+ static void string2params(std::string const &, InsetIndexMacroParams &);
+ ///
+ InsetIndexMacroParams const & params() const { return params_; }
+ ///
+ void getLatex(otexstream &, OutputParams const &) const;
+ ///
+ int getPlaintext(odocstringstream &, OutputParams const &, size_t) const;
+ ///
+ void getDocbook(XMLStream &, OutputParams const &) const;
+private:
+ ///
+ InsetCode lyxCode() const override;
+ ///
+ docstring layoutName() const override;
+ ///
+ void write(std::ostream &) const override;
+ ///
+ void read(Lexer & lex) override;
+ ///
+ bool neverIndent() const override { return true; }
+ /// We do not output anything directly to the stream
+ void latex(otexstream &, OutputParams const &) const override {};
+ /// We do not output anything directly to the stream
+ int plaintext(odocstringstream &, OutputParams const &, size_t) const override { return 0; };
+ /// We do not output anything directly to the stream
+ void docbook(XMLStream &, OutputParams const &) const override {};
+ /// We do not output anything directly to the stream
+ docstring xhtml(XMLStream &, OutputParams const &) const override { return docstring(); };
+ ///
+ docstring getXhtml(XMLStream &, OutputParams const &) const;
+ ///
+ bool allowSpellCheck() const override { return false; }
+ ///
+ bool insetAllowed(InsetCode code) const override;
+ ///
+ bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const override;
+ ///
+ void doDispatch(Cursor & cur, FuncRequest & cmd) override;
+ ///
+ docstring toolTip(BufferView const & bv, int x, int y) const override;
+ ///
+ void processLatexSorting(otexstream &, OutputParams const &,
+ docstring const, docstring const) const;
+ ///
+ bool hasSortKey() const;
+ ///
+ void getSortkey(otexstream &, OutputParams const &) const;
+ ///
+ std::string contextMenuName() const override;
+ ///
+ std::string contextMenu(BufferView const &, int, int) const override;
+ ///
+ Inset * clone() const override { return new InsetIndexMacro(*this); }
+ /// used by the constructors
+ void init();
+ ///
+ friend class InsetIndexMacroParams;
+
+ ///
+ InsetIndexMacroParams params_;
+};
+
+
+} // namespace lyx
+
+#endif
case QUOTE_CODE:
case COUNTER_CODE:
return true;
+ // These are only allowed in index insets
+ case INDEXMACRO_CODE:
+ case INDEXMACRO_SORTKEY_CODE:
+ return false;
default:
return !isPassThru();
}
}
-Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping)
+bool Parser::hasIdxMacros(string const & c, string const & e)
+{
+ // Check for index entry separator (! or @),
+ // consider escaping via "
+ // \p e marks a terminating delimiter¸
+
+ // remember current position
+ unsigned int oldpos = pos_;
+ // skip spaces and comments
+ bool retval = false;
+ while (good()) {
+ get_token();
+ if (isParagraph()) {
+ putback();
+ break;
+ }
+ if (curr_token().cat() == catEnd)
+ break;
+ if (!e.empty() && curr_token().asInput() == e
+ && prev_token().asInput() != "\"")
+ break;
+ if (curr_token().asInput() == c
+ && prev_token().asInput() != "\"") {
+ retval = true;
+ break;
+ }
+ continue;
+ }
+ pos_ = oldpos;
+ return retval;
+}
+
+
+Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping, char e)
{
skip_spaces(true);
if (! good())
return make_pair(false, string());
- int group_level = 0;
+ int group_level = (left == '{') ? 1 : 0;
string result;
Token t = get_token();
- if (t.cat() == catComment || t.cat() == catEscape ||
- t.character() != left) {
+ if (left != char()
+ && (t.cat() == catComment || t.cat() == catEscape
+ || t.character() != left)) {
putback();
return make_pair(false, string());
} else {
while (good()) {
t = get_token();
// honor grouping
- if (left != '{' && t.cat() == catBegin) {
+ if (t.cat() == catBegin) {
++group_level;
- continue;
+ if (left != '{')
+ continue;
}
- if (left != '{' && t.cat() == catEnd) {
+ if (group_level > 0 && t.cat() == catEnd) {
--group_level;
- continue;
+ if (left != '{')
+ continue;
}
// Ignore comments
if (t.cat() == catComment) {
if (t.cat() != catEscape && t.character() == right
&& group_level == 0)
break;
+ } else if (e != char()) {
+ if (prev_token().character() != e && t.character() == right
+ && group_level == 0)
+ break;
} else {
if (t.character() == right) {
if (t.cat() == catEscape)
}
-string Parser::getArg(char left, char right, bool allow_escaping)
+string Parser::getArg(char left, char right, bool allow_escaping, char e)
{
- return getFullArg(left, right, allow_escaping).second;
+ return getFullArg(left, right, allow_escaping, e).second;
}
/// Does an optional argument follow after the current token?
bool hasOpt(std::string const & l = "[");
+ /// Does this index entry has levels?
+ bool hasIdxMacros(std::string const & c,
+ std::string const & e = std::string());
///
typedef std::pair<bool, std::string> Arg;
/*!
* Get an argument enclosed by \p left and \p right.
* If \p allow_escaping is true, a right delimiter escaped by a
* backslash does not count as delimiter, but is included in the
- * argument.
+ * argument. The \p e allows for a different escape character
+ * (used in index insets)
* \returns whether an argument was found in \p Arg.first and the
* argument in \p Arg.second. \see getArg().
*/
- Arg getFullArg(char left, char right, bool allow_escaping = true);
+ Arg getFullArg(char left, char right, bool allow_escaping = true,
+ char e = char());
/*!
* Get an argument enclosed by \p left and \p right.
* If \p allow_escaping is true, a right delimiter escaped by a
* getFullArg() if you need to know whether there was an empty
* argument or no argument at all.
*/
- std::string getArg(char left, char right, bool allow_escaping = true);
+ std::string getArg(char left, char right, bool allow_escaping = true,
+ char e = char());
/*!
* Like getOpt(), but distinguishes between a missing argument ""
* and an empty argument "[]".
std::string translate_len(std::string const &);
void parse_text(Parser & p, std::ostream & os, unsigned flags, bool outer,
- Context & context, std::string const & rdelim = "");
+ Context & context, std::string const & rdelim = "",
+ std::string const & rdelimesc = "");
void check_comment_bib(std::ostream & os, Context & context);
void fix_child_filename(std::string & name);
void parse_text_in_inset(Parser & p, std::ostream & os, unsigned flags,
bool outer, Context & context,
InsetLayout const * layout = nullptr,
- std::string const & rdelim = "");
+ std::string const & rdelim = "",
+ std::string const & rdelimesc = "");
/// Guess document language from \p p if CJK is used.
/// \p lang is used for all non-CJK contents.
void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
Context & context, InsetLayout const * layout,
- string const & rdelim)
+ string const & rdelim, string const & rdelimesc)
{
bool const forcePlainLayout =
layout ? layout->forcePlainLayout() : false;
parse_text(p, oss, FLAG_RDELIM, outer, dummy,
string(1, context.latexparam.back()));
}
- parse_text(p, os, flags, outer, newcontext, rdelim);
+ parse_text(p, os, flags, outer, newcontext, rdelim, rdelimesc);
if (layout)
output_arguments(os, p, outer, false, "post", newcontext,
layout->postcommandargs());
void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
Context const & context, string const & name,
- string const & rdelim = string())
+ string const & rdelim = string(),
+ string const & rdelimesc = string())
{
InsetLayout const * layout = 0;
DocumentClass::InsetLayouts::const_iterator it =
if (it != context.textclass.insetLayouts().end())
layout = &(it->second);
Context newcontext = context;
- parse_text_in_inset(p, os, flags, outer, newcontext, layout, rdelim);
+ parse_text_in_inset(p, os, flags, outer, newcontext, layout, rdelim, rdelimesc);
}
/// parses a paragraph snippet, useful for example for \\emph{...}
void parse_text_snippet(Parser & p, ostream & os, unsigned flags, bool outer,
- Context & context)
+ Context & context, string const & rdelim = string(),
+ string const & rdelimesc = string())
{
Context newcontext(context);
// Don't inherit the paragraph-level extra stuff
newcontext.par_extra_stuff.clear();
- parse_text(p, os, flags, outer, newcontext);
+ parse_text(p, os, flags, outer, newcontext, rdelim, rdelimesc);
// Make sure that we don't create invalid .lyx files
context.need_layout = newcontext.need_layout;
context.need_end_layout = newcontext.need_end_layout;
}
+void parse_index_entry(Parser & p, ostream & os, Context & context, string const & kind)
+{
+ // write inset header
+ begin_inset(os, "Index ");
+ os << kind;
+
+ // Parse for post argument (|...)
+ p.pushPosition();
+ string const marg = p.getArg('{', '}');
+ p.popPosition();
+ char lc = char();
+ bool inpost = false;
+ bool startrange = false;
+ bool endrange = false;
+ string post;
+ for (string::const_iterator it = marg.begin(), et = marg.end(); it != et; ++it) {
+ char c = *it;
+ if (inpost) {
+ if (post.empty() && c == '(')
+ startrange = true;
+ else if (post.empty() && c == ')')
+ endrange = true;
+ else
+ post += c;
+ }
+ if (!inpost && (c == '|' && lc != '"'))
+ inpost = true;
+ lc = c;
+ }
+ if (startrange)
+ os << "\nrange start";
+ else if (endrange)
+ os << "\nrange end";
+ else
+ os << "\nrange none";
+ bool const see = prefixIs(post, "see{");
+ bool const seealso = prefixIs(post, "seealso{");
+ if (!post.empty() && !see && !seealso)
+ os << "\npageformat " << post;
+ else
+ os << "\npageformat default";
+ os << "\nstatus collapsed\n";
+
+ bool main = true;
+ // save position
+ p.pushPosition();
+ // Check for levels
+ if (p.hasIdxMacros("!")) {
+ // Index entry with levels
+ while (p.hasIdxMacros("!")) {
+ if (main) {
+ // swallow brace
+ p.get_token();
+ os << "\\begin_layout Plain Layout\n";
+ } else {
+ begin_inset(os, "IndexMacro subindex");
+ os << "\nstatus collapsed\n";
+ }
+ // Check for (level-specific) sortkey
+ if (p.hasIdxMacros("@", "!")) {
+ if (!main)
+ os << "\\begin_layout Plain Layout\n";
+ begin_inset(os, "IndexMacro sortkey");
+ os << "\nstatus collapsed\n";
+ parse_text_in_inset(p, os, FLAG_RDELIM, false, context, "IndexMacro sortkey", "@", "\"");
+ end_inset(os);
+ }
+ parse_text_snippet(p, os, FLAG_RDELIM, false, context, "!", "\"");
+ if (!main) {
+ os << "\n\\end_layout\n";
+ end_inset(os);
+ }
+ main = false;
+ }
+ if (!main) {
+ begin_inset(os, "IndexMacro subindex");
+ os << "\nstatus collapsed\n";
+ }
+ // Final level
+ // Check for (level-specific) sortkey
+ if (p.hasIdxMacros("@", "!")) {
+ if (main) {
+ // swallow brace
+ p.get_token();
+ }
+ os << "\\begin_layout Plain Layout\n";
+ begin_inset(os, "IndexMacro sortkey");
+ os << "\nstatus collapsed\n";
+ parse_text_in_inset(p, os, FLAG_RDELIM, false, context, "IndexMacro sortkey", "@", "\"");
+ end_inset(os);
+ if (post.empty() && !startrange && !endrange) {
+ parse_text_snippet(p, os, FLAG_BRACE_LAST, false, context);
+ p.dropPosition();
+ } else {
+ // Handle post-argument
+ parse_text_snippet(p, os, FLAG_RDELIM, false, context, "|", "\"");
+ if (see || seealso) {
+ while (p.next_token().character() != '{' && p.good())
+ p.get_token();
+ // this ends the subinset, as the see[also] insets
+ // must come at main index inset
+ os << "\n\\end_layout\n";
+ end_inset(os);
+ if (see)
+ begin_inset(os, "IndexMacro see");
+ else
+ begin_inset(os, "IndexMacro seealso");
+ os << "\nstatus collapsed\n";
+ os << "\\begin_layout Plain Layout\n";
+ parse_text_snippet(p, os, FLAG_ITEM, false, context);
+ }
+ p.popPosition();
+ // swallow argument
+ p.getArg('{', '}');
+ }
+ os << "\n\\end_layout\n";
+ } else {
+ if (post.empty() && !startrange && !endrange) {
+ parse_text_in_inset(p, os, FLAG_BRACE_LAST, false, context, "IndexMacro subindex");
+ p.dropPosition();
+ } else {
+ // Handle post-argument
+ if (see || seealso) {
+ os << "\\begin_layout Plain Layout\n";
+ parse_text_snippet(p, os, FLAG_RDELIM, false, context, "|", "\"");
+ while (p.next_token().character() != '{' && p.good())
+ p.get_token();
+ // this ends the subinset, as the see[also] insets
+ // must come at main index inset
+ os << "\n\\end_layout\n";
+ end_inset(os);
+ if (see)
+ begin_inset(os, "IndexMacro see");
+ else
+ begin_inset(os, "IndexMacro seealso");
+ os << "\nstatus collapsed\n";
+ parse_text_in_inset(p, os, FLAG_ITEM, false, context, "IndexMacro see");
+ } else
+ parse_text_in_inset(p, os, FLAG_RDELIM, false, context, "Index", "|", "\"");
+ p.popPosition();
+ // swallow argument
+ p.getArg('{', '}');
+ }
+ }
+ if (!main)
+ end_inset(os);
+ os << "\n\\end_layout\n";
+ } else {
+ // Index without any levels
+ // Check for sortkey
+ if (p.hasIdxMacros("@", "!")) {
+ // swallow brace
+ p.get_token();
+ os << "\\begin_layout Plain Layout\n";
+ begin_inset(os, "IndexMacro sortkey");
+ os << "\nstatus collapsed\n";
+ parse_text_in_inset(p, os, FLAG_RDELIM, false, context, "IndexMacro sortkey", "@", "\"");
+ end_inset(os);
+ if (post.empty() && !startrange && !endrange) {
+ parse_text_snippet(p, os, FLAG_BRACE_LAST, false, context);
+ p.dropPosition();
+ } else {
+ parse_text_snippet(p, os, FLAG_RDELIM, false, context, "|", "\"");
+ if (see || seealso) {
+ while (p.next_token().character() != '{' && p.good())
+ p.get_token();
+ if (see)
+ begin_inset(os, "IndexMacro see");
+ else
+ begin_inset(os, "IndexMacro seealso");
+ os << "\nstatus collapsed\n";
+ parse_text_in_inset(p, os, FLAG_ITEM, false, context, "IndexMacro see");
+ end_inset(os);
+ }
+ p.popPosition();
+ // swallow argument
+ p.getArg('{', '}');
+ }
+ os << "\n\\end_layout\n";
+ } else {
+ if (post.empty() && !startrange && !endrange) {
+ parse_text_in_inset(p, os, FLAG_ITEM, false, context, "Index");
+ p.dropPosition();
+ } else {
+ // Handle post-argument
+ // swallow brace
+ p.get_token();
+ if (see || seealso) {
+ os << "\\begin_layout Plain Layout\n";
+ parse_text_snippet(p, os, FLAG_RDELIM, false, context, "|", "\"");
+ while (p.next_token().character() != '{' && p.good())
+ p.get_token();
+ if (see)
+ begin_inset(os, "IndexMacro see");
+ else
+ begin_inset(os, "IndexMacro seealso");
+ os << "\nstatus collapsed\n";
+ parse_text_in_inset(p, os, FLAG_ITEM, false, context, "IndexMacro see");
+ end_inset(os);
+ os << "\n\\end_layout\n";
+ } else
+ parse_text_in_inset(p, os, FLAG_RDELIM, false, context, "Index", "|", "\"");
+ p.popPosition();
+ // swallow argument
+ p.getArg('{', '}');
+ }
+ }
+ }
+ end_inset(os);
+}
+
+
void parse_listings(Parser & p, ostream & os, Context & parent_context,
bool in_line, bool use_minted)
{
void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
- Context & context, string const & rdelim)
+ Context & context, string const & rdelim, string const & rdelimesc)
{
Layout const * newlayout = 0;
InsetLayout const * newinsetlayout = 0;
if (rdelim.size() > 1)
tok += p.next_token().asInput();
if (t.cat() != catEscape && !rdelim.empty()
- && tok == rdelim && (flags & FLAG_RDELIM)) {
+ && tok == rdelim && (flags & FLAG_RDELIM)
+ && (rdelimesc.empty() || p.prev_token().asInput() != rdelimesc)) {
if (rdelim.size() > 1)
p.get_token(); // eat rdelim
return;
string const arg = (t.cs() == "sindex" && p.hasOpt()) ?
p.getArg('[', ']') : "";
string const kind = arg.empty() ? "idx" : arg;
- begin_inset(os, "Index ");
- os << kind << "\nstatus collapsed\n";
- parse_text_in_inset(p, os, FLAG_ITEM, false, context, "Index");
- end_inset(os);
+ parse_index_entry(p, os, context, kind);
if (kind != "idx")
preamble.registerAutomaticallyLoadedPackage("splitidx");
continue;