From 029adfa28cedf921ee7ee4709422441705d93520 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Mon, 19 Dec 2022 15:15:41 +0100 Subject: [PATCH] Improve LaTeX version checking Instead of having to add and individually test the versions to check for, we store the current version and test on that with a specific function isAvailableAtLeastFrom(package, year, month, day) Currently only used for the LaTeX version, but could also be extended for package versions. --- lib/chkconfig.ltx | 35 +++---------------- src/Buffer.cpp | 2 +- src/BufferParams.cpp | 6 ++-- src/LaTeXFeatures.cpp | 8 ++++- src/LaTeXFeatures.h | 4 +++ src/LaTeXPackages.cpp | 66 ++++++++++++++++++++++++++++++++++-- src/LaTeXPackages.h | 6 +++- src/insets/InsetSpace.cpp | 2 +- src/mathed/InsetMathGrid.cpp | 2 +- 9 files changed, 90 insertions(+), 41 deletions(-) diff --git a/lib/chkconfig.ltx b/lib/chkconfig.ltx index 34f9aff132..a9b82e6e48 100644 --- a/lib/chkconfig.ltx +++ b/lib/chkconfig.ltx @@ -75,8 +75,8 @@ \newcommand{\AddVariable}[2]{ \immediate\write\vars{chk_#1='#2'}} -\newcommand{\AddPackage}[1]{ - \immediate\write\packages{#1}} +\newcommand{\AddPackage}[2][]{ + \immediate\write\packages{#2 #1}} % Tests whether an item is present % Syntax: \TestItem[]{}{}{}{}{} @@ -148,20 +148,6 @@ \fi} -% Test for the LaTeX version -\newcommand{\TestLaTeXVersion}[1]{ - \message{^^J\prefix checking for LaTeX version at least as of #1...} - \@ifl@t@r\fmtversion{#1}{\existstrue}{\existsfalse} - \ifexists - \message{yes^^J} - \AddVariable{#1}{yes} - \AddPackage{LaTeX-#1} - \else - \message{no^^J} - \AddVariable{#1}{no} - \fi} - - % Adapted from ltxcheck.tex \newcommand{\TestFont}[2][\default]{ \def\default{#2} @@ -180,6 +166,7 @@ \fi} \newcommand{\TestPackage}[2][\default]{ + \def\default{#2} \TestItem[#1]{#2}{package}{sty}{\AddPackage{#2}}{}} \newcommand{\TestDocClass}[2]{ @@ -234,20 +221,8 @@ \message{^^J\prefix checking for LaTeX version... \fmtversion} \AddVariable{fmtversion}{\fmtversion} -%%% Crucial versions -% This one introduces \textsubscript -\TestLaTeXVersion{2005/12/01} -% This one introduces \UseRawInputEncoding -\TestLaTeXVersion{2018/04/01} -% This one introduces path encoding changes -\TestLaTeXVersion{2019/10/01} -% This introduces all math and text spaces -% previously only available via amsmath -\TestLaTeXVersion{2020/10/01} -% This robustifies LaTeX commands -\TestLaTeXVersion{2021/06/01} -% Introduction of \\DocumentMetadata -\TestLaTeXVersion{2022/06/01} +%%% Store the current LaTeX version +\AddPackage[\fmtversion]{LaTeX} %%% And now, the list of available languages % The trick is to know that \the\everyjob contains something like diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 34291542e8..94f4dd477c 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -1966,7 +1966,7 @@ Buffer::ExportStatus Buffer::writeLaTeXSource(otexstream & os, docdir = subst(docdir, "~", "\\string~"); bool const nonascii = !isAscii(from_utf8(docdir)); // LaTeX 2019/10/01 handles non-ascii path without detokenize - bool const utfpathlatex = features.isAvailable("LaTeX-2019/10/01"); + bool const utfpathlatex = features.isAvailableAtLeastFrom("LaTeX", 2019, 10); bool const detokenize = !utfpathlatex && nonascii; bool const quote = contains(docdir, ' '); if (utfpathlatex && nonascii) diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 3c55756709..6e9cdd5f00 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -1703,7 +1703,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, 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; @@ -3430,7 +3430,7 @@ void BufferParams::writeEncodingPreamble(otexstream & os, case Encoding::japanese: if (encoding().iconvName() != "UTF-8" && !features.runparams().isFullUnicode() - && features.isAvailable("LaTeX-2018/04/01")) + && features.isAvailableAtLeastFrom("LaTeX", 2018, 4)) // don't default to [utf8]{inputenc} with LaTeX >= 2018/04 os << "\\UseRawInputEncoding\n"; break; @@ -3457,7 +3457,7 @@ void BufferParams::writeEncodingPreamble(otexstream & os, } } if ((inputenc == "auto-legacy-plain" || features.isRequired("japanese")) - && features.isAvailable("LaTeX-2018/04/01")) + && features.isAvailableAtLeastFrom("LaTeX", 2018, 4)) // don't default to [utf8]{inputenc} with LaTeX >= 2018/04 os << "\\UseRawInputEncoding\n"; } diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index 69194b1fee..0bed75a073 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -827,6 +827,12 @@ bool LaTeXFeatures::isAvailable(string const & name) } +bool LaTeXFeatures::isAvailableAtLeastFrom(string const & name, int const y, int const m, int const d) +{ + return LaTeXPackages::isAvailableAtLeastFrom(name, y, m, d); +} + + namespace { void addSnippet(std::list & list, TexString ts, bool allow_dupes) @@ -1514,7 +1520,7 @@ string const LaTeXFeatures::getPackages() const // fixltx2e provides subscript if (mustProvide("subscript") && !isRequired("fixltx2e") - && !isAvailable("LaTeX-2005/12/01")) + && !isAvailableAtLeastFrom("LaTeX", 2005, 12)) packages << "\\usepackage{subscript}\n"; // footmisc must be loaded after setspace diff --git a/src/LaTeXFeatures.h b/src/LaTeXFeatures.h index 91d27e8c70..a19d2ab68a 100644 --- a/src/LaTeXFeatures.h +++ b/src/LaTeXFeatures.h @@ -108,6 +108,10 @@ public: void provide(std::string const & name); /// Is the (required) package available? static bool isAvailable(std::string const & name); + /// Is the (required) package available at least as of version + /// y/m/d? + static bool isAvailableAtLeastFrom(std::string const & name, + int const y, int const m, int const d = 1); /// Has the package been required? bool isRequired(std::string const & name) const; /** Is this feature already provided diff --git a/src/LaTeXPackages.cpp b/src/LaTeXPackages.cpp index a231a2294a..4df2528c2e 100644 --- a/src/LaTeXPackages.cpp +++ b/src/LaTeXPackages.cpp @@ -18,10 +18,13 @@ #include "Lexer.h" +#include "support/convert.h" #include "support/FileName.h" #include "support/filetools.h" #include "support/lstrings.h" +#include + using namespace std; using namespace lyx::support; @@ -55,8 +58,13 @@ void LaTeXPackages::getAvailable() case Lexer::LEX_FEOF: finished = true; break; - default: - packages_.insert(lex.getString()); + default: { + string const p = lex.getString(); + // Parse optional version info + lex.eatLine(); + string const v = lex.getString(); + packages_.insert(make_pair(p, v)); + } } } } @@ -69,7 +77,59 @@ bool LaTeXPackages::isAvailable(string const & name) string n = name; if (suffixIs(n, ".sty")) n.erase(name.length() - 4); - return packages_.find(n) != packages_.end(); + for (auto const & package : packages_) { + if (package.first == n) + return true; + } + return false; +} + + +bool LaTeXPackages::isAvailableAtLeastFrom(string const & name, + int const y, int const m, int const d) +{ + if (packages_.empty()) + getAvailable(); + + bool result = false; + // Check for yyyy-mm-dd + static regex const reg("([\\d]{4})-([\\d]{2})-([\\d]{2})"); + for (auto const & package : packages_) { + if (package.first == name && !package.second.empty()) { + smatch sub; + if (regex_match(package.second, sub, reg)) { + // Test whether date is same or newer. + // + // Test for year first + int const avail_y = convert(sub.str(1)); + if (avail_y < y) + // our year is older: bad! + break; + if (avail_y > y) { + // our year is newer: good! + result = true; + break; + } + // Same year: now test month + int const avail_m = convert(sub.str(2)); + if (avail_m < m) + // our month is older: bad! + break; + if (avail_m > m) { + // our month is newer: good! + result = true; + break; + } + // Same year and month: test day + if (convert(sub.str(3)) >= d) { + // day same or newer: good! + result = true; + break; + } + } + } + } + return result; } } // namespace lyx diff --git a/src/LaTeXPackages.h b/src/LaTeXPackages.h index ff67e0a460..dba6d039f6 100644 --- a/src/LaTeXPackages.h +++ b/src/LaTeXPackages.h @@ -28,9 +28,13 @@ public: static void getAvailable(); /// Is the (required) package available? static bool isAvailable(std::string const & name); + /// Is the (required) package available at least as of + /// version y/m/d? + static bool isAvailableAtLeastFrom(std::string const & name, + int const y, int const m, int const d = 1); private: /// The available (required) packages - typedef std::set Packages; + typedef std::set> Packages; /// static Packages packages_; }; diff --git a/src/insets/InsetSpace.cpp b/src/insets/InsetSpace.cpp index 3f86eb8c07..b7323b6162 100644 --- a/src/insets/InsetSpace.cpp +++ b/src/insets/InsetSpace.cpp @@ -895,7 +895,7 @@ docstring InsetSpace::xhtml(XMLStream & xs, OutputParams const &) const void InsetSpace::validate(LaTeXFeatures & features) const { - if (features.isAvailable("LaTeX-2020/10/01")) + if (features.isAvailableAtLeastFrom("LaTeX", 2020, 10)) // As of this version, the LaTeX kernel // includes all spaces. return; diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp index 85511e6ddf..0061bdd715 100644 --- a/src/mathed/InsetMathGrid.cpp +++ b/src/mathed/InsetMathGrid.cpp @@ -1252,7 +1252,7 @@ void InsetMathGrid::write(TeXMathStream & os, // \\ is a robust command and its protection // is no longer necessary bool const fragile = os.fragile() - && !LaTeXFeatures::isAvailable("LaTeX-2021/06/01"); + && !LaTeXFeatures::isAvailableAtLeastFrom("LaTeX", 2021, 06); for (row_type row = beg_row; row < end_row; ++row) { os << verboseHLine(rowinfo_[row].lines); // don't write & and empty cells at end of line,