tex2lyx: support for \includeonly

This commit is contained in:
Juergen Spitzmueller 2018-03-09 17:27:55 +01:00
parent 3d0ce01ff1
commit 15fd17d83f
5 changed files with 152 additions and 108 deletions

View File

@ -173,6 +173,11 @@ const char * const known_basic_color_codes[] = {"#000000", "#0000ff", "#964B00",
const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists",
0};
/*!
* Known file extensions for TeX files as used by \\includeonly
*/
char const * const known_tex_extensions[] = {"tex", 0};
/// packages that work only in xetex
/// polyglossia is handled separately
const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian",
@ -1252,6 +1257,12 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled
os << *it << '\n';
os << "\\end_modules\n";
}
if (!h_includeonlys.empty()) {
os << "\\begin_includeonly\n";
for (auto const & iofile : h_includeonlys)
os << iofile << '\n';
os << "\\end_includeonly\n";
}
os << "\\maintain_unincluded_children " << h_maintain_unincluded_children << "\n"
<< "\\language " << h_language << "\n"
<< "\\language_package " << h_language_package << "\n"
@ -2040,6 +2051,33 @@ void Preamble::parse(Parser & p, string const & forceclass,
}
}
if (t.cs() == "includeonly") {
vector<string> includeonlys = getVectorFromString(p.getArg('{', '}'));
for (auto & iofile : includeonlys) {
string filename(normalize_filename(iofile));
string const path = getMasterFilePath(true);
// We want to preserve relative/absolute filenames,
// therefore path is only used for testing
if (!makeAbsPath(filename, path).exists()) {
// The file extension is probably missing.
// Now try to find it out.
string const tex_name =
find_file(filename, path,
known_tex_extensions);
if (!tex_name.empty())
filename = tex_name;
}
string outname;
if (makeAbsPath(filename, path).exists())
fix_child_filename(filename);
else
cerr << "Warning: Could not find included file '"
<< filename << "'." << endl;
outname = changeExtension(filename, "lyx");
h_includeonlys.push_back(outname);
}
}
else if (is_known(t.cs(), known_if_3arg_commands)) {
// prevent misparsing of \usepackage if it is used
// as an argument (see e.g. our own output of

View File

@ -223,6 +223,7 @@ private:
std::map<std::string, std::string> h_use_packages;
std::string h_use_default_options;
std::string h_use_hyperref;
std::vector<std::string> h_includeonlys;
bool h_use_refstyle;
bool h_use_minted;

View File

@ -39,8 +39,6 @@ Format LaTeX feature LyX feature
363 horizontal longtable alignment InsetTabular
364 branch file name suffix \filename_suffix
371 automatic mhchem loading \use_mhchem
375 \includeonly \{begin,end}_includeonly
376 update .aux of unincluded children \maintain_unincluded_children
377 multirow.sty InsetTabular
378 revision info InsetInfo
380 ? InsetPreview

View File

@ -51,6 +51,13 @@ void parse_text(Parser & p, std::ostream & os, unsigned flags, bool outer,
Context & context);
void check_comment_bib(std::ostream & os, Context & context);
void fix_child_filename(std::string & name);
std::string const normalize_filename(std::string const & name);
std::string find_file(std::string const & name, std::string const & path,
char const * const * extensions);
/*!
* Parses a subdocument, usually useful in insets (whence the name).
*

View File

@ -482,22 +482,6 @@ void translate_box_len(string const & length, string & value, string & unit, str
}
/*!
* Find a file with basename \p name in path \p path and an extension
* in \p extensions.
*/
string find_file(string const & name, string const & path,
char const * const * extensions)
{
for (char const * const * what = extensions; *what; ++what) {
string const trial = addExtension(name, *what);
if (makeAbsPath(trial, path).exists())
return trial;
}
return string();
}
void begin_inset(ostream & os, string const & name)
{
os << "\n\\begin_inset " << name;
@ -2194,96 +2178,6 @@ void get_cite_arguments(Parser & p, bool natbibOrder,
}
/// Convert filenames with TeX macros and/or quotes to something LyX
/// can understand
string const normalize_filename(string const & name)
{
Parser p(name);
ostringstream os;
while (p.good()) {
Token const & t = p.get_token();
if (t.cat() != catEscape)
os << t.asInput();
else if (t.cs() == "lyxdot") {
// This is used by LyX for simple dots in relative
// names
os << '.';
p.skip_spaces();
} else if (t.cs() == "space") {
os << ' ';
p.skip_spaces();
} else if (t.cs() == "string") {
// Convert \string" to " and \string~ to ~
Token const & n = p.next_token();
if (n.asInput() != "\"" && n.asInput() != "~")
os << t.asInput();
} else
os << t.asInput();
}
// Strip quotes. This is a bit complicated (see latex_path()).
string full = os.str();
if (!full.empty() && full[0] == '"') {
string base = removeExtension(full);
string ext = getExtension(full);
if (!base.empty() && base[base.length()-1] == '"')
// "a b"
// "a b".tex
return addExtension(trim(base, "\""), ext);
if (full[full.length()-1] == '"')
// "a b.c"
// "a b.c".tex
return trim(full, "\"");
}
return full;
}
/// Convert \p name from TeX convention (relative to master file) to LyX
/// convention (relative to .lyx file) if it is relative
void fix_child_filename(string & name)
{
string const absMasterTeX = getMasterFilePath(true);
bool const isabs = FileName::isAbsolute(name);
// convert from "relative to .tex master" to absolute original path
if (!isabs)
name = makeAbsPath(name, absMasterTeX).absFileName();
bool copyfile = copyFiles();
string const absParentLyX = getParentFilePath(false);
string abs = name;
if (copyfile) {
// convert from absolute original path to "relative to master file"
string const rel = to_utf8(makeRelPath(from_utf8(name),
from_utf8(absMasterTeX)));
// re-interpret "relative to .tex file" as "relative to .lyx file"
// (is different if the master .lyx file resides in a
// different path than the master .tex file)
string const absMasterLyX = getMasterFilePath(false);
abs = makeAbsPath(rel, absMasterLyX).absFileName();
// Do not copy if the new path is impossible to create. Example:
// absMasterTeX = "/foo/bar/"
// absMasterLyX = "/bar/"
// name = "/baz.eps" => new absolute name would be "/../baz.eps"
if (contains(name, "/../"))
copyfile = false;
}
if (copyfile) {
if (isabs)
name = abs;
else {
// convert from absolute original path to
// "relative to .lyx file"
name = to_utf8(makeRelPath(from_utf8(abs),
from_utf8(absParentLyX)));
}
}
else if (!isabs) {
// convert from absolute original path to "relative to .lyx file"
name = to_utf8(makeRelPath(from_utf8(name),
from_utf8(absParentLyX)));
}
}
void copy_file(FileName const & src, string dstname)
{
if (!copyFiles())
@ -2508,6 +2402,112 @@ void registerExternalTemplatePackages(string const & name)
} // anonymous namespace
/*!
* Find a file with basename \p name in path \p path and an extension
* in \p extensions.
*/
string find_file(string const & name, string const & path,
char const * const * extensions)
{
for (char const * const * what = extensions; *what; ++what) {
string const trial = addExtension(name, *what);
if (makeAbsPath(trial, path).exists())
return trial;
}
return string();
}
/// Convert filenames with TeX macros and/or quotes to something LyX
/// can understand
string const normalize_filename(string const & name)
{
Parser p(name);
ostringstream os;
while (p.good()) {
Token const & t = p.get_token();
if (t.cat() != catEscape)
os << t.asInput();
else if (t.cs() == "lyxdot") {
// This is used by LyX for simple dots in relative
// names
os << '.';
p.skip_spaces();
} else if (t.cs() == "space") {
os << ' ';
p.skip_spaces();
} else if (t.cs() == "string") {
// Convert \string" to " and \string~ to ~
Token const & n = p.next_token();
if (n.asInput() != "\"" && n.asInput() != "~")
os << t.asInput();
} else
os << t.asInput();
}
// Strip quotes. This is a bit complicated (see latex_path()).
string full = os.str();
if (!full.empty() && full[0] == '"') {
string base = removeExtension(full);
string ext = getExtension(full);
if (!base.empty() && base[base.length()-1] == '"')
// "a b"
// "a b".tex
return addExtension(trim(base, "\""), ext);
if (full[full.length()-1] == '"')
// "a b.c"
// "a b.c".tex
return trim(full, "\"");
}
return full;
}
/// Convert \p name from TeX convention (relative to master file) to LyX
/// convention (relative to .lyx file) if it is relative
void fix_child_filename(string & name)
{
string const absMasterTeX = getMasterFilePath(true);
bool const isabs = FileName::isAbsolute(name);
// convert from "relative to .tex master" to absolute original path
if (!isabs)
name = makeAbsPath(name, absMasterTeX).absFileName();
bool copyfile = copyFiles();
string const absParentLyX = getParentFilePath(false);
string abs = name;
if (copyfile) {
// convert from absolute original path to "relative to master file"
string const rel = to_utf8(makeRelPath(from_utf8(name),
from_utf8(absMasterTeX)));
// re-interpret "relative to .tex file" as "relative to .lyx file"
// (is different if the master .lyx file resides in a
// different path than the master .tex file)
string const absMasterLyX = getMasterFilePath(false);
abs = makeAbsPath(rel, absMasterLyX).absFileName();
// Do not copy if the new path is impossible to create. Example:
// absMasterTeX = "/foo/bar/"
// absMasterLyX = "/bar/"
// name = "/baz.eps" => new absolute name would be "/../baz.eps"
if (contains(name, "/../"))
copyfile = false;
}
if (copyfile) {
if (isabs)
name = abs;
else {
// convert from absolute original path to
// "relative to .lyx file"
name = to_utf8(makeRelPath(from_utf8(abs),
from_utf8(absParentLyX)));
}
}
else if (!isabs) {
// convert from absolute original path to "relative to .lyx file"
name = to_utf8(makeRelPath(from_utf8(name),
from_utf8(absParentLyX)));
}
}
void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
Context & context)
{