#include "LaTeXFeatures.h"
#include "LaTeXFonts.h"
#include "Font.h"
-#include "Lexer.h"
#include "LyXRC.h"
#include "OutputParams.h"
#include "Spacing.h"
#include "support/filetools.h"
#include "support/gettext.h"
#include "support/Length.h"
+#include "support/Lexer.h"
#include "support/Messages.h"
#include "support/mutex.h"
#include "support/Package.h"
static char const * const string_quotes_style[] = {
"english", "swedish", "german", "polish", "swiss", "danish", "plain",
"british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle",
- "hungarian", ""
+ "hungarian", "hebrew", ""
};
translator.addPair(string_quotes_style[12], QuoteStyle::CJK);
translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngle);
translator.addPair(string_quotes_style[14], QuoteStyle::Hungarian);
+ translator.addPair(string_quotes_style[15], QuoteStyle::Hebrew);
return translator;
}
authorlist.record(Author(from_utf8(lyxrc.user_name),
from_utf8(lyxrc.user_email),
from_utf8(lyxrc.user_initials)));
+ // set comparison author
+ authorlist.record(Author(from_utf8("Document Comparison"),
+ docstring(), docstring()));
}
shell_escape = false;
output_sync = false;
use_refstyle = true;
+ use_formatted_ref = false;
use_minted = false;
use_lineno = false;
Bullet & BufferParams::temp_bullet(lyx::size_type const index)
{
- if (index < 4)
- return pimpl_->temp_bullets[index];
- // Fallback bullet if we are too deeply nested
- docstring const fb = from_ascii("?") + convert<docstring>(index + 1);
- Bullet const & res = Bullet(fb);
- return const_cast<Bullet&>(res);
+ LASSERT(index < 4, return pimpl_->temp_bullets[0]);
+ return pimpl_->temp_bullets[index];
}
Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
{
- if (index < 4)
- return pimpl_->temp_bullets[index];
- // Fallback bullet if we are too deeply nested
- docstring const fb = from_ascii("?") + convert<docstring>(index + 1);
- Bullet const & res = Bullet(fb);
- return res;
+ LASSERT(index < 4, return pimpl_->temp_bullets[0]);
+ return pimpl_->temp_bullets[index];
}
Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
{
- if (index < 4)
- return pimpl_->user_defined_bullets[index];
- // Fallback bullet if we are too deeply nested
- docstring const fb = from_ascii("?") + convert<docstring>(index + 1);
- Bullet const & res = Bullet(fb);
- return const_cast<Bullet&>(res);
+ LASSERT(index < 4, return pimpl_->temp_bullets[0]);
+ return pimpl_->user_defined_bullets[index];
}
Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
{
- if (index < 4)
- return pimpl_->user_defined_bullets[index];
- // Fallback bullet if we are too deeply nested
- docstring const fb = from_ascii("?") + convert<docstring>(index + 1);
- Bullet const & res = Bullet(fb);
- return res;
+ LASSERT(index < 4, return pimpl_->temp_bullets[0]);
+ return pimpl_->user_defined_bullets[index];
}
lex >> output_sync_macro;
} else if (token == "\\use_refstyle") {
lex >> use_refstyle;
+ } else if (token == "\\use_formatted_ref") {
+ lex >> use_formatted_ref;
} else if (token == "\\use_minted") {
lex >> use_minted;
} else if (token == "\\use_lineno") {
<< "\n\\suppress_date " << convert<string>(suppress_date)
<< "\n\\justification " << convert<string>(justification)
<< "\n\\use_refstyle " << use_refstyle
+ << "\n\\use_formatted_ref " << use_formatted_ref
<< "\n\\use_minted " << use_minted
<< "\n\\use_lineno " << use_lineno
<< '\n';
{
features.require(documentClass().required());
- if (columns > 1 && language->rightToLeft())
+ if (columns > 1 && language->rightToLeft()
+ && !features.runparams().isFullUnicode()
+ && language->babel() != "hebrew")
features.require("rtloutputdblcol");
if (output_changes) {
features.require("ulem");
features.require("xcolor");
// improves color handling in PDF output
- features.require("pdfcolmk");
} else {
features.require("ct-none");
}
FileName const & filepath) const
{
// DocumentMetadata must come before anything else
- if (features.isAvailable("LaTeX-2022/06/01")
+ if (features.isAvailableAtLeastFrom("LaTeX", 2022, 6)
&& !containsOnly(document_metadata, " \n\t")) {
// Check if the user preamble contains uncodable glyphs
odocstringstream doc_metadata;
"\n\nPlease select an appropriate "
"document encoding\n"
"(such as utf8) or change the "
- "preamble code accordingly."),
+ "metadata accordingly."),
uncodable_glyphs));
}
if (!doc_metadata.str().empty()) {
break;
}
+ if (paragraph_separation) {
+ if (!tclass.halfparskip().empty() && getDefSkip().kind() == VSpace::HALFLINE)
+ clsoptions << tclass.halfparskip() << ",";
+ if (!tclass.fullparskip().empty() && getDefSkip().kind() == VSpace::FULLLINE)
+ clsoptions << tclass.fullparskip() << ",";
+ }
+
// language should be a parameter to \documentclass
if (language->babel() == "hebrew"
&& default_language->babel() != "hebrew")
if (useNonTeXFonts) {
// Babel (as of 2017/11/03) loads fontspec itself
+ // However, it does so only if a non-default font is requested via \babelfont
+ // Thus load fontspec if this is not the case and we need fontspec features
+ bool const babel_needfontspec =
+ !features.isAvailableAtLeastFrom("babel", 2017, 11, 3)
+ || (fontsRoman() == "default"
+ && fontsSans() == "default"
+ && fontsTypewriter() == "default"
+ // these need fontspec features
+ && (features.isRequired("textquotesinglep")
+ || features.isRequired("textquotedblp")));
if (!features.isProvided("fontspec")
- && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
+ && (!features.useBabel() || babel_needfontspec))
os << "\\usepackage{fontspec}\n";
if (features.mustProvide("unicode-math")
&& features.isAvailable("unicode-math"))
if (!features.runparams().includeall && !included_children_.empty()) {
os << "\\includeonly{";
bool first = true;
+ // we do not use "auto const &" here, because incfile is modified later
+ // coverity[auto_causes_copy]
for (auto incfile : included_children_) {
FileName inc = makeAbsPath(incfile, filepath.absFileName());
string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
if (paragraph_separation) {
// when skip separation
string psopt;
+ bool default_skip = false;
+ bool by_class_option = false;
switch (getDefSkip().kind()) {
case VSpace::SMALLSKIP:
psopt = "\\smallskipamount";
break;
case VSpace::HALFLINE:
// default (no option)
+ default_skip = true;
+ by_class_option = !tclass.halfparskip().empty();
break;
case VSpace::FULLLINE:
psopt = "\\baselineskip";
+ by_class_option = !tclass.fullparskip().empty();
break;
case VSpace::LENGTH:
psopt = getDefSkip().length().asLatexString();
default:
break;
}
- if (!features.isProvided("parskip")) {
+ if (features.isProvided("parskip")) {
+ // package already loaded (with arbitrary options)
+ // change parskip value only
if (!psopt.empty())
- psopt = "[skip=" + psopt + "]";
- os << "\\usepackage" + psopt + "{parskip}\n";
- } else {
- os << "\\setlength{\\parskip}{" + psopt + "}\n";
+ os << "\\setlength{\\parskip}{" + psopt + "}\n";
+ else if (default_skip)
+ // explicitly reset default (might have been changed
+ // in a class or package)
+ os << "\\parskip=.5\\baselineskip plus 2pt\\relax\n";
+ } else if (!by_class_option) {
+ // load parskip package with required options
+ string psopts;
+ if (!psopt.empty()) {
+ if (contains(psopt, ' '))
+ // glue length has spaces: embrace
+ psopts = "skip={" + psopt + "}";
+ else
+ psopts = "skip=" + psopt;
+ }
+ string const xpsopts = getPackageOptions("parskip");
+ if (!xpsopts.empty()) {
+ if (!psopts.empty())
+ psopts += ",";
+ psopts += xpsopts;
+ }
+ os << "\\usepackage";
+ if (!psopts.empty())
+ os << "[" << psopts << "]";
+ os << "{parskip}\n";
}
} else {
// when separation by indentation
os << from_utf8(output_sync_macro) +"\n";
else if (features.runparams().flavor == Flavor::LaTeX)
os << "\\usepackage[active]{srcltx}\n";
- else if (features.runparams().flavor == Flavor::PdfLaTeX)
+ else
os << "\\synctex=-1\n";
}
if (!tmppreamble.str.empty())
atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
"LyX specific LaTeX commands.\n"
- << move(tmppreamble)
+ << std::move(tmppreamble)
<< '\n';
}
// the text class specific preamble
}
+bool BufferParams::hasPackageOption(string const package, string const opt) const
+{
+ for (auto const & p : documentClass().packageOptions())
+ if (package == p.first && opt == p.second)
+ return true;
+ return false;
+}
+
+
+string BufferParams::getPackageOptions(string const package) const
+{
+ for (auto const & p : documentClass().packageOptions())
+ if (package == p.first)
+ return p.second;
+ return string();
+}
+
+
+bool BufferParams::useBidiPackage(OutputParams const & rp) const
+{
+ return (rp.use_polyglossia
+ // as of babel 3.29, bidi=bidi-* is supported by babel
+ // So we check whether we use a respective version and
+ // whethert bidi-r or bidi-l have been requested either via class
+ // or package options
+ || (rp.use_babel
+ && LaTeXFeatures::isAvailableAtLeastFrom("babel", 2019, 4, 3)
+ && (hasPackageOption("babel", "bidi-r")
+ || hasPackageOption("babel", "bidi-l")
+ || contains(options, "bidi-r")
+ || contains(options, "bidi-l")))
+ )
+ && rp.flavor == Flavor::XeTeX;
+}
+
+
void BufferParams::readPreamble(Lexer & lex)
{
if (lex.getString() != "\\begin_preamble")
if (useNonTeXFonts)
return;
+ string const doc_encoding = encoding().latexName();
+ Encoding::Package const package = encoding().package();
+ // (dvi)lualatex uses luainputenc rather than inputenc
+ string const inputenc_package =
+ (features.runparams().flavor == Flavor::LuaTeX
+ || features.runparams().flavor == Flavor::DviLuaTeX)
+ ? "luainputenc" : "inputenc";
+
if (inputenc == "auto-legacy") {
- string const doc_encoding =
- language->encoding()->latexName();
- Encoding::Package const package =
- language->encoding()->package();
-
- // Create list of inputenc options:
- set<string> encoding_set;
- // luainputenc fails with more than one encoding
- if (features.runparams().flavor != Flavor::LuaTeX
- && features.runparams().flavor != Flavor::DviLuaTeX)
- // list all input encodings used in the document
- encoding_set = features.getEncodingSet(doc_encoding);
-
- // The "japanese" babel-language requires the pLaTeX engine
+ // The "japanese" babel language requires the pLaTeX engine
// which conflicts with "inputenc".
// See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
- if ((!encoding_set.empty() || package == Encoding::inputenc)
- && !features.isRequired("japanese")
+ if (!features.isRequired("japanese")
&& !features.isProvided("inputenc")) {
- os << "\\usepackage[";
- set<string>::const_iterator it = encoding_set.begin();
- set<string>::const_iterator const end = encoding_set.end();
- if (it != end) {
- os << from_ascii(*it);
- ++it;
- }
- for (; it != end; ++it)
- os << ',' << from_ascii(*it);
if (package == Encoding::inputenc) {
- if (!encoding_set.empty())
- os << ',';
- os << from_ascii(doc_encoding);
+ // Main language requires (lua)inputenc
+ os << "\\usepackage[" << doc_encoding << "]{"
+ << inputenc_package << "}\n";
+ } else {
+ // We might have an additional language that requires inputenc
+ set<string> encoding_set = features.getEncodingSet(doc_encoding);
+ bool inputenc = false;
+ for (auto const & enc : encoding_set) {
+ if (encodings.fromLaTeXName(enc)
+ && encodings.fromLaTeXName(enc)->package() == Encoding::inputenc) {
+ inputenc = true;
+ break;
+ }
+ }
+ if (inputenc)
+ // load (lua)inputenc without options
+ // (the encoding is loaded later)
+ os << "\\usepackage{" << inputenc_package << "}\n";
}
- if (features.runparams().flavor == Flavor::LuaTeX
- || features.runparams().flavor == Flavor::DviLuaTeX)
- os << "]{luainputenc}\n";
- else
- os << "]{inputenc}\n";
}
} else if (inputenc != "auto-legacy-plain") {
- switch (encoding().package()) {
+ switch (package) {
case Encoding::none:
case Encoding::CJK:
case Encoding::japanese:
if (encoding().iconvName() != "UTF-8"
- && !features.runparams().isFullUnicode())
- // don't default to [utf8]{inputenc} with TeXLive >= 18
- os << "\\ifdefined\\UseRawInputEncoding\n"
- << " \\UseRawInputEncoding\\fi\n";
+ && !features.runparams().isFullUnicode()
+ && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
+ // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
+ os << "\\UseRawInputEncoding\n";
break;
case Encoding::inputenc:
// do not load inputenc if japanese is used
if (features.isRequired("japanese")
|| features.isProvided("inputenc"))
break;
- os << "\\usepackage[" << from_ascii(encoding().latexName());
- if (features.runparams().flavor == Flavor::LuaTeX
- || features.runparams().flavor == Flavor::DviLuaTeX)
- os << "]{luainputenc}\n";
- else
- os << "]{inputenc}\n";
+ // The 2022 release of ucs.sty uses the default utf8
+ // inputenc encoding with 'utf8x' inputenc if the ucs
+ // package is not loaded before inputenc.
+ // This breaks existing documents that use utf8x
+ // and also makes utf8x redundant.
+ // Thus we load ucs.sty in order to keep functionality
+ // that would otherwise be silently dropped.
+ if (doc_encoding == "utf8x"
+ && features.isAvailableAtLeastFrom("ucs", 2022, 8, 7)
+ && !features.isProvided("ucs"))
+ os << "\\usepackage{ucs}\n";
+ os << "\\usepackage[" << doc_encoding << "]{"
+ << inputenc_package << "}\n";
break;
}
}
- if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
- // don't default to [utf8]{inputenc} with TeXLive >= 18
- os << "\\ifdefined\\UseRawInputEncoding\n";
- os << " \\UseRawInputEncoding\\fi\n";
- }
+ if ((inputenc == "auto-legacy-plain" || features.isRequired("japanese"))
+ && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
+ // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
+ os << "\\UseRawInputEncoding\n";
}
// As of 2017/11/03, Babel has its own higher-level
// interface on top of fontspec that is to be used.
bool const babelfonts = features.useBabel()
- && features.isAvailable("babel-2017/11/03");
+ && features.isAvailableAtLeastFrom("babel", 2017, 11, 3);
string const texmapping =
(features.runparams().flavor == Flavor::XeTeX) ?
"Mapping=tex-text" : "Ligatures=TeX";
os << "\\babelfont{rm}[";
else
os << "\\setmainfont[";
- if (!font_roman_opts.empty())
- os << font_roman_opts << ',';
os << texmapping;
if (fonts_roman_osf)
os << ",Numbers=OldStyle";
+ if (!font_roman_opts.empty())
+ os << ',' << font_roman_opts;
os << "]{" << parseFontName(fontsRoman()) << "}\n";
}
if (fontsSans() != "default") {
<< float(fontsSansScale()) / 100 << ',';
if (fonts_sans_osf)
os << "Numbers=OldStyle,";
+ os << texmapping;
if (!font_sans_opts.empty())
- os << font_sans_opts << ',';
- os << texmapping << "]{"
- << sans << "}\n";
+ os << ',' << font_sans_opts;
+ os << "]{" << sans << "}\n";
} else {
if (babelfonts)
os << "\\babelfont{sf}[";
os << "\\setsansfont[";
if (fonts_sans_osf)
os << "Numbers=OldStyle,";
+ os << texmapping;
if (!font_sans_opts.empty())
- os << font_sans_opts << ',';
- os << texmapping << "]{"
- << sans << "}\n";
+ os << ',' << font_sans_opts;
+ os << "]{" << sans << "}\n";
}
}
if (fontsTypewriter() != "default") {
{
string const & lang = bp.language->lang();
setLanguage(lang);
+ quotes_style = bp.quotes_style;
layout_modules_ = bp.layout_modules_;
string const & doc_class = bp.documentClass().name();
setBaseClass(doc_class);
}
+BufferParams const & defaultBufferParams()
+{
+ static BufferParams default_params;
+ return default_params;
+}
+
} // namespace lyx