X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Ftex2lyx%2Ftext.cpp;h=e083e39ec8a147e8104186f1e8167e3e31103722;hb=d09f87c3ca895e53ff77ca47918778e257826806;hp=71d36a56befa72afe432ede42035bd7ac2ef04aa;hpb=76c5902b4060e0a15b6c23dff273ad6721a9ac69;p=lyx.git diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 71d36a56be..e083e39ec8 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -24,6 +24,8 @@ #include "Length.h" #include "Preamble.h" +#include "insets/ExternalTemplate.h" + #include "support/lassert.h" #include "support/convert.h" #include "support/FileName.h" @@ -455,8 +457,11 @@ docstring convert_unicodesymbols(docstring s) } s = s.substr(i); docstring rem; - docstring parsed = encodings.fromLaTeXCommand(s, rem, - Encodings::TEXT_CMD); + set req; + docstring parsed = encodings.fromLaTeXCommand(s, + Encodings::TEXT_CMD, rem, &req); + for (set::const_iterator it = req.begin(); it != req.end(); it++) + preamble.registerAutomaticallyLoadedPackage(*it); os << parsed; s = rem; if (s.empty() || s[0] != '\\') @@ -564,7 +569,7 @@ void skip_spaces_braces(Parser & p, bool keepws = false) should be handled by this function: - abc \j{} xyz - abc \j {} xyz - - abc \j + - abc \j {} xyz - abc \j %comment {} xyz @@ -608,7 +613,7 @@ void output_command_layout(ostream & os, Parser & p, bool outer, while (optargs < context.layout->optargs) { eat_whitespace(p, os, context, false); if (p.next_token().cat() == catEscape || - p.next_token().character() != '[') + p.next_token().character() != '[') break; p.get_token(); // eat '[' begin_inset(os, "Argument\n"); @@ -925,7 +930,7 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, // the inner env if (!inner_type.empty() && (inner_flags & FLAG_END)) active_environments.pop_back(); - + // Ensure that the end of the outer box is parsed correctly: // The opening brace has been eaten by parse_outer_box() if (!outer_type.empty() && (outer_flags & FLAG_ITEM)) { @@ -1113,16 +1118,35 @@ void parse_outer_box(Parser & p, ostream & os, unsigned flags, bool outer, } -void parse_listings(Parser & p, ostream & os, Context & parent_context) +void parse_listings(Parser & p, ostream & os, Context & parent_context, bool in_line) { parent_context.check_layout(os); begin_inset(os, "listings\n"); - os << "inline false\n" - << "status collapsed\n"; + if (p.hasOpt()) { + // there can be a [] pair inside the argument for the language + string arg = p.getArg('[', ']'); + if (arg.find("language={[") != string::npos) { + char start = p.next_token().character(); + arg += ']'; + arg += start; + arg += p.getArg(start, ']'); + } + os << "lstparams " << '"' << arg << '"' << '\n'; + } + if (in_line) + os << "inline true\n"; + else + os << "inline false\n"; + os << "status collapsed\n"; Context context(true, parent_context.textclass); context.layout = &parent_context.textclass.plainLayout(); - context.check_layout(os); - string const s = p.verbatimEnvironment("lstlisting"); + string s; + if (in_line) { + s = p.plainCommand('!', '!', "lstinline"); + context.new_paragraph(os); + context.check_layout(os); + } else + s = p.plainEnvironment("lstlisting"); for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) { if (*it == '\\') os << "\n\\backslash\n"; @@ -1223,6 +1247,15 @@ void parse_environment(Parser & p, ostream & os, bool outer, float_type = ""; if (!opt.empty()) os << "placement " << opt << '\n'; + if (contains(opt, "H")) + preamble.registerAutomaticallyLoadedPackage("float"); + else { + Floating const & fl = parent_context.textclass.floats() + .getType(unstarred_name); + if (!fl.floattype().empty() && fl.usesFloatPkg()) + preamble.registerAutomaticallyLoadedPackage("float"); + } + os << "wide " << convert(is_starred) << "\nsideways false" << "\nstatus open\n\n"; @@ -1253,6 +1286,7 @@ void parse_environment(Parser & p, ostream & os, bool outer, // we must make sure that the next item gets a \begin_layout. parent_context.new_paragraph(os); p.skip_spaces(); + preamble.registerAutomaticallyLoadedPackage("rotfloat"); } else if (name == "wrapfigure" || name == "wraptable") { @@ -1285,6 +1319,7 @@ void parse_environment(Parser & p, ostream & os, bool outer, // we must make sure that the next item gets a \begin_layout. parent_context.new_paragraph(os); p.skip_spaces(); + preamble.registerAutomaticallyLoadedPackage("wrapfig"); } else if (name == "minipage") { @@ -1324,6 +1359,31 @@ void parse_environment(Parser & p, ostream & os, bool outer, end_inset(os); p.skip_spaces(); skip_braces(p); // eat {} that might by set by LyX behind comments + preamble.registerAutomaticallyLoadedPackage("verbatim"); + } + + else if (name == "verbatim") { + os << "\n\\end_layout\n\n\\begin_layout Verbatim\n"; + string const s = p.plainEnvironment("verbatim"); + string::const_iterator it2 = s.begin(); + for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) { + if (*it == '\\') + os << "\\backslash "; + else if (*it == '\n') { + it2 = it + 1; + // avoid adding an empty paragraph at the end + // FIXME: if there are 2 consecutive spaces at the end ignore it + // because LyX will re-add a \n + // This hack must be removed once bug 8049 is fixed! + if ((it + 1 != et) && (it + 2 != et || *it2 != '\n')) + os << "\n\\end_layout\n\\begin_layout Verbatim\n"; + } else + os << *it; + } + os << "\n\\end_layout\n\n"; + p.skip_spaces(); + // reset to Standard layout + os << "\n\\begin_layout Standard\n"; } else if (name == "lyxgreyedout") { @@ -1346,14 +1406,9 @@ void parse_environment(Parser & p, ostream & os, bool outer, else if (name == "lstlisting") { eat_whitespace(p, os, parent_context, false); - // FIXME handle listings with parameters - // If this is added, don't forgot to handle the - // automatic color package loading - if (p.hasOpt()) - parse_unknown_environment(p, name, os, FLAG_END, - outer, parent_context); - else - parse_listings(p, os, parent_context); + // FIXME handle the automatic color package loading + // uwestoehr asks: In what case color is loaded? + parse_listings(p, os, parent_context, false); p.skip_spaces(); } @@ -1386,12 +1441,16 @@ void parse_environment(Parser & p, ostream & os, bool outer, parent_context.add_extra_stuff("\\align center\n"); else if (name == "singlespace") parent_context.add_extra_stuff("\\paragraph_spacing single\n"); - else if (name == "onehalfspace") + else if (name == "onehalfspace") { parent_context.add_extra_stuff("\\paragraph_spacing onehalf\n"); - else if (name == "doublespace") + preamble.registerAutomaticallyLoadedPackage("setspace"); + } else if (name == "doublespace") { parent_context.add_extra_stuff("\\paragraph_spacing double\n"); - else if (name == "spacing") + preamble.registerAutomaticallyLoadedPackage("setspace"); + } else if (name == "spacing") { parent_context.add_extra_stuff("\\paragraph_spacing other " + p.verbatim_item() + "\n"); + preamble.registerAutomaticallyLoadedPackage("setspace"); + } parse_text(p, os, FLAG_END, outer, parent_context); // Just in case the environment is empty parent_context.extra_stuff.erase(); @@ -1459,7 +1518,7 @@ void parse_environment(Parser & p, ostream & os, bool outer, while (optargs < context.layout->optargs) { eat_whitespace(p, os, context, false); if (p.next_token().cat() == catEscape || - p.next_token().character() != '[') + p.next_token().character() != '[') break; p.get_token(); // eat '[' if (need_layout) { @@ -1503,6 +1562,9 @@ void parse_environment(Parser & p, ostream & os, bool outer, p.skip_spaces(); if (!title_layout_found) title_layout_found = newlayout->intitle; + set const & req = newlayout->requires(); + for (set::const_iterator it = req.begin(); it != req.end(); it++) + preamble.registerAutomaticallyLoadedPackage(*it); } // The single '=' is meant here. @@ -1877,6 +1939,28 @@ void parse_macro(Parser & p, ostream & os, Context & context) handle_ert(os, command + ert, context); } + +void registerExternalTemplatePackages(string const & name) +{ + external::TemplateManager const & etm = external::TemplateManager::get(); + external::Template const * const et = etm.getTemplateByName(name); + if (!et) + return; + external::Template::Formats::const_iterator cit = et->formats.end(); + if (pdflatex) + cit = et->formats.find("PDFLaTeX"); + if (cit == et->formats.end()) + // If the template has not specified a PDFLaTeX output, + // we try the LaTeX format. + cit = et->formats.find("LaTeX"); + if (cit == et->formats.end()) + return; + vector::const_iterator qit = cit->second.requirements.begin(); + vector::const_iterator qend = cit->second.requirements.end(); + for (; qit != qend; ++qit) + preamble.registerAutomaticallyLoadedPackage(*qit); +} + } // anonymous namespace @@ -1889,7 +1973,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // Store the latest bibliographystyle and nocite{*} option // (needed for bibtex inset) string btprint; - string bibliographystyle; + string bibliographystyle = "default"; bool const use_natbib = preamble.isPackageUsed("natbib"); bool const use_jurabib = preamble.isPackageUsed("jurabib"); string last_env; @@ -2241,7 +2325,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // FIXME: This swallows comments, but we cannot use // eat_whitespace() since we must not output // anything before the item. - s = p.getArg('[', ']'); + p.skip_spaces(true); + s = p.verbatimOption(); } else p.skip_spaces(false); context.set_item(); @@ -2291,7 +2376,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else if (t.cs() == "bibitem") { context.set_item(); context.check_layout(os); - string label = convert_command_inset_arg(p.getArg('[', ']')); + eat_whitespace(p, os, context, false); + string label = convert_command_inset_arg(p.verbatimOption()); string key = convert_command_inset_arg(p.verbatim_item()); if (contains(label, '\\') || contains(key, '\\')) { // LyX can't handle LaTeX commands in labels or keys @@ -2308,20 +2394,29 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else if (is_macro(p)) { // catch the case of \def\inputGnumericTable + bool macro = true; if (t.cs() == "def") { - Token second = p.get_token(); + Token second = p.next_token(); if (second.cs() == "inputGnumericTable") { + p.pushPosition(); + p.get_token(); skip_braces(p); Token third = p.get_token(); + p.popPosition(); if (third.cs() == "input") { + p.get_token(); + skip_braces(p); + p.get_token(); string name = normalize_filename(p.verbatim_item()); string const path = getMasterFilePath(); // We want to preserve relative / absolute filenames, // therefore path is only used for testing + // The file extension is in every case ".tex". + // So we need to remove this extension and check for + // the original one. + name = removeExtension(name); if (!makeAbsPath(name, path).exists()) { - // The file extension is probably missing. - // Now try to find it out. - char const * const Gnumeric_formats[] = {"gnumeric" + char const * const Gnumeric_formats[] = {"gnumeric", "ods", "xls", 0}; string const Gnumeric_name = find_file(name, path, Gnumeric_formats); @@ -2339,10 +2434,14 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, << name << "\n"; end_inset(os); context.check_layout(os); + macro = false; + // register the packages that are automatically reloaded + // by the Gnumeric template + registerExternalTemplatePackages("GnumericSpreadsheet"); } } } - if (is_macro(p)) + if (macro) parse_macro(p, os, context); } @@ -2390,6 +2489,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.skip_spaces(); if (!title_layout_found) title_layout_found = newlayout->intitle; + set const & req = newlayout->requires(); + for (set::const_iterator it = req.begin(); + it != req.end(); it++) + preamble.registerAutomaticallyLoadedPackage(*it); } else handle_ert(os, "\\date{" + date + '}', context); @@ -2407,6 +2510,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.skip_spaces(); if (!title_layout_found) title_layout_found = newlayout->intitle; + set const & req = newlayout->requires(); + for (set::const_iterator it = req.begin(); it != req.end(); it++) + preamble.registerAutomaticallyLoadedPackage(*it); } // Section headings and the like @@ -2417,6 +2523,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.skip_spaces(); if (!title_layout_found) title_layout_found = newlayout->intitle; + set const & req = newlayout->requires(); + for (set::const_iterator it = req.begin(); it != req.end(); it++) + preamble.registerAutomaticallyLoadedPackage(*it); } else if (t.cs() == "caption") { @@ -2665,6 +2774,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // Warn about invalid options. // Check whether some option was given twice. end_inset(os); + preamble.registerAutomaticallyLoadedPackage("graphicx"); } else if (t.cs() == "footnote" || @@ -2686,6 +2796,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); } + else if (t.cs() == "lstinline") { + p.skip_spaces(); + parse_listings(p, os, context, true); + } + else if (t.cs() == "ensuremath") { p.skip_spaces(); context.check_layout(os); @@ -2906,7 +3021,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); skip_spaces_braces(p); } - + else if (t.cs() == "lyxline") { // swallow size argument (it is not used anyway) p.getArg('{', '}'); @@ -2971,6 +3086,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, << convert_command_inset_arg(p.verbatim_item()) << "\"\n"; end_inset(os); + if (t.cs() == "vref" || t.cs() == "vpageref") + preamble.registerAutomaticallyLoadedPackage("varioref"); + } else { // LyX does not support optional arguments of ref commands handle_ert(os, t.asInput() + '[' + opt + "]{" + @@ -3103,12 +3221,18 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, btprint = key; } - else if (t.cs() == "index") { + else if (t.cs() == "index" || + (t.cs() == "sindex" && preamble.use_indices() == "true")) { context.check_layout(os); - begin_inset(os, "Index idx\n"); - os << "status collapsed\n"; + string const arg = (t.cs() == "sindex" && p.hasOpt()) ? + p.getArg('[', ']') : ""; + string const kind = arg.empty() ? "idx" : arg; + begin_inset(os, "Index "); + os << kind << "\nstatus collapsed\n"; parse_text_in_inset(p, os, FLAG_ITEM, false, context, "Index"); end_inset(os); + if (kind != "idx") + preamble.registerAutomaticallyLoadedPackage("splitidx"); } else if (t.cs() == "nomenclature") { @@ -3123,8 +3247,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, << convert_command_inset_arg(p.verbatim_item()) << "\"\n"; end_inset(os); + preamble.registerAutomaticallyLoadedPackage("nomencl"); } - + else if (t.cs() == "label") { context.check_layout(os); begin_command_inset(os, "label", "label"); @@ -3140,6 +3265,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "type \"idx\"\n"; end_inset(os); skip_spaces_braces(p); + preamble.registerAutomaticallyLoadedPackage("makeidx"); + if (preamble.use_indices() == "true") + preamble.registerAutomaticallyLoadedPackage("splitidx"); } else if (t.cs() == "printnomenclature") { @@ -3166,6 +3294,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "width \"" << width << '\"'; end_inset(os); skip_spaces_braces(p); + preamble.registerAutomaticallyLoadedPackage("nomencl"); } else if ((t.cs() == "textsuperscript" || t.cs() == "textsubscript")) { @@ -3267,7 +3396,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else if (t.cs() == "selectlanguage") { context.check_layout(os); // save the language for the case that a - // \foreignlanguage is used + // \foreignlanguage is used context.font.language = babel2lyx(p.verbatim_item()); os << "\n\\lang " << context.font.language << "\n"; @@ -3374,21 +3503,25 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, handle_ert(os, t.asInput(), context); // accents (see Table 6 in Comprehensive LaTeX Symbol List) - else if (t.cs().size() == 1 + else if (t.cs().size() == 1 && contains("\"'.=^`bcdHkrtuv~", t.cs())) { context.check_layout(os); // try to see whether the string is in unicodesymbols docstring rem; - string command = t.asInput() + "{" + string command = t.asInput() + "{" + trimSpaceAndEol(p.verbatim_item()) + "}"; - docstring s = encodings.fromLaTeXCommand(from_utf8(command), rem); + set req; + docstring s = encodings.fromLaTeXCommand(from_utf8(command), + Encodings::TEXT_CMD | Encodings::MATH_CMD, rem, &req); if (!s.empty()) { if (!rem.empty()) - cerr << "When parsing " << command + cerr << "When parsing " << command << ", result is " << to_utf8(s) << "+" << to_utf8(rem) << endl; os << to_utf8(s); + for (set::const_iterator it = req.begin(); it != req.end(); it++) + preamble.registerAutomaticallyLoadedPackage(*it); } else // we did not find a non-ert version handle_ert(os, command, context); @@ -3518,10 +3651,13 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, begin_inset(os, "External\n"); os << "\ttemplate XFig\n" << "\tfilename " << outname << '\n'; + registerExternalTemplatePackages("XFig"); } else { begin_command_inset(os, "include", name); os << "preview false\n" "filename \"" << outname << "\"\n"; + if (t.cs() == "verbatiminput") + preamble.registerAutomaticallyLoadedPackage("verbatim"); } end_inset(os); } @@ -3872,6 +4008,75 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); } + else if (t.cs() == "includepdf") { + p.skip_spaces(); + string const arg = p.getArg('[', ']'); + map opts; + vector keys; + split_map(arg, opts, keys); + string name = normalize_filename(p.verbatim_item()); + string const path = getMasterFilePath(); + // We want to preserve relative / absolute filenames, + // therefore path is only used for testing + if (!makeAbsPath(name, path).exists()) { + // The file extension is probably missing. + // Now try to find it out. + char const * const pdfpages_format[] = {"pdf", 0}; + string const pdftex_name = + find_file(name, path, pdfpages_format); + if (!pdftex_name.empty()) { + name = pdftex_name; + pdflatex = true; + } + } + if (makeAbsPath(name, path).exists()) + fix_relative_filename(name); + else + cerr << "Warning: Could not find file '" + << name << "'." << endl; + // write output + context.check_layout(os); + begin_inset(os, "External\n\ttemplate "); + os << "PDFPages\n\tfilename " + << name << "\n"; + // parse the options + if (opts.find("pages") != opts.end()) + os << "\textra LaTeX \"pages=" + << opts["pages"] << "\"\n"; + if (opts.find("angle") != opts.end()) + os << "\trotateAngle " + << opts["angle"] << '\n'; + if (opts.find("origin") != opts.end()) { + ostringstream ss; + string const opt = opts["origin"]; + if (opt == "tl") ss << "topleft"; + if (opt == "bl") ss << "bottomleft"; + if (opt == "Bl") ss << "baselineleft"; + if (opt == "c") ss << "center"; + if (opt == "tc") ss << "topcenter"; + if (opt == "bc") ss << "bottomcenter"; + if (opt == "Bc") ss << "baselinecenter"; + if (opt == "tr") ss << "topright"; + if (opt == "br") ss << "bottomright"; + if (opt == "Br") ss << "baselineright"; + if (!ss.str().empty()) + os << "\trotateOrigin " << ss.str() << '\n'; + else + cerr << "Warning: Ignoring unknown includegraphics origin argument '" << opt << "'\n"; + } + if (opts.find("width") != opts.end()) + os << "\twidth " + << translate_len(opts["width"]) << '\n'; + if (opts.find("height") != opts.end()) + os << "\theight " + << translate_len(opts["height"]) << '\n'; + if (opts.find("keepaspectratio") != opts.end()) + os << "\tkeepAspectRatio\n"; + end_inset(os); + context.check_layout(os); + registerExternalTemplatePackages("PDFPages"); + } + else if (t.cs() == "loadgame") { p.skip_spaces(); string name = normalize_filename(p.verbatim_item()); @@ -3901,6 +4106,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // after a \loadgame follows a \showboard if (p.get_token().asInput() == "showboard") p.get_token(); + registerExternalTemplatePackages("ChessDiagram"); } else { @@ -3908,16 +4114,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // Only use text mode commands, since we are in text mode here, // and math commands may be invalid (bug 6797) docstring rem; + set req; docstring s = encodings.fromLaTeXCommand(from_utf8(t.asInput()), - rem, Encodings::TEXT_CMD); + Encodings::TEXT_CMD, rem, &req); if (!s.empty()) { if (!rem.empty()) - cerr << "When parsing " << t.cs() + cerr << "When parsing " << t.cs() << ", result is " << to_utf8(s) << "+" << to_utf8(rem) << endl; context.check_layout(os); os << to_utf8(s); skip_spaces_braces(p); + for (set::const_iterator it = req.begin(); it != req.end(); it++) + preamble.registerAutomaticallyLoadedPackage(*it); } //cerr << "#: " << t << " mode: " << mode << endl; // heuristic: read up to next non-nested space