]> git.lyx.org Git - features.git/commitdiff
Add support for \babelfont
authorJuergen Spitzmueller <spitz@lyx.org>
Thu, 11 Jul 2019 11:21:32 +0000 (13:21 +0200)
committerJean-Marc Lasgouttes <lasgouttes@lyx.org>
Thu, 18 Jun 2020 13:48:35 +0000 (15:48 +0200)
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
lib/lyx2lyx/lyx_2_4.py
src/BufferParams.cpp
src/tex2lyx/Preamble.cpp
src/version.h

index cd66ae72352ce91d95d8da720d8617a3e0d6f499..2f4097c3bf905e54ac6f8a03c16b8c277ee1c487 100644 (file)
@@ -7,6 +7,9 @@ changes happened in particular if possible. A good example would be
 
 -----------------------
 
+2019-07-11  Jürgen Spitzmüller <spitz@lyx.org>
+       * Format incremented to 579: Add support for \babelfont.
+
 2019-06-23  Jürgen Spitzmüller <spitz@lyx.org>
        * Format incremented to 578: Add support for Discourse Representation Structures
           in the Linguistics module (using drs package).
index 5dd9a1bbee2261e9b409e2117abd1a61cd72df11..08490576558e30a73234b7ef54fafc7247278cad 100644 (file)
@@ -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]],
index d98f768b3612f03bf55f243453e7e1d08c28a3b7..d4e2ca4e85c9ab17f446eac5d23777147c4d851d 100644 (file)
@@ -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();
        }
index 5fc5ca06a27142130b029db9ada09f26d7708152..739af0f86cb101924a08411291b9593a3a32ecf3 100644 (file)
@@ -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())
index ce41bf00a92bf60c7f88d551b68df49ab2e12da3..386d72efa80810c00e37fa0cd1c940a8175a5f0f 100644 (file)
@@ -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