mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-22 01:59:02 +00:00
Introduce InsetIndexMacros
This adds native macros for subindexes (!level), |see and |seealso as well as native support for ranges |( |) and pagination format -- e.g., |textbf -- via the index dialog Resolves #12478, #7232 and #5014 The feature is complete (incl. tex2lyx) except for * file format change and lyx2lyx * docbook/xhtml * documentation
This commit is contained in:
parent
335f158896
commit
7d7b21ec3e
@ -431,6 +431,36 @@ InsetLayout Index
|
||||
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
|
||||
|
@ -631,6 +631,23 @@ Menuset
|
||||
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
|
||||
|
@ -391,6 +391,7 @@ Menuset
|
||||
Item "Label...|L" "label-insert"
|
||||
Captions
|
||||
Indices
|
||||
OptSubmenu "Index Properties" "index_properties"
|
||||
Item "Nomenclature Entry...|y" "nomencl-insert"
|
||||
Separator
|
||||
Item "Table...|T" "tabular-insert"
|
||||
@ -532,6 +533,13 @@ Menuset
|
||||
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"
|
||||
|
@ -503,6 +503,8 @@ enum FuncCode
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -2323,6 +2323,16 @@ void LyXAction::init()
|
||||
*/
|
||||
{ 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
|
||||
|
@ -565,6 +565,7 @@ SOURCEFILESINSETS = \
|
||||
insets/InsetHyperlink.cpp \
|
||||
insets/InsetInclude.cpp \
|
||||
insets/InsetIndex.cpp \
|
||||
insets/InsetIndexMacro.cpp \
|
||||
insets/InsetInfo.cpp \
|
||||
insets/InsetIPA.cpp \
|
||||
insets/InsetIPAMacro.cpp \
|
||||
|
@ -58,6 +58,7 @@
|
||||
#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"
|
||||
@ -2107,6 +2108,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
|
||||
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:
|
||||
@ -3285,6 +3287,14 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||
}
|
||||
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")
|
||||
|
@ -34,6 +34,7 @@
|
||||
#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"
|
||||
@ -159,6 +160,16 @@ Inset * createInsetHelper(Buffer * buf, FuncRequest const & cmd)
|
||||
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);
|
||||
|
||||
@ -667,6 +678,9 @@ Inset * readInset(Lexer & lex, Buffer * 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") {
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "BufferParams.h"
|
||||
#include "FuncRequest.h"
|
||||
#include "IndicesList.h"
|
||||
#include "insets/InsetIndex.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
@ -37,6 +38,18 @@ GuiIndex::GuiIndex(GuiView & lv)
|
||||
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));
|
||||
@ -49,11 +62,26 @@ void GuiIndex::change_adaptor()
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
@ -64,8 +92,19 @@ void GuiIndex::updateContents()
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +112,15 @@ void GuiIndex::applyView()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,6 +31,7 @@ public:
|
||||
|
||||
private Q_SLOTS:
|
||||
void change_adaptor();
|
||||
void pageFormatChanged(int);
|
||||
|
||||
private:
|
||||
/// Apply changes
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>262</width>
|
||||
<height>121</height>
|
||||
<width>384</width>
|
||||
<height>288</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -16,50 +16,119 @@
|
||||
<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>
|
||||
|
@ -239,6 +239,10 @@ enum InsetCode {
|
||||
///
|
||||
COUNTER_CODE,
|
||||
///
|
||||
INDEXMACRO_CODE, // 110
|
||||
///
|
||||
INDEXMACRO_SORTKEY_CODE,
|
||||
///
|
||||
INSET_CODE_SIZE
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <config.h>
|
||||
|
||||
#include "InsetIndex.h"
|
||||
#include "InsetIndexMacro.h"
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "BufferParams.h"
|
||||
@ -19,10 +20,13 @@
|
||||
#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"
|
||||
@ -37,6 +41,7 @@
|
||||
#include "support/FileName.h"
|
||||
#include "support/gettext.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/Translator.h"
|
||||
|
||||
#include "frontends/alert.h"
|
||||
|
||||
@ -51,6 +56,62 @@ using namespace lyx::support;
|
||||
|
||||
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
|
||||
@ -59,7 +120,7 @@ namespace lyx {
|
||||
|
||||
|
||||
InsetIndex::InsetIndex(Buffer * buf, InsetIndexParams const & params)
|
||||
: InsetCollapsible(buf), params_(params)
|
||||
: InsetCollapsible(buf), params_(params)
|
||||
{}
|
||||
|
||||
|
||||
@ -91,106 +152,108 @@ void InsetIndex::latex(otexstream & ios, OutputParams const & runparams_in) cons
|
||||
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!");
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
// 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 << '@';
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} 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 << '}';
|
||||
|
||||
@ -203,6 +266,45 @@ void InsetIndex::latex(otexstream & ios, OutputParams const & runparams_in) cons
|
||||
}
|
||||
|
||||
|
||||
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 {}).
|
||||
@ -445,6 +547,8 @@ void InsetIndex::doDispatch(Cursor & cur, FuncRequest & cmd)
|
||||
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();
|
||||
@ -485,6 +589,9 @@ bool InsetIndex::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||
flag.setEnabled(realbuffer.params().use_indices);
|
||||
return true;
|
||||
}
|
||||
|
||||
case LFUN_INDEXMACRO_INSERT:
|
||||
return macrosPossible(cmd.getArg(0));
|
||||
|
||||
default:
|
||||
return InsetCollapsible::getStatus(cur, cmd, flag);
|
||||
@ -492,6 +599,125 @@ bool InsetIndex::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||
}
|
||||
|
||||
|
||||
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"))
|
||||
@ -520,7 +746,21 @@ docstring InsetIndex::toolTip(BufferView const &, int, int) const
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -541,9 +781,14 @@ docstring const InsetIndex::buttonLabel(BufferView const & bv) const
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -621,12 +866,33 @@ string InsetIndex::contextMenuName() const
|
||||
}
|
||||
|
||||
|
||||
bool InsetIndex::hasSettings() const
|
||||
string InsetIndex::contextMenu(BufferView const & bv, int x, int y) const
|
||||
{
|
||||
return buffer().masterBuffer()->params().use_indices;
|
||||
// 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -644,6 +910,12 @@ void InsetIndexParams::write(ostream & os) const
|
||||
else
|
||||
os << "idx";
|
||||
os << '\n';
|
||||
os << "range "
|
||||
<< insetindexpagerangetranslator().find(range)
|
||||
<< '\n';
|
||||
os << "pageformat "
|
||||
<< pagefmt
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
|
||||
@ -653,6 +925,16 @@ void InsetIndexParams::read(Lexer & lex)
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,15 +21,24 @@ namespace lyx {
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@ -63,6 +72,9 @@ private:
|
||||
///
|
||||
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;
|
||||
@ -80,11 +92,27 @@ private:
|
||||
/// 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;
|
||||
|
384
src/insets/InsetIndexMacro.cpp
Normal file
384
src/insets/InsetIndexMacro.cpp
Normal file
@ -0,0 +1,384 @@
|
||||
/**
|
||||
* \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
|
125
src/insets/InsetIndexMacro.h
Normal file
125
src/insets/InsetIndexMacro.h
Normal file
@ -0,0 +1,125 @@
|
||||
// -*- 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
|
@ -1040,6 +1040,10 @@ bool InsetText::insetAllowed(InsetCode code) const
|
||||
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();
|
||||
}
|
||||
|
@ -486,7 +486,40 @@ bool Parser::hasOpt(string const & l)
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
@ -495,25 +528,28 @@ Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping)
|
||||
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) {
|
||||
@ -525,6 +561,10 @@ Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping)
|
||||
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)
|
||||
@ -540,9 +580,9 @@ Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping)
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -215,17 +215,22 @@ public:
|
||||
|
||||
/// 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
|
||||
@ -236,7 +241,8 @@ public:
|
||||
* 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 "[]".
|
||||
|
@ -48,7 +48,8 @@ extern std::string rgbcolor2code(std::string const & name);
|
||||
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);
|
||||
@ -68,7 +69,8 @@ std::string find_file(std::string const & name, std::string const & path,
|
||||
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.
|
||||
|
@ -55,7 +55,7 @@ void output_arguments(ostream &, Parser &, bool, bool, const string &, Context &
|
||||
|
||||
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;
|
||||
@ -78,7 +78,7 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
|
||||
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());
|
||||
@ -91,7 +91,8 @@ namespace {
|
||||
|
||||
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 =
|
||||
@ -99,17 +100,18 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
|
||||
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;
|
||||
@ -1506,6 +1508,218 @@ void parse_outer_box(Parser & p, ostream & os, unsigned flags, bool outer,
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
@ -2901,7 +3115,7 @@ void fix_child_filename(string & name)
|
||||
|
||||
|
||||
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;
|
||||
@ -2990,7 +3204,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
|
||||
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;
|
||||
@ -4712,10 +4927,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user