commit cb5bd87e9c16f3dc1a774ece4f78d7c63cc4c645
Author: Juergen Spitzmueller <[email protected]>
Date: Thu Jul 11 13:21:32 2019 +0200
Add support for \babelfont
This is a higher-level (non-TeX) font interface of babel that draws on,
but is supposed to be used rather than, fontspec with babel and XeTeX/
LuaTeX.
File format change.
Addresses: #11614
---
development/FORMAT | 3 +
lib/lyx2lyx/lyx_2_4.py | 125 +++++++++++++++++++++++++++++++++++++++++++--
src/BufferParams.cpp | 54 +++++++++++++++----
src/tex2lyx/Preamble.cpp | 51 +++++++++++++++++++
src/version.h | 4 +-
5 files changed, 217 insertions(+), 20 deletions(-)
diff --git a/development/FORMAT b/development/FORMAT
index cd66ae7..2f4097c 100644
--- a/development/FORMAT
+++ b/development/FORMAT
@@ -7,6 +7,9 @@ changes happened in particular if possible. A good example
would be
-----------------------
+2019-07-11 Jürgen Spitzmüller <[email protected]>
+ * Format incremented to 579: Add support for \babelfont.
+
2019-06-23 Jürgen Spitzmüller <[email protected]>
* Format incremented to 578: Add support for Discourse Representation
Structures
in the Linguistics module (using drs package).
diff --git a/lib/lyx2lyx/lyx_2_4.py b/lib/lyx2lyx/lyx_2_4.py
index 5dd9a1b..0849057 100644
--- a/lib/lyx2lyx/lyx_2_4.py
+++ b/lib/lyx2lyx/lyx_2_4.py
@@ -37,11 +37,11 @@ from parser_tools import (count_pars_in_inset, del_token,
find_end_of_inset,
# is_in_inset, set_bool_value
# find_tokens, check_token
-from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble, lyx2latex,
- revert_language, revert_flex_inset)
-# revert_font_attrs, insert_to_preamble, latex_length
+from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble,
insert_to_preamble, lyx2latex,
+ revert_language, revert_flex_inset, str2bool)
+# revert_font_attrs, latex_length
# get_ert, lyx2verbatim, length_in_bp, convert_info_insets
-# revert_flex_inset, hex2ratio, str2bool
+# revert_flex_inset, hex2ratio
####################################################################
# Private helper functions
@@ -2172,6 +2172,117 @@ def revert_drs(document):
i = beginPlain
+
+def revert_babelfont(document):
+ " Reverts the use of \\babelfont to user preamble "
+
+ i = find_token(document.header, '\\use_non_tex_fonts', 0)
+ if i == -1:
+ document.warning("Malformed LyX document: Missing
\\use_non_tex_fonts.")
+ return
+ if not str2bool(get_value(document.header, "\\use_non_tex_fonts", i)):
+ return
+ i = find_token(document.header, '\\language_package', 0)
+ if i == -1:
+ document.warning("Malformed LyX document: Missing \\language_package.")
+ return
+ if get_value(document.header, "\\language_package", 0) != "babel":
+ return
+
+ # check font settings
+ # defaults
+ roman = sans = typew = "default"
+ osf = False
+ sf_scale = tt_scale = 100.0
+
+ j = find_token(document.header, "\\font_roman", 0)
+ if j == -1:
+ document.warning("Malformed LyX document: Missing \\font_roman.")
+ else:
+ # We need to use this regex since split() does not handle quote
protection
+ romanfont = re.findall(r'[^"\s]\S*|".+?"', document.header[j])
+ roman = romanfont[2].strip('"')
+ romanfont[2] = '"default"'
+ document.header[j] = " ".join(romanfont)
+
+ j = find_token(document.header, "\\font_sans", 0)
+ if j == -1:
+ document.warning("Malformed LyX document: Missing \\font_sans.")
+ else:
+ # We need to use this regex since split() does not handle quote
protection
+ sansfont = re.findall(r'[^"\s]\S*|".+?"', document.header[j])
+ sans = sansfont[2].strip('"')
+ sansfont[2] = '"default"'
+ document.header[j] = " ".join(sansfont)
+
+ j = find_token(document.header, "\\font_typewriter", 0)
+ if j == -1:
+ document.warning("Malformed LyX document: Missing \\font_typewriter.")
+ else:
+ # We need to use this regex since split() does not handle quote
protection
+ ttfont = re.findall(r'[^"\s]\S*|".+?"', document.header[j])
+ typew = ttfont[2].strip('"')
+ ttfont[2] = '"default"'
+ document.header[j] = " ".join(ttfont)
+
+ i = find_token(document.header, "\\font_osf", 0)
+ if i == -1:
+ document.warning("Malformed LyX document: Missing \\font_osf.")
+ else:
+ osf = str2bool(get_value(document.header, "\\font_osf", i))
+
+ j = find_token(document.header, "\\font_sf_scale", 0)
+ if j == -1:
+ document.warning("Malformed LyX document: Missing \\font_sf_scale.")
+ else:
+ sfscale = document.header[j].split()
+ val = sfscale[2]
+ sfscale[2] = "100"
+ document.header[j] = " ".join(sfscale)
+ try:
+ # float() can throw
+ sf_scale = float(val)
+ except:
+ document.warning("Invalid font_sf_scale value: " + val)
+
+ j = find_token(document.header, "\\font_tt_scale", 0)
+ if j == -1:
+ document.warning("Malformed LyX document: Missing \\font_tt_scale.")
+ else:
+ ttscale = document.header[j].split()
+ val = ttscale[2]
+ ttscale[2] = "100"
+ document.header[j] = " ".join(ttscale)
+ try:
+ # float() can throw
+ tt_scale = float(val)
+ except:
+ document.warning("Invalid font_tt_scale value: " + val)
+
+ # set preamble stuff
+ pretext = ['%% This document must be processed with xelatex or lualatex!']
+ pretext.append('\\AtBeginDocument{%')
+ if roman != "default":
+ pretext.append('\\babelfont{rm}[Mapping=tex-text]{' + roman + '}')
+ if sans != "default":
+ sf = '\\babelfont{sf}['
+ if sf_scale != 100.0:
+ sf += 'Scale=' + str(sf_scale / 100.0) + ','
+ sf += 'Mapping=tex-text]{' + sans + '}'
+ pretext.append(sf)
+ if typew != "default":
+ tw = '\\babelfont{tt}'
+ if tt_scale != 100.0:
+ tw += '[Scale=' + str(tt_scale / 100.0) + ']'
+ tw += '{' + typew + '}'
+ pretext.append(tw)
+ if osf:
+ pretext.append('\\defaultfontfeatures{Numbers=OldStyle}')
+ pretext.append('}')
+ insert_to_preamble(document, pretext)
+
+
+
##
# Conversion hub
#
@@ -2211,10 +2322,12 @@ convert = [
[575, [convert_lineno]],
[576, []],
[577, [convert_linggloss]],
- [578, []]
+ [578, []],
+ [579, []]
]
-revert = [[577, [revert_drs]],
+revert = [[578, [revert_babelfont]],
+ [577, [revert_drs]],
[576, [revert_linggloss, revert_subexarg]],
[575, [revert_new_languages]],
[574, [revert_lineno]],
diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index d98f768..d4e2ca4 100644
--- a/src/BufferParams.cpp
+++ b/src/BufferParams.cpp
@@ -1763,7 +1763,8 @@ bool BufferParams::writeLaTeX(otexstream & os,
LaTeXFeatures & features,
os << from_ascii(ams);
if (useNonTeXFonts) {
- if (!features.isProvided("fontspec"))
+ // Babel loads fontspec itself
+ if (!features.isProvided("fontspec") && !features.useBabel())
os << "\\usepackage{fontspec}\n";
if (features.mustProvide("unicode-math")
&& features.isAvailable("unicode-math"))
@@ -1781,8 +1782,9 @@ bool BufferParams::writeLaTeX(otexstream & os,
LaTeXFeatures & features,
}
// font selection must be done before loading fontenc.sty
+ // but after babel with non-TeX fonts
string const fonts = loadFonts(features);
- if (!fonts.empty())
+ if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
os << from_utf8(fonts);
if (fonts_default_family != "default")
@@ -2313,6 +2315,10 @@ bool BufferParams::writeLaTeX(otexstream & os,
LaTeXFeatures & features,
if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
writeEncodingPreamble(os, features);
+ // font selection must be done after babel with non-TeX fonts
+ if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
+ os << from_utf8(fonts);
+
if (features.isRequired("bicaption"))
os << "\\usepackage{bicaption}\n";
if (!listings_params.empty()
@@ -3391,36 +3397,60 @@ string const BufferParams::loadFonts(LaTeXFeatures &
features) const
// variants are understood by both engines. However,
// we want to provide support for at least TeXLive 2009
// (for XeTeX; LuaTeX is only supported as of v.2)
+ // Babel has its own higher-level interface on top of
+ // fontspec that is to be used.
+ bool const babel = features.useBabel();
string const texmapping =
(features.runparams().flavor == OutputParams::XETEX) ?
"Mapping=tex-text" : "Ligatures=TeX";
if (fontsRoman() != "default") {
- os << "\\setmainfont[" << texmapping;
+ if (babel)
+ os << "\\babelfont{rm}[";
+ else
+ os << "\\setmainfont[";
+ os << texmapping;
if (fonts_old_figures)
os << ",Numbers=OldStyle";
os << "]{" << parseFontName(fontsRoman()) << "}\n";
}
if (fontsSans() != "default") {
string const sans = parseFontName(fontsSans());
- if (fontsSansScale() != 100)
- os << "\\setsansfont[Scale="
+ if (fontsSansScale() != 100) {
+ if (babel)
+ os << "\\babelfont{sf}";
+ else
+ os << "\\setsansfont";
+ os << "[Scale="
<< float(fontsSansScale()) / 100
<< "," << texmapping << "]{"
<< sans << "}\n";
- else
- os << "\\setsansfont[" << texmapping << "]{"
+ } else {
+ if (babel)
+ os << "\\babelfont{sf}[";
+ else
+ os << "\\setsansfont[";
+ os << texmapping << "]{"
<< sans << "}\n";
+ }
}
if (fontsTypewriter() != "default") {
string const mono = parseFontName(fontsTypewriter());
- if (fontsTypewriterScale() != 100)
- os << "\\setmonofont[Scale="
+ if (fontsTypewriterScale() != 100) {
+ if (babel)
+ os << "\\babelfont{tt}";
+ else
+ os << "\\setmonofont";
+ os << "[Scale="
<< float(fontsTypewriterScale()) / 100
<< "]{"
<< mono << "}\n";
- else
- os << "\\setmonofont{"
- << mono << "}\n";
+ } else {
+ if (babel)
+ os << "\\babelfont{tt}{";
+ else
+ os << "\\setmonofont{";
+ os << mono << "}\n";
+ }
}
return os.str();
}
diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp
index 5fc5ca0..739af0f 100644
--- a/src/tex2lyx/Preamble.cpp
+++ b/src/tex2lyx/Preamble.cpp
@@ -1716,6 +1716,57 @@ void Preamble::parse(Parser & p, string const &
forceclass,
continue;
}
+ if (t.cs() == "babelfont") {
+ xetex = true;
+ h_use_non_tex_fonts = true;
+ h_language_package = "babel";
+ if (h_inputencoding == "auto-legacy")
+ p.setEncoding("UTF-8");
+ // we don't care about the lang option
+ string const lang = p.hasOpt() ? p.getArg('[', ']') :
string();
+ string const family = p.getArg('{', '}');
+ string const fontopts = p.hasOpt() ? p.getArg('[', ']')
: string();
+ string const fontname = p.getArg('{', '}');
+ if (lang.empty() && family == "rm") {
+ h_font_roman[1] = fontname;
+ continue;
+ } else if (lang.empty() && (family == "sf" || family ==
"tt")) {
+ // LyX currently only supports the scale option
+ string scale;
+ if (!fontopts.empty()) {
+ // check if the option contains a
scaling, if yes, extract it
+ string::size_type pos =
fontopts.find("Scale");
+ if (pos != string::npos) {
+ string::size_type i =
fontopts.find(',', pos);
+ if (i == string::npos)
+
scale_as_percentage(fontopts.substr(pos + 1), scale);
+ else
+
scale_as_percentage(fontopts.substr(pos, i - pos), scale);
+ }
+ }
+ if (family == "sf") {
+ if (!scale.empty())
+ h_font_sf_scale[1] = scale;
+ h_font_sans[1] = fontname;
+ } else {
+ if (!scale.empty())
+ h_font_tt_scale[1] = scale;
+ h_font_typewriter[1] = fontname;
+ }
+ continue;
+ } else {
+ // not rm, sf or tt or lang specific
+ h_preamble << '\\' << t.cs();
+ if (!lang.empty())
+ h_preamble << '[' << lang << ']';
+ h_preamble << '{' << family << '}';
+ if (!fontopts.empty())
+ h_preamble << '[' << fontopts << ']';
+ h_preamble << '{' << fontname << '}' << '\n';
+ continue;
+ }
+ }
+
if (t.cs() == "date") {
string argument = p.getArg('{', '}');
if (argument.empty())
diff --git a/src/version.h b/src/version.h
index ce41bf0..386d72e 100644
--- a/src/version.h
+++ b/src/version.h
@@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
// Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own.
-#define LYX_FORMAT_LYX 578 // spitz: drs
-#define LYX_FORMAT_TEX2LYX 578
+#define LYX_FORMAT_LYX 579 // spitz: babelfont
+#define LYX_FORMAT_TEX2LYX 579
#if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
#ifndef _MSC_VER