CharInfo: allow to store several commands (both text and math) for each character.

Only the first one is returned by default with existing methods to guarantee compatibility with existing code.
This commit is contained in:
Thibaut Cuvelier 2022-02-18 22:11:04 +01:00
parent faf0e9ee13
commit 3f9e21b826
4 changed files with 121 additions and 92 deletions

View File

@ -52,7 +52,7 @@ void BufferEncodings::validate(char_type c, LaTeXFeatures & features, bool for_m
CharInfo const & ci = Encodings::unicodeCharInfo(c);
if (ci.isUnicodeSymbol()) {
// In mathed, c could be used both in textmode and mathmode
docstring const textcommand = ci.textcommand();
docstring const textcommand = ci.textCommand();
bool const math_mode = for_mathed && isMathCmd(c);
bool const use_math = math_mode ||
(!for_mathed && textcommand.empty());
@ -65,9 +65,9 @@ void BufferEncodings::validate(char_type c, LaTeXFeatures & features, bool for_m
// and if we do not use unicode-math
if ((math_mode && !unicode_math)
|| (use_math && !plain_utf8)) {
string const mathpreamble = ci.mathpreamble();
string const mathpreamble = ci.mathPreamble();
if (!mathpreamble.empty()) {
if (ci.mathfeature()) {
if (ci.mathFeature()) {
string feats = mathpreamble;
while (!feats.empty()) {
string feat;
@ -80,9 +80,9 @@ void BufferEncodings::validate(char_type c, LaTeXFeatures & features, bool for_m
}
// with utf8-plain, we do not load packages (see #7766)
if (use_text && !plain_utf8) {
string const textpreamble = ci.textpreamble();
string const textpreamble = ci.textPreamble();
if (!textpreamble.empty()) {
if (ci.textfeature()) {
if (ci.textFeature()) {
string feats = textpreamble;
while (!feats.empty()) {
string feat;

View File

@ -75,12 +75,23 @@ const char * EncodingException::what() const noexcept
CharInfo::CharInfo(
docstring const & textcommand, docstring const & mathcommand,
std::string const & textpreamble, std::string const & mathpreamble,
std::string const & tipashortcut, unsigned int flags)
: textcommand_(textcommand), mathcommand_(mathcommand),
textpreamble_(textpreamble), mathpreamble_(mathpreamble),
tipashortcut_(tipashortcut), flags_(flags)
docstring const & text_command, docstring const & math_command,
std::string const & text_preamble, std::string const & math_preamble,
std::string const & tipa_shortcut, unsigned int flags)
: text_commands_({text_command}), math_commands_({math_command}),
text_preamble_(text_preamble), math_preamble_(math_preamble),
tipa_shortcut_(tipa_shortcut), flags_(flags)
{
}
CharInfo::CharInfo(
std::vector<docstring> const & text_commands, std::vector<docstring> const & math_commands,
std::string const & text_preamble, std::string const & math_preamble,
std::string const & tipa_shortcut, unsigned int flags)
: text_commands_(text_commands), math_commands_(math_commands),
text_preamble_(text_preamble), math_preamble_(math_preamble),
tipa_shortcut_(tipa_shortcut), flags_(flags)
{
}
@ -216,11 +227,11 @@ pair<docstring, bool> Encoding::latexChar(char_type c) const
CharInfoMap::const_iterator const it = unicodesymbols.find(c);
if (it == unicodesymbols.end())
throw EncodingException(c);
// at least one of mathcommand and textcommand is nonempty
if (it->second.textcommand().empty())
// at least one of mathCommand and textCommand is nonempty
if (it->second.textCommand().empty())
return make_pair(
"\\ensuremath{" + it->second.mathcommand() + '}', false);
return make_pair(it->second.textcommand(), !it->second.textnotermination());
"\\ensuremath{" + it->second.mathCommand() + '}', false);
return make_pair(it->second.textCommand(), !it->second.textNoTermination());
}
@ -302,17 +313,17 @@ bool Encodings::latexMathChar(char_type c, bool mathmode,
addMathSym(c);
return false;
}
// at least one of mathcommand and textcommand is nonempty
bool use_math = (mathmode && !it->second.mathcommand().empty()) ||
(!mathmode && it->second.textcommand().empty());
// at least one of mathCommand and textCommand is nonempty
bool use_math = (mathmode && !it->second.mathCommand().empty()) ||
(!mathmode && it->second.textCommand().empty());
if (use_math) {
command = it->second.mathcommand();
needsTermination = !it->second.mathnotermination();
command = it->second.mathCommand();
needsTermination = !it->second.mathNoTermination();
addMathCmd(c);
} else {
if (!encoding || command.empty()) {
command = it->second.textcommand();
needsTermination = !it->second.textnotermination();
command = it->second.textCommand();
needsTermination = !it->second.textNoTermination();
}
if (mathmode)
addMathSym(c);
@ -331,23 +342,31 @@ char_type Encodings::fromLaTeXCommand(docstring const & cmd, int cmdtype,
for (combining = false; it != end; ++it) {
if (it->second.deprecated())
continue;
docstring const math = it->second.mathcommand();
docstring const text = it->second.textcommand();
if ((cmdtype & MATH_CMD) && math == cmd) {
combining = it->second.combining();
needsTermination = !it->second.mathnotermination();
if (req && it->second.mathfeature() &&
!it->second.mathpreamble().empty())
req->insert(it->second.mathpreamble());
return it->first;
if (cmdtype & MATH_CMD) {
for (const docstring& math : it->second.mathCommands()) {
if ((cmdtype & MATH_CMD) && math == cmd) {
combining = it->second.combining();
needsTermination = !it->second.mathNoTermination();
if (req && it->second.mathFeature() &&
!it->second.mathPreamble().empty())
req->insert(it->second.mathPreamble());
return it->first;
}
}
}
if ((cmdtype & TEXT_CMD) && text == cmd) {
combining = it->second.combining();
needsTermination = !it->second.textnotermination();
if (req && it->second.textfeature() &&
!it->second.textpreamble().empty())
req->insert(it->second.textpreamble());
return it->first;
if (cmdtype & TEXT_CMD) {
for (const docstring& text : it->second.textCommands()) {
if (text == cmd) {
combining = it->second.combining();
needsTermination = !it->second.textNoTermination();
if (req && it->second.textFeature() &&
!it->second.textPreamble().empty())
req->insert(it->second.textPreamble());
return it->first;
}
}
}
}
needsTermination = false;
@ -418,9 +437,9 @@ docstring Encodings::fromLaTeXCommand(docstring const & cmd, int cmdtype,
for (; it != uniend; ++it) {
if (it->second.deprecated())
continue;
docstring const math = mathmode ? it->second.mathcommand()
docstring const math = mathmode ? it->second.mathCommand()
: docstring();
docstring const text = textmode ? it->second.textcommand()
docstring const text = textmode ? it->second.textCommand()
: docstring();
if (!combcmd.empty() && it->second.combining() &&
(math == combcmd || text == combcmd))
@ -496,16 +515,16 @@ docstring Encodings::fromLaTeXCommand(docstring const & cmd, int cmdtype,
i = j + 1;
unicmd_size = cur_size;
if (math == tmp)
needsTermination = !it->second.mathnotermination();
needsTermination = !it->second.mathNoTermination();
else
needsTermination = !it->second.textnotermination();
needsTermination = !it->second.textNoTermination();
if (req) {
if (math == tmp && it->second.mathfeature() &&
!it->second.mathpreamble().empty())
req->insert(it->second.mathpreamble());
if (text == tmp && it->second.textfeature() &&
!it->second.textpreamble().empty())
req->insert(it->second.textpreamble());
if (math == tmp && it->second.mathFeature() &&
!it->second.mathPreamble().empty())
req->insert(it->second.mathPreamble());
if (text == tmp && it->second.textFeature() &&
!it->second.textPreamble().empty())
req->insert(it->second.textPreamble());
}
}
}
@ -584,7 +603,7 @@ string const Encodings::TIPAShortcut(char_type c)
{
CharInfoMap::const_iterator const it = unicodesymbols.find(c);
if (it != unicodesymbols.end())
return it->second.tipashortcut();
return it->second.tipaShortcut();
return string();
}
@ -595,11 +614,11 @@ string const Encodings::isKnownScriptChar(char_type const c)
if (it == unicodesymbols.end())
return string();
// FIXME: parse complex textpreamble (may be list or alternatives,
// FIXME: parse complex textPreamble (may be list or alternatives,
// e.g., "subscript,textgreek" or "textcomp|textgreek")
if (it->second.textpreamble() == "textgreek"
|| it->second.textpreamble() == "textcyrillic")
return it->second.textpreamble();
if (it->second.textPreamble() == "textgreek"
|| it->second.textPreamble() == "textcyrillic")
return it->second.textPreamble();
return string();
}
@ -627,7 +646,7 @@ bool Encodings::isUnicodeTextOnly(char_type c)
return false;
CharInfoMap::const_iterator const it = unicodesymbols.find(c);
return it == unicodesymbols.end() || it->second.mathcommand().empty();
return it == unicodesymbols.end() || it->second.mathCommand().empty();
}
@ -754,7 +773,7 @@ void Encodings::read(FileName const & encfile, FileName const & symbolsfile)
} else if (flag == "notermination=none") {
flags &= ~CharInfoTextNoTermination;
flags &= ~CharInfoMathNoTermination;
} else if (contains(flag, "tipashortcut=")) {
} else if (contains(flag, "tipaShortcut=")) {
tipashortcut = split(flag, '=');
} else if (flag == "deprecated") {
flags |= CharInfoDeprecated;
@ -765,7 +784,7 @@ void Encodings::read(FileName const & encfile, FileName const & symbolsfile)
<< "'." << endl;
}
}
// mathcommand and mathpreamble have been added for 1.6.0.
// mathCommand and mathPreamble have been added for 1.6.0.
// make them optional so that old files still work.
int const lineno = symbolslex.lineNumber();
bool breakout = false;
@ -773,7 +792,7 @@ void Encodings::read(FileName const & encfile, FileName const & symbolsfile)
string mathpreamble;
if (symbolslex.next(true)) {
if (symbolslex.lineNumber() != lineno) {
// line in old format without mathcommand and mathpreamble
// line in old format without mathCommand and mathPreamble
getNextToken = false;
} else {
mathcommand = symbolslex.getDocString();
@ -781,10 +800,10 @@ void Encodings::read(FileName const & encfile, FileName const & symbolsfile)
flags |= CharInfoMathNoTermination;
if (symbolslex.next(true)) {
if (symbolslex.lineNumber() != lineno) {
// line in new format with mathcommand only
// line in new format with mathCommand only
getNextToken = false;
} else {
// line in new format with mathcommand and mathpreamble
// line in new format with mathCommand and mathPreamble
mathpreamble = symbolslex.getString();
}
} else
@ -810,12 +829,12 @@ void Encodings::read(FileName const & encfile, FileName const & symbolsfile)
textpreamble, mathpreamble,
tipashortcut, flags);
LYXERR(Debug::INFO, "Read unicode symbol " << symbol << " '"
<< to_utf8(info.textcommand()) << "' '" << info.textpreamble()
<< " '" << info.textfeature() << ' ' << info.textnotermination()
<< ' ' << to_utf8(info.mathcommand()) << "' '" << info.mathpreamble()
<< "' " << info.mathfeature() << ' ' << info.mathnotermination()
<< to_utf8(info.textCommand()) << "' '" << info.textPreamble()
<< " '" << info.textFeature() << ' ' << info.textNoTermination()
<< ' ' << to_utf8(info.mathCommand()) << "' '" << info.mathPreamble()
<< "' " << info.mathFeature() << ' ' << info.mathNoTermination()
<< ' ' << info.combining() << ' ' << info.force()
<< ' ' << info.forceselected());
<< ' ' << info.forceSelected());
// we assume that at least one command is nonempty when using unicodesymbols
if (info.isUnicodeSymbol()) {

View File

@ -62,52 +62,62 @@ class CharInfo {
public:
CharInfo() : flags_(0) {}
CharInfo(
docstring const & textcommand, docstring const & mathcommand,
std::string const & textpreamble, std::string const & mathpreamble,
std::string const & tipashortcut, unsigned int flags);
docstring const & text_command, docstring const & math_command,
std::string const & text_preamble, std::string const & math_preamble,
std::string const & tipa_shortcut, unsigned int flags);
CharInfo(
std::vector<docstring> const & text_commands, std::vector<docstring> const & math_commands,
std::string const & text_preamble, std::string const & math_preamble,
std::string const & tipa_shortcut, unsigned int flags);
// we assume that at least one command is nonempty when using unicodesymbols
bool isUnicodeSymbol() const { return !textcommand_.empty() || !mathcommand_.empty(); }
bool isUnicodeSymbol() const { return !text_commands_.empty() || !math_commands_.empty(); }
/// LaTeX command (text mode) for this character
docstring const textcommand() const { return textcommand_; }
docstring textCommand() const { return text_commands_[0]; }
/// All known LaTeX commands (text mode) for this character
std::vector<docstring> textCommands() const { return text_commands_; }
/// LaTeX command (math mode) for this character
docstring mathcommand() const { return mathcommand_; }
docstring mathCommand() const { return math_commands_[0]; }
/// All known LaTeX commands (math mode) for this character
std::vector<docstring> mathCommands() const { return math_commands_; }
/// Needed LaTeX preamble (or feature) for text mode
std::string textpreamble() const { return textpreamble_; }
std::string textPreamble() const { return text_preamble_; }
/// Needed LaTeX preamble (or feature) for math mode
std::string mathpreamble() const { return mathpreamble_; }
std::string mathPreamble() const { return math_preamble_; }
/// Is this a combining character?
bool combining() const { return flags_ & CharInfoCombining; }
/// Is \c textpreamble a feature known by LaTeXFeatures, or a raw LaTeX
/// Is \c textPreamble a feature known by LaTeXFeatures, or a raw LaTeX
/// command?
bool textfeature() const { return flags_ & CharInfoTextFeature; }
/// Is \c mathpreamble a feature known by LaTeXFeatures, or a raw LaTeX
bool textFeature() const { return flags_ & CharInfoTextFeature; }
/// Is \c mathPreamble a feature known by LaTeXFeatures, or a raw LaTeX
/// command?
bool mathfeature() const { return flags_ & CharInfoMathFeature; }
bool mathFeature() const { return flags_ & CharInfoMathFeature; }
/// Always force the LaTeX command, even if the encoding contains
/// this character?
bool force() const { return flags_ & CharInfoForce; }
/// Force the LaTeX command for some encodings?
bool forceselected() const { return flags_ & CharInfoForceSelected; }
bool forceSelected() const { return flags_ & CharInfoForceSelected; }
/// Disable LaTeX command => char_type conversion for this deprecated symbol?
bool deprecated() const { return flags_ & CharInfoDeprecated; }
/// TIPA shortcut
std::string const tipashortcut() const { return tipashortcut_; }
/// \c textcommand needs no termination (such as {} or space).
bool textnotermination() const { return flags_ & CharInfoTextNoTermination; }
/// \c mathcommand needs no termination (such as {} or space).
bool mathnotermination() const { return flags_ & CharInfoMathNoTermination; }
std::string const tipaShortcut() const { return tipa_shortcut_; }
/// \c textCommand needs no termination (such as {} or space).
bool textNoTermination() const { return flags_ & CharInfoTextNoTermination; }
/// \c mathCommand needs no termination (such as {} or space).
bool mathNoTermination() const { return flags_ & CharInfoMathNoTermination; }
///
private:
/// LaTeX command (text mode) for this character
trivdocstring textcommand_;
/// LaTeX command (math mode) for this character
trivdocstring mathcommand_;
/// LaTeX commands (text mode) for this character. The first one is the default, the others
/// are only present for compatibility other ways users may encode the character
std::vector<trivdocstring> text_commands_;
/// LaTeX command (math mode) for this character. The first one is the default, the others
// /// are only present for compatibility other ways users may encode the character
std::vector<trivdocstring> math_commands_;
/// Needed LaTeX preamble (or feature) for text mode
trivstring textpreamble_;
trivstring text_preamble_;
/// Needed LaTeX preamble (or feature) for math mode
trivstring mathpreamble_;
trivstring math_preamble_;
/// TIPA shortcut
trivstring tipashortcut_;
trivstring tipa_shortcut_;
/// feature flags
unsigned int flags_;
};
@ -288,7 +298,7 @@ public:
/**
* Do we have to wrap in \text this character when in mathmode?
* This is true if \p c is not ascii and the "mathalpha" flag is not
* set and a mathcommand is not defined in the unicodesymbols file.
* set and a mathCommand is not defined in the unicodesymbols file.
*/
static bool isUnicodeTextOnly(char_type c);
/**

View File

@ -1535,9 +1535,9 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const
else if (features.runparams().main_fontenc != "T1"
|| ((&owner_->getFontSettings(bp, i))->language()->internalFontEncoding()))
features.require("textquotedbl");
} else if (ci.textfeature() && contains(ci.textpreamble(), '=')) {
} else if (ci.textFeature() && contains(ci.textPreamble(), '=')) {
// features that depend on the font or input encoding
string feats = ci.textpreamble();
string feats = ci.textPreamble();
string fontenc = (&owner_->getFontSettings(bp, i))->language()->fontenc(bp);
if (fontenc.empty())
fontenc = features.runparams().main_fontenc;