X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftex2lyx%2Ftext.cpp;h=d28ed5a0cb4c5849db7602a5a522347d4c2f94a5;hb=70b0f8d953f14d450e817294204b4069cc16db8b;hp=a11723ed17d23855adf96cefd4b09570fed888f1;hpb=f04c7711b0eb15c64a2e3166476fe506ebaa45e6;p=lyx.git diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index a11723ed17..d28ed5a0cb 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -45,6 +45,14 @@ using namespace lyx::support; namespace lyx { +namespace { + +void output_arguments(ostream &, Parser &, bool, bool, bool, Context &, + Layout::LaTeXArgMap const &); + +} + + void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer, Context const & context, InsetLayout const * layout) { @@ -55,7 +63,13 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer, newcontext.layout = &context.textclass.plainLayout(); else newcontext.font = context.font; + if (layout) + output_arguments(os, p, outer, false, false, newcontext, + layout->latexargs()); parse_text(p, os, flags, outer, newcontext); + if (layout) + output_arguments(os, p, outer, false, true, newcontext, + layout->postcommandargs()); newcontext.check_end_layout(os); } @@ -110,20 +124,23 @@ string parse_text_snippet(Parser & p, unsigned flags, const bool outer, return os.str(); } +string fboxrule = ""; +string fboxsep = ""; +string shadow_size = ""; char const * const known_ref_commands[] = { "ref", "pageref", "vref", - "vpageref", "prettyref", "eqref", 0 }; + "vpageref", "prettyref", "nameref", "eqref", 0 }; char const * const known_coded_ref_commands[] = { "ref", "pageref", "vref", - "vpageref", "formatted", "eqref", 0 }; + "vpageref", "formatted", "nameref", "eqref", 0 }; char const * const known_refstyle_commands[] = { "algref", "chapref", "corref", "eqref", "enuref", "figref", "fnref", "lemref", "parref", "partref", "propref", - "secref", "subref", "tabref", "thmref", 0 }; + "secref", "subsecref", "tabref", "thmref", 0 }; char const * const known_refstyle_prefixes[] = { "alg", "chap", "cor", "eq", "enu", "fig", "fn", "lem", "par", "part", "prop", - "sec", "sub", "tab", "thm", 0 }; + "sec", "subsec", "tab", "thm", 0 }; /** @@ -235,12 +252,20 @@ char const * const known_coded_font_shapes[] = { "italic", "slanted", /// Known special characters which need skip_spaces_braces() afterwards char const * const known_special_chars[] = {"ldots", "lyxarrow", "textcompwordmark", -"slash", "textasciitilde", "textasciicircum", "textbackslash", 0}; +"slash", "textasciitilde", "textasciicircum", "textbackslash", +"LyX", "TeX", "LaTeXe", +"LaTeX", 0}; + +/// special characters from known_special_chars which may have a \\protect before +char const * const known_special_protect_chars[] = {"LyX", "TeX", +"LaTeXe", "LaTeX", 0}; /// the same as known_special_chars with .lyx names -char const * const known_coded_special_chars[] = {"\\SpecialChar \\ldots{}\n", -"\\SpecialChar \\menuseparator\n", "\\SpecialChar \\textcompwordmark{}\n", -"\\SpecialChar \\slash{}\n", "~", "^", "\n\\backslash\n", 0}; +char const * const known_coded_special_chars[] = {"\\SpecialChar ldots\n", +"\\SpecialChar menuseparator\n", "\\SpecialChar ligaturebreak\n", +"\\SpecialChar breakableslash\n", "~", "^", "\n\\backslash\n", +"\\SpecialChar LyX\n", "\\SpecialChar TeX\n", "\\SpecialChar LaTeX2e\n", +"\\SpecialChar LaTeX\n", 0}; /*! * Graphics file extensions known by the dvips driver of the graphics package. @@ -281,12 +306,6 @@ char const * const known_coded_spaces[] = { "space{}", "space{}", "hfill{}", "dotfill{}", "hrulefill{}", "leftarrowfill{}", "rightarrowfill{}", "upbracefill{}", "downbracefill{}", 0}; -/// These are translated by LyX to commands like "\\LyX{}", so we have to put -/// them in ERT. "LaTeXe" must come before "LaTeX"! -char const * const known_phrases[] = {"LyX", "TeX", "LaTeXe", "LaTeX", 0}; -char const * const known_coded_phrases[] = {"LyX", "TeX", "LaTeX2e", "LaTeX", 0}; -int const known_phrase_lengths[] = {3, 5, 7, 0}; - /// known TIPA combining diacritical marks char const * const known_tipa_marks[] = {"textsubwedge", "textsubumlaut", "textsubtilde", "textseagull", "textsubbridge", "textinvsubbridge", @@ -294,7 +313,7 @@ char const * const known_tipa_marks[] = {"textsubwedge", "textsubumlaut", "textovercross", "textsubarch", "textsuperimposetilde", "textraising", "textlowering", "textadvancing", "textretracting", "textdoublegrave", "texthighrise", "textlowrise", "textrisefall", "textsyllabic", -"textsubring", 0}; +"textsubring", "textsubbar", 0}; /// TIPA tones that need special handling char const * const known_tones[] = {"15", "51", "45", "12", "454", 0}; @@ -394,6 +413,9 @@ bool translate_len(string const & length, string & valstring, string & unit) } else if (unit == "\\textheight") { valstring = percentval; unit = "theight%" + endlen; + } else if (unit == "\\baselineskip") { + valstring = percentval; + unit = "baselineskip%" + endlen; } return true; } @@ -502,8 +524,8 @@ docstring convert_unicodesymbols(docstring s) bool termination; docstring rem; set req; - docstring parsed = encodings.fromLaTeXCommand(s, - Encodings::TEXT_CMD, termination, rem, &req); + docstring parsed = normalize_c(encodings.fromLaTeXCommand(s, + Encodings::TEXT_CMD, termination, rem, &req)); set::const_iterator it = req.begin(); set::const_iterator en = req.end(); for (; it != en; ++it) @@ -561,6 +583,16 @@ void output_ert_inset(ostream & os, string const & s, Context & context) } +void output_comment(Parser & p, ostream & os, string const & s, + Context & context) +{ + if (p.next_token().cat() == catNewline) + output_ert_inset(os, '%' + s, context); + else + output_ert_inset(os, '%' + s + '\n', context); +} + + Layout const * findLayout(TextClass const & textclass, string const & name, bool command) { Layout const * layout = findLayoutWithoutModule(textclass, name, command); @@ -613,6 +645,55 @@ void skip_spaces_braces(Parser & p, bool keepws = false) } +void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bool post, + Context & context, Layout::LaTeXArgMap const & latexargs) +{ + if (need_layout) { + context.check_layout(os); + need_layout = false; + } else + need_layout = true; + int i = 0; + Layout::LaTeXArgMap::const_iterator lait = latexargs.begin(); + Layout::LaTeXArgMap::const_iterator const laend = latexargs.end(); + for (; lait != laend; ++lait) { + ++i; + eat_whitespace(p, os, context, false); + if (lait->second.mandatory) { + if (p.next_token().cat() != catBegin) + break; + p.get_token(); // eat '{' + if (need_layout) { + context.check_layout(os); + need_layout = false; + } + begin_inset(os, "Argument "); + if (post) + os << "post:"; + os << i << "\nstatus collapsed\n\n"; + parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context); + end_inset(os); + } else { + if (p.next_token().cat() == catEscape || + p.next_token().character() != '[') + continue; + p.get_token(); // eat '[' + if (need_layout) { + context.check_layout(os); + need_layout = false; + } + begin_inset(os, "Argument "); + if (post) + os << "post:"; + os << i << "\nstatus collapsed\n\n"; + parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context); + end_inset(os); + } + eat_whitespace(p, os, context, false); + } +} + + void output_command_layout(ostream & os, Parser & p, bool outer, Context & parent_context, Layout const * newlayout) @@ -636,48 +717,11 @@ void output_command_layout(ostream & os, Parser & p, bool outer, context.need_end_deeper = true; } context.check_deeper(os); - context.check_layout(os); - // FIXME: Adjust to format 446! - // Since format 446, layouts do not require anymore all optional - // arguments before the required ones. Needs to be implemented! - int optargs = 0; - while (optargs < context.layout->optArgs()) { - eat_whitespace(p, os, context, false); - if (p.next_token().cat() == catEscape || - p.next_token().character() != '[') - break; - p.get_token(); // eat '[' - // FIXME: Just a workaround. InsetArgument::updateBuffer - // will compute a proper ID for all "999" Arguments - // (which is also what lyx2lyx produces). - // However, tex2lyx should be able to output proper IDs - // itself. - begin_inset(os, "Argument 999\n"); - os << "status collapsed\n\n"; - parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context); - end_inset(os); - eat_whitespace(p, os, context, false); - ++optargs; - } - int reqargs = 0; - while (reqargs < context.layout->requiredArgs()) { - eat_whitespace(p, os, context, false); - if (p.next_token().cat() != catBegin) - break; - p.get_token(); // eat '{' - // FIXME: Just a workaround. InsetArgument::updateBuffer - // will compute a proper ID for all "999" Arguments - // (which is also what lyx2lyx produces). - // However, tex2lyx should be able to output proper IDs - // itself. - begin_inset(os, "Argument 999\n"); - os << "status collapsed\n\n"; - parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context); - end_inset(os); - eat_whitespace(p, os, context, false); - ++reqargs; - } + output_arguments(os, p, outer, true, false, context, + context.layout->latexargs()); parse_text(p, os, FLAG_ITEM, outer, context); + output_arguments(os, p, outer, false, true, context, + context.layout->postcommandargs()); context.check_end_layout(os); if (parent_context.deeper_paragraph) { // We must suppress the "end deeper" because we @@ -804,11 +848,12 @@ bool parse_command(string const & command, Parser & p, ostream & os, void parse_box(Parser & p, ostream & os, unsigned outer_flags, unsigned inner_flags, bool outer, Context & parent_context, string const & outer_type, string const & special, - string const & inner_type) + string inner_type, string const & frame_color, + string const & background_color) { string position; string inner_pos; - string hor_pos = "c"; + string hor_pos = "l"; // We need to set the height to the LaTeX default of 1\\totalheight // for the case when no height argument is given string height_value = "1"; @@ -819,6 +864,63 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, string width_unit; string latex_width; string width_special = "none"; + string thickness = "0.4pt"; + if (!fboxrule.empty()) + thickness = fboxrule; + else + thickness = "0.4pt"; + string separation; + if (!fboxsep.empty()) + separation = fboxsep; + else + separation = "3pt"; + string shadowsize; + if (!shadow_size.empty()) + shadowsize = shadow_size; + else + shadowsize = "4pt"; + string framecolor = "black"; + string backgroundcolor = "none"; + if (!frame_color.empty()) + framecolor = frame_color; + if (!background_color.empty()) + backgroundcolor = background_color; + // if there is a color box around the \begin statements have not yet been parsed + // so do this now + if (!frame_color.empty() || !background_color.empty()) { + eat_whitespace(p, os, parent_context, false); + p.get_token().asInput(); // the '{' + // parse minipage + if (p.next_token().asInput() == "\\begin") { + p.get_token().asInput(); + p.getArg('{', '}'); + inner_type = "minipage"; + inner_flags = FLAG_END; + active_environments.push_back("minipage"); + } + // parse parbox + else if (p.next_token().asInput() == "\\parbox") { + p.get_token().asInput(); + inner_type = "parbox"; + inner_flags = FLAG_ITEM; + } + // parse makebox + else if (p.next_token().asInput() == "\\makebox") { + p.get_token().asInput(); + inner_type = "makebox"; + inner_flags = FLAG_ITEM; + } + // in case there is just \colorbox{color}{text} + else { + latex_width = ""; + inner_type = "makebox"; + inner_flags = FLAG_BRACE_LAST; + position = "t"; + inner_pos = "t"; + } + } + if (!p.hasOpt() && (inner_type == "makebox" || outer_type == "mbox")) + hor_pos = "c"; if (!inner_type.empty() && p.hasOpt()) { if (inner_type != "makebox") position = p.getArg('[', ']'); @@ -859,6 +961,9 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, inner_pos = position; } } + } else { + if (inner_type == "makebox") + hor_pos = "c"; } } if (inner_type.empty()) { @@ -876,6 +981,9 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, << " for " << outer_type << endl; hor_pos = "c"; } + } else { + if (outer_type == "framebox") + hor_pos = "c"; } } } else if (inner_type != "makebox") @@ -906,9 +1014,8 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, if (!outer_type.empty() && !inner_type.empty() && (inner_flags & FLAG_END)) active_environments.push_back(inner_type); - // LyX can't handle length variables - bool use_ert = contains(width_unit, '\\') || contains(height_unit, '\\'); - if (!use_ert && !outer_type.empty() && !inner_type.empty()) { + bool use_ert = false; + if (!outer_type.empty() && !inner_type.empty()) { // Look whether there is some content after the end of the // inner box, but before the end of the outer box. // If yes, we need to output ERT. @@ -927,18 +1034,7 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, } p.popPosition(); } - // if only \makebox{content} was used we can set its width to 1\width - // because this identic and also identic to \mbox - // this doesn't work for \framebox{content}, thus we have to use ERT for this - if (latex_width.empty() && inner_type == "makebox") { - width_value = "1"; - width_unit = "in"; - width_special = "width"; - } else if (latex_width.empty() && outer_type == "framebox") { - width_value.clear(); - width_unit.clear(); - width_special = "none"; - } + if (use_ert) { ostringstream ss; if (!outer_type.empty()) { @@ -1008,7 +1104,7 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, begin_inset(os, "Box "); if (outer_type == "framed") os << "Framed\n"; - else if (outer_type == "framebox" || outer_type == "fbox") + else if (outer_type == "framebox" || outer_type == "fbox" || !frame_color.empty()) os << "Boxed\n"; else if (outer_type == "shadowbox") os << "Shadowbox\n"; @@ -1027,6 +1123,8 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, os << "hor_pos \"" << hor_pos << "\"\n"; if (outer_type == "mbox") os << "has_inner_box 1\n"; + else if (!frame_color.empty() && inner_type == "makebox") + os << "has_inner_box 0\n"; else os << "has_inner_box " << !inner_type.empty() << "\n"; os << "inner_pos \"" << inner_pos << "\"\n"; @@ -1034,15 +1132,32 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, << '\n'; if (outer_type == "mbox") os << "use_makebox 1\n"; + else if (!frame_color.empty()) + os << "use_makebox 0\n"; else os << "use_makebox " << (inner_type == "makebox") << '\n'; - if (outer_type == "fbox" || outer_type == "mbox") + if (outer_type == "mbox" || (outer_type == "fbox" && inner_type.empty())) os << "width \"\"\n"; + // for values like "1.5\width" LyX uses "1.5in" as width ad sets "width" as sepecial + else if (contains(width_unit, '\\')) + os << "width \"" << width_value << "in" << "\"\n"; else os << "width \"" << width_value << width_unit << "\"\n"; - os << "special \"" << width_special << "\"\n"; - os << "height \"" << height_value << height_unit << "\"\n"; + if (contains(width_unit, '\\')) { + width_unit.erase (0,1); // remove the leading '\' + os << "special \"" << width_unit << "\"\n"; + } else + os << "special \"" << width_special << "\"\n"; + if (contains(height_unit, '\\')) + os << "height \"" << height_value << "in" << "\"\n"; + else + os << "height \"" << height_value << height_unit << "\"\n"; os << "height_special \"" << height_special << "\"\n"; + os << "thickness \"" << thickness << "\"\n"; + os << "separation \"" << separation << "\"\n"; + os << "shadowsize \"" << shadowsize << "\"\n"; + os << "framecolor \"" << framecolor << "\"\n"; + os << "backgroundcolor \"" << backgroundcolor << "\"\n"; os << "status open\n\n"; // Unfortunately we can't use parse_text_in_inset: @@ -1087,13 +1202,13 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, // LyX puts a % after the end of the minipage if (p.next_token().cat() == catNewline && p.next_token().cs().size() > 1) { // new paragraph - //output_ert_inset(os, "%dummy", parent_context); + //output_comment(p, os, "dummy", parent_context); p.get_token(); p.skip_spaces(); parent_context.new_paragraph(os); } else if (p.next_token().cat() == catSpace || p.next_token().cat() == catNewline) { - //output_ert_inset(os, "%dummy", parent_context); + //output_comment(p, os, "dummy", parent_context); p.get_token(); p.skip_spaces(); // We add a protected space if something real follows @@ -1104,6 +1219,26 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, } #endif } + if (inner_type == "minipage" && (!frame_color.empty() || !background_color.empty())) + active_environments.pop_back(); + if (inner_flags != FLAG_BRACE_LAST && (!frame_color.empty() || !background_color.empty())) { + // in this case we have to eat the the closing brace of the color box + p.get_token().asInput(); // the '}' + } + if (p.next_token().asInput() == "}") { + // in this case we assume that the closing brace is from the box settings + // therefore reset these values for the next box + fboxrule = ""; + fboxsep = ""; + shadow_size = ""; + } + + // all boxes except of Frameless and Shaded require calc + if (!(outer_type.empty() || outer_type == "mbox") && + !((outer_type == "shaded" && inner_type.empty()) || + (outer_type == "minipage" && inner_type == "shaded") || + (outer_type == "parbox" && inner_type == "shaded"))) + preamble.registerAutomaticallyLoadedPackage("calc"); } @@ -1139,8 +1274,7 @@ void parse_outer_box(Parser & p, ostream & os, unsigned flags, bool outer, p.skip_spaces(true); } } - if (outer_type == "shaded" || outer_type == "fbox" - || outer_type == "mbox") { + if (outer_type == "shaded" || outer_type == "mbox") { // These boxes never have an inner box ; } else if (p.next_token().asInput() == "\\parbox") { @@ -1166,14 +1300,14 @@ void parse_outer_box(Parser & p, ostream & os, unsigned flags, bool outer, eat_whitespace(p, os, parent_context, false); } parse_box(p, os, flags, FLAG_END, outer, parent_context, - outer_type, special, inner); + outer_type, special, inner, "", ""); } else { if (inner_flags == FLAG_ITEM) { p.get_token(); eat_whitespace(p, os, parent_context, false); } parse_box(p, os, flags, inner_flags, outer, parent_context, - outer_type, special, inner); + outer_type, special, inner, "", ""); } } @@ -1310,12 +1444,12 @@ void parse_environment(Parser & p, ostream & os, bool outer, if (!opt.empty()) os << "placement " << opt << '\n'; if (contains(opt, "H")) - preamble.registerAutomaticallyLoadedPackage("float"); + preamble.registerAutomaticallyLoadedPackage("float"); else { Floating const & fl = parent_context.textclass.floats() - .getType(unstarred_name); - if (!fl.floattype().empty() && fl.usesFloatPkg()) - preamble.registerAutomaticallyLoadedPackage("float"); + .getType(unstarred_name); + if (!fl.floattype().empty() && fl.usesFloatPkg()) + preamble.registerAutomaticallyLoadedPackage("float"); } os << "wide " << convert(is_starred) @@ -1332,13 +1466,16 @@ void parse_environment(Parser & p, ostream & os, bool outer, } else if (unstarred_name == "sidewaysfigure" - || unstarred_name == "sidewaystable") { + || unstarred_name == "sidewaystable" + || unstarred_name == "sidewaysalgorithm") { eat_whitespace(p, os, parent_context, false); parent_context.check_layout(os); if (unstarred_name == "sidewaysfigure") begin_inset(os, "Float figure\n"); - else + else if (unstarred_name == "sidewaystable") begin_inset(os, "Float table\n"); + else if (unstarred_name == "sidewaysalgorithm") + begin_inset(os, "Float algorithm\n"); os << "wide " << convert(is_starred) << "\nsideways true" << "\nstatus open\n\n"; @@ -1408,7 +1545,7 @@ void parse_environment(Parser & p, ostream & os, bool outer, parent_context, name, "shaded"); else parse_box(p, os, 0, FLAG_END, outer, parent_context, - "", "", name); + "", "", name, "", ""); p.skip_spaces(); } @@ -1424,15 +1561,17 @@ void parse_environment(Parser & p, ostream & os, bool outer, preamble.registerAutomaticallyLoadedPackage("verbatim"); } - else if (name == "verbatim") { + else if (unstarred_name == "verbatim") { // FIXME: this should go in the generic code that // handles environments defined in layout file that // have "PassThru 1". However, the code over there is // already too complicated for my taste. + string const ascii_name = + (name == "verbatim*") ? "Verbatim*" : "Verbatim"; parent_context.new_paragraph(os); Context context(true, parent_context.textclass, - &parent_context.textclass[from_ascii("Verbatim")]); - string s = p.verbatimEnvironment("verbatim"); + &parent_context.textclass[from_ascii(ascii_name)]); + string s = p.verbatimEnvironment(name); output_ert(os, s, context); p.skip_spaces(); } @@ -1525,10 +1664,42 @@ void parse_environment(Parser & p, ostream & os, bool outer, preamble.registerAutomaticallyLoadedPackage("color"); } + else if (name == "btSect") { + eat_whitespace(p, os, parent_context, false); + parent_context.check_layout(os); + begin_command_inset(os, "bibtex", "bibtex"); + string bibstyle = "plain"; + if (p.hasOpt()) { + bibstyle = p.getArg('[', ']'); + p.skip_spaces(true); + } + string const bibfile = p.getArg('{', '}'); + eat_whitespace(p, os, parent_context, false); + Token t = p.get_token(); + if (t.asInput() == "\\btPrintCited") { + p.skip_spaces(true); + os << "btprint " << '"' << "btPrintCited" << '"' << "\n"; + } + if (t.asInput() == "\\btPrintNotCited") { + p.skip_spaces(true); + os << "btprint " << '"' << "btPrintNotCited" << '"' << "\n"; + } + if (t.asInput() == "\\btPrintAll") { + p.skip_spaces(true); + os << "btprint " << '"' << "btPrintAll" << '"' << "\n"; + } + os << "bibfiles " << '"' << bibfile << "\"\n" + << "options " << '"' << bibstyle << "\"\n"; + parse_text_in_inset(p, os, FLAG_END, outer, parent_context); + end_inset(os); + p.skip_spaces(); + } + else if (name == "framed" || name == "shaded") { eat_whitespace(p, os, parent_context, false); parse_outer_box(p, os, FLAG_END, outer, parent_context, name, ""); p.skip_spaces(); + preamble.registerAutomaticallyLoadedPackage("framed"); } else if (name == "lstlisting") { @@ -1599,24 +1770,13 @@ void parse_environment(Parser & p, ostream & os, bool outer, if (last_env == name) { // we need to output a separator since LyX would export // the two environments as one otherwise (bug 5716) - docstring const sep = from_ascii("--Separator--"); TeX2LyXDocClass const & textclass(parent_context.textclass); - if (textclass.hasLayout(sep)) { - Context newcontext(parent_context); - newcontext.layout = &(textclass[sep]); - newcontext.check_layout(os); - newcontext.check_end_layout(os); - } else { - parent_context.check_layout(os); - begin_inset(os, "Note Note\n"); - os << "status closed\n"; - Context newcontext(true, textclass, - &(textclass.defaultLayout())); - newcontext.check_layout(os); - newcontext.check_end_layout(os); - end_inset(os); - parent_context.check_end_layout(os); - } + Context newcontext(true, textclass, + &(textclass.defaultLayout())); + newcontext.check_layout(os); + begin_inset(os, "Separator plain\n"); + end_inset(os); + newcontext.check_end_layout(os); } switch (context.layout->latextype) { case LATEX_LIST_ENVIRONMENT: @@ -1633,60 +1793,16 @@ void parse_environment(Parser & p, ostream & os, bool outer, } context.check_deeper(os); // handle known optional and required arguments - // FIXME: Since format 446, layouts do not require anymore all optional - // arguments before the required ones. Needs to be implemented! // Unfortunately LyX can't handle arguments of list arguments (bug 7468): // It is impossible to place anything after the environment name, // but before the first \\item. - if (context.layout->latextype == LATEX_ENVIRONMENT) { - bool need_layout = true; - int optargs = 0; - while (optargs < context.layout->optArgs()) { - eat_whitespace(p, os, context, false); - if (p.next_token().cat() == catEscape || - p.next_token().character() != '[') - break; - p.get_token(); // eat '[' - if (need_layout) { - context.check_layout(os); - need_layout = false; - } - // FIXME: Just a workaround. InsetArgument::updateBuffer - // will compute a proper ID for all "999" Arguments - // (which is also what lyx2lyx produces). - // However, tex2lyx should be able to output proper IDs - // itself. - begin_inset(os, "Argument 999\n"); - os << "status collapsed\n\n"; - parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context); - end_inset(os); - eat_whitespace(p, os, context, false); - ++optargs; - } - int reqargs = 0; - while (reqargs < context.layout->requiredArgs()) { - eat_whitespace(p, os, context, false); - if (p.next_token().cat() != catBegin) - break; - p.get_token(); // eat '{' - if (need_layout) { - context.check_layout(os); - need_layout = false; - } - // FIXME: Just a workaround. InsetArgument::updateBuffer - // will compute a proper ID for all "999" Arguments - // (which is also what lyx2lyx produces). - // However, tex2lyx should be able to output proper IDs - // itself. - begin_inset(os, "Argument 999\n"); - os << "status collapsed\n\n"; - parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context); - end_inset(os); - eat_whitespace(p, os, context, false); - ++reqargs; - } - } + if (context.layout->latextype == LATEX_ENVIRONMENT) + output_arguments(os, p, outer, false, false, context, + context.layout->latexargs()); parse_text(p, os, FLAG_END, outer, context); + if (context.layout->latextype == LATEX_ENVIRONMENT) + output_arguments(os, p, outer, false, true, context, + context.layout->postcommandargs()); context.check_end_layout(os); if (parent_context.deeper_paragraph) { // We must suppress the "end deeper" because we @@ -1714,7 +1830,7 @@ void parse_environment(Parser & p, ostream & os, bool outer, << "status collapsed\n"; if (newinsetlayout->isPassThru()) { string const arg = p.verbatimEnvironment(name); - Context context(true, parent_context.textclass, + Context context(true, parent_context.textclass, &parent_context.textclass.plainLayout(), parent_context.layout); output_ert(os, arg, parent_context); @@ -1782,7 +1898,7 @@ void parse_comment(Parser & p, ostream & os, Token const & t, Context & context) LASSERT(t.cat() == catComment, return); if (!t.cs().empty()) { context.check_layout(os); - output_ert_inset(os, '%' + t.cs(), context); + output_comment(p, os, t.cs(), context); if (p.next_token().cat() == catNewline) { // A newline after a comment line starts a new // paragraph @@ -1965,7 +2081,6 @@ void copy_file(FileName const & src, string dstname) dst = FileName(dstname); else dst = makeAbsPath(dstname, absParent); - string const absMaster = getMasterFilePath(false); FileName const srcpath = src.onlyPath(); FileName const dstpath = dst.onlyPath(); if (equivalent(srcpath, dstpath)) @@ -1993,43 +2108,55 @@ void copy_file(FileName const & src, string dstname) } -/// Parse a NoWeb Chunk section. The initial "<<" is already parsed. -bool parse_noweb(Parser & p, ostream & os, Context & context) +/// Parse a literate Chunk section. The initial "<<" is already parsed. +bool parse_chunk(Parser & p, ostream & os, Context & context) { // check whether a chunk is possible here. - if (!context.new_layout_allowed || - !context.textclass.hasLayout(from_ascii("Chunk"))) { + if (!context.textclass.hasInsetLayout(from_ascii("Flex:Chunk"))) { return false; } p.pushPosition(); // read the parameters - Parser::Arg stuff = p.verbatimStuff(">>=", false); - if (!stuff.first) { + Parser::Arg const params = p.verbatimStuff(">>=\n", false); + if (!params.first) { p.popPosition(); return false; } - string chunk = "<<" + stuff.second + ">>=" - + p.verbatimStuff("\n").second + '\n'; - stuff = p.verbatimStuff("\n@"); - if (!stuff.first) { + Parser::Arg const code = p.verbatimStuff("\n@"); + if (!code.first) { p.popPosition(); return false; } - chunk += stuff.second + "\n@"; - string post_chunk = p.verbatimStuff("\n").second + '\n'; + string const post_chunk = p.verbatimStuff("\n").second + '\n'; if (post_chunk[0] != ' ' && post_chunk[0] != '\n') { p.popPosition(); return false; } - chunk += post_chunk; + // The last newline read is important for paragraph handling + p.putback(); + p.deparse(); - context.new_paragraph(os); - Context newcontext(true, context.textclass, - &context.textclass[from_ascii("Chunk")]); - output_ert(os, chunk, newcontext); + //cerr << "params=[" << params.second << "], code=[" << code.second << "]" <pass_thru) { + if (p.next_next_token().asInput() == "-") { + // --- is emdash + os << to_utf8(docstring(1, 0x2014)); + p.get_token(); + } else + // -- is endash + os << to_utf8(docstring(1, 0x2013)); + p.get_token(); + } else + // This translates "&" to "\\&" which may be wrong... + os << t.cs(); } else if (p.isParagraph()) { @@ -2404,10 +2525,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // {} Token const prev = p.prev_token(); p.get_token(); - if (p.next_token().character() == '`' || - (prev.character() == '-' && - p.next_token().character() == '-')) - ; // ignore it in {}`` or -{}- + if (p.next_token().character() == '`') + ; // ignore it in {}`` else output_ert_inset(os, "{}", context); } else if (next.cat() == catEscape && @@ -2596,11 +2715,18 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } if (optarg) { if (context.layout->labeltype != LABEL_MANUAL) { - // LyX does not support \item[\mybullet] - // in itemize environments + // handle option of itemize item + begin_inset(os, "Argument item:1\n"); + os << "status open\n"; + os << "\n\\begin_layout Plain Layout\n"; Parser p2(s + ']'); os << parse_text_snippet(p2, FLAG_BRACK_LAST, outer, context); + // we must not use context.check_end_layout(os) + // because that would close the outer itemize layout + os << "\n\\end_layout\n"; + end_inset(os); + eat_whitespace(p, os, context, false); } else if (!s.empty()) { // LyX adds braces around the argument, // so we need to remove them here. @@ -2616,8 +2742,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else { Parser p2(s + ']'); os << parse_text_snippet(p2, - FLAG_BRACK_LAST, - outer, context); + FLAG_BRACK_LAST, outer, context); } // The space is needed to separate the // item from the rest of the sentence. @@ -2641,7 +2766,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else { begin_command_inset(os, "bibitem", "bibitem"); os << "label \"" << label << "\"\n" - "key \"" << key << "\"\n"; + << "key \"" << key << "\"\n" + << "literal \"true\"\n"; end_inset(os); } } @@ -2719,8 +2845,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.check_layout(os); // FIXME: This is a hack to prevent paragraph // deletion if it is empty. Handle this better! - output_ert_inset(os, - "%dummy comment inserted by tex2lyx to " + output_comment(p, os, + "dummy comment inserted by tex2lyx to " "ensure that this paragraph is not empty", context); // Both measures above may generate an additional @@ -2790,46 +2916,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, preamble.registerAutomaticallyLoadedPackage(*it); } - else if (t.cs() == "caption") { - bool starred = false; - if (p.next_token().asInput() == "*") { - p.get_token(); - starred = true; - } - p.skip_spaces(); - context.check_layout(os); - p.skip_spaces(); - if (starred) - begin_inset(os, "Caption LongTableNoNumber\n"); - else - begin_inset(os, "Caption Standard\n"); - Context newcontext(true, context.textclass, 0, 0, context.font); - newcontext.check_layout(os); - // FIXME InsetArgument is now properly implemented in InsetLayout - // (for captions, but also for others) - if (p.next_token().cat() != catEscape && - p.next_token().character() == '[') { - p.get_token(); // eat '[' - begin_inset(os, "Argument 1\n"); - os << "status collapsed\n"; - parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context); - end_inset(os); - eat_whitespace(p, os, context, false); - } - parse_text(p, os, FLAG_ITEM, outer, context); - context.check_end_layout(os); - // We don't need really a new paragraph, but - // we must make sure that the next item gets a \begin_layout. - context.new_paragraph(os); - end_inset(os); - p.skip_spaces(); - newcontext.check_end_layout(os); - } - else if (t.cs() == "subfloat") { - // the syntax is \subfloat[caption]{content} + // the syntax is \subfloat[list entry][sub caption]{content} // if it is a table of figure depends on the surrounding float - bool has_caption = false; + // FIXME: second optional argument is not parsed p.skip_spaces(); // do nothing if there is no outer float if (!float_type.empty()) { @@ -2841,6 +2931,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, << "\nstatus collapsed\n\n"; // test for caption string caption; + bool has_caption = false; if (p.next_token().cat() != catEscape && p.next_token().character() == '[') { p.get_token(); // eat '[' @@ -3160,7 +3251,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else if (t.cs() == "textcolor") { // scheme is \textcolor{color name}{text} string const color = p.verbatim_item(); - // we only support the predefined colors of the color package + // we support the predefined colors of the color and the xcolor package if (color == "black" || color == "blue" || color == "cyan" || color == "green" || color == "magenta" || color == "red" || color == "white" || color == "yellow") { @@ -3170,6 +3261,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.check_layout(os); os << "\n\\color inherit\n"; preamble.registerAutomaticallyLoadedPackage("color"); + } else if (color == "brown" || color == "darkgray" || color == "gray" + || color == "lightgray" || color == "lime" || color == "olive" + || color == "orange" || color == "pink" || color == "purple" + || color == "teal" || color == "violet") { + context.check_layout(os); + os << "\n\\color " << color << "\n"; + parse_text_snippet(p, os, FLAG_ITEM, outer, context); + context.check_layout(os); + os << "\n\\color inherit\n"; + preamble.registerAutomaticallyLoadedPackage("xcolor"); } else // for custom defined colors output_ert_inset(os, t.asInput() + "{" + color + "}", context); @@ -3199,14 +3300,15 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, preamble.registerAutomaticallyLoadedPackage("ulem"); } - else if (t.cs() == "uuline" || t.cs() == "uwave" || - t.cs() == "emph" || t.cs() == "noun") { + else if (t.cs() == "uuline" || t.cs() == "uwave" + || t.cs() == "emph" || t.cs() == "noun" + || t.cs() == "xout") { context.check_layout(os); os << "\n\\" << t.cs() << " on\n"; parse_text_snippet(p, os, FLAG_ITEM, outer, context); context.check_layout(os); os << "\n\\" << t.cs() << " default\n"; - if (t.cs() == "uuline" || t.cs() == "uwave") + if (t.cs() == "uuline" || t.cs() == "uwave" || t.cs() == "xout") preamble.registerAutomaticallyLoadedPackage("ulem"); } @@ -3255,7 +3357,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else if (t.cs() == "textipa") { context.check_layout(os); begin_inset(os, "IPA\n"); + bool merging_hyphens_allowed = context.merging_hyphens_allowed; + context.merging_hyphens_allowed = false; parse_text_in_inset(p, os, FLAG_ITEM, outer, context); + context.merging_hyphens_allowed = merging_hyphens_allowed; end_inset(os); preamble.registerAutomaticallyLoadedPackage("tipa"); preamble.registerAutomaticallyLoadedPackage("tipx"); @@ -3342,6 +3447,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "target \"" << target << "\"\n"; if (type == "mailto:" || type == "file:") os << "type \"" << type << "\"\n"; + os << "literal \"true\"\n"; end_inset(os); skip_spaces_braces(p); } @@ -3386,20 +3492,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); } - else if (is_known(t.cs(), known_phrases) || - (t.cs() == "protect" && - p.next_token().cat() == catEscape && - is_known(p.next_token().cs(), known_phrases))) { - // LyX sometimes puts a \protect in front, so we have to ignore it - // FIXME: This needs to be changed when bug 4752 is fixed. - where = is_known( - t.cs() == "protect" ? p.get_token().cs() : t.cs(), - known_phrases); - context.check_layout(os); - os << known_coded_phrases[where - known_phrases]; - skip_spaces_braces(p); - } - // handle refstyle first to catch \eqref which can also occur // without refstyle. Only recognize these commands if // refstyle.sty was found in the preamble (otherwise \eqref @@ -3413,6 +3505,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, << ":"; os << convert_command_inset_arg(p.verbatim_item()) << "\"\n"; + os << "plural \"false\"\n"; + os << "caps \"false\"\n"; + os << "noprefix \"false\"\n"; end_inset(os); preamble.registerAutomaticallyLoadedPackage("refstyle"); } @@ -3429,6 +3524,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "reference \"" << convert_command_inset_arg(p.verbatim_item()) << "\"\n"; + os << "plural \"false\"\n"; + os << "caps \"false\"\n"; + os << "noprefix \"false\"\n"; end_inset(os); if (t.cs() == "vref" || t.cs() == "vpageref") preamble.registerAutomaticallyLoadedPackage("varioref"); @@ -3496,7 +3594,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "before " << '"' << before << '"' << "\n"; os << "key \"" << convert_command_inset_arg(p.verbatim_item()) - << "\"\n"; + << "\"\n" + << "literal \"true\"\n"; end_inset(os); // Need to set the cite engine if natbib is loaded by // the document class directly @@ -3548,9 +3647,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, before.erase(before.length() - 1, 1); } begin_command_inset(os, "citation", command); - os << "after " << '"' << after << '"' << "\n"; - os << "before " << '"' << before << '"' << "\n"; - os << "key " << '"' << citation << '"' << "\n"; + os << "after " << '"' << after << "\"\n" + << "before " << '"' << before << "\"\n" + << "key " << '"' << citation << "\"\n" + << "literal \"true\"\n"; end_inset(os); // Need to set the cite engine if jurabib is loaded by // the document class directly @@ -3567,8 +3667,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // the BibTeX inset if (key != "*") { begin_command_inset(os, "citation", t.cs()); - os << "after " << '"' << after << '"' << "\n"; - os << "key " << '"' << key << '"' << "\n"; + os << "after " << '"' << after << "\"\n" + << "key " << '"' << key << "\"\n" + << "literal \"true\"\n"; end_inset(os); } else if (t.cs() == "nocite") btprint = key; @@ -3598,7 +3699,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, << convert_command_inset_arg(p.verbatim_item()); os << "\"\ndescription \"" << convert_command_inset_arg(p.verbatim_item()) - << "\"\n"; + << "\"\n" + << "literal \"true\"\n"; end_inset(os); preamble.registerAutomaticallyLoadedPackage("nomencl"); } @@ -3628,6 +3730,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "type \"idx\"\n"; else os << "type \"" << indexname << "\"\n"; + os << "literal \"true\"\n"; } end_inset(os); skip_spaces_braces(p); @@ -3667,7 +3770,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.check_layout(os); begin_inset(os, "script "); os << t.cs().substr(4) << '\n'; - parse_text_in_inset(p, os, FLAG_ITEM, false, context); + newinsetlayout = findInsetLayout(context.textclass, t.cs(), true); + parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout); end_inset(os); if (t.cs() == "textsubscript") preamble.registerAutomaticallyLoadedPackage("subscript"); @@ -3774,7 +3878,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.font.language, lang); } - else if (prefixIs(t.cs(), "text") + else if (prefixIs(t.cs(), "text") && preamble.usePolyglossia() && is_known(t.cs().substr(4), preamble.polyglossia_languages)) { // scheme is \textLANGUAGE{text} where LANGUAGE is in polyglossia_languages[] string lang; @@ -3810,17 +3914,32 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.setEncoding(enc, Encoding::inputenc); } - else if ((where = is_known(t.cs(), known_special_chars))) { + else if (is_known(t.cs(), known_special_chars) || + (t.cs() == "protect" && + p.next_token().cat() == catEscape && + is_known(p.next_token().cs(), known_special_protect_chars))) { + // LyX sometimes puts a \protect in front, so we have to ignore it + where = is_known( + t.cs() == "protect" ? p.get_token().cs() : t.cs(), + known_special_chars); context.check_layout(os); os << known_coded_special_chars[where - known_special_chars]; skip_spaces_braces(p); } else if ((t.cs() == "nobreakdash" && p.next_token().asInput() == "-") || + (t.cs() == "protect" && p.next_token().asInput() == "\\nobreakdash" && + p.next_next_token().asInput() == "-") || (t.cs() == "@" && p.next_token().asInput() == ".")) { + // LyX sometimes puts a \protect in front, so we have to ignore it + if (t.cs() == "protect") + p.get_token(); context.check_layout(os); - os << "\\SpecialChar \\" << t.cs() - << p.get_token().asInput() << '\n'; + if (t.cs() == "nobreakdash") + os << "\\SpecialChar nobreakdash\n"; + else + os << "\\SpecialChar endofsentence\n"; + p.get_token(); } else if (t.cs() == "textquotedbl") { @@ -3834,7 +3953,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, || t.cs() == "%" || t.cs() == "-") { context.check_layout(os); if (t.cs() == "-") - os << "\\SpecialChar \\-\n"; + os << "\\SpecialChar softhyphen\n"; else os << t.cs(); } @@ -3862,7 +3981,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, string delim = p.get_token().asInput(); Parser::Arg arg = p.verbatimStuff(delim); if (arg.first) - output_ert_inset(os, "\\verb" + delim + output_ert_inset(os, "\\verb" + delim + arg.second + delim, context); else cerr << "invalid \\verb command. Skipping" << endl; @@ -3929,8 +4048,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, string const absfigname = changeExtension(abstexname, ".fig"); fix_child_filename(filename); - string const lyxname = - changeExtension(filename, ".lyx"); + string const lyxname = changeExtension(filename, + roundtripMode() ? ".lyx.lyx" : ".lyx"); string const abslyxname = makeAbsPath( lyxname, getParentFilePath(false)).absFileName(); bool xfig = false; @@ -4141,7 +4260,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context, "parbox", "shaded"); } else parse_box(p, os, 0, FLAG_ITEM, outer, context, - "", "", t.cs()); + "", "", t.cs(), "", ""); } else if (t.cs() == "fbox" || t.cs() == "mbox" || @@ -4149,6 +4268,52 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, t.cs() == "shadowbox" || t.cs() == "doublebox") parse_outer_box(p, os, FLAG_ITEM, outer, context, t.cs(), ""); + else if (t.cs() == "fcolorbox" || t.cs() == "colorbox") { + string backgroundcolor; + preamble.registerAutomaticallyLoadedPackage("xcolor"); + if (t.cs() == "fcolorbox") { + string const framecolor = p.getArg('{', '}'); + backgroundcolor = p.getArg('{', '}'); + parse_box(p, os, 0, 0, outer, context, "", "", "", framecolor, backgroundcolor); + } else { + backgroundcolor = p.getArg('{', '}'); + parse_box(p, os, 0, 0, outer, context, "", "", "", "", backgroundcolor); + } + } + + // FIXME: due to the compiler limit of "if" nestings + // the code for the alignment was put here + // put them in their own if if this is fixed + else if (t.cs() == "fboxrule" || t.cs() == "fboxsep" + || t.cs() == "shadowsize" + || t.cs() == "raggedleft" || t.cs() == "centering" + || t.cs() == "raggedright") { + if (t.cs() == "fboxrule") + fboxrule = ""; + if (t.cs() == "fboxsep") + fboxsep = ""; + if (t.cs() == "shadowsize") + shadow_size = ""; + if (t.cs() != "raggedleft" && t.cs() != "centering" + && t.cs() != "raggedright") { + p.skip_spaces(true); + while (p.good() && p.next_token().cat() != catSpace + && p.next_token().cat() != catNewline + && p.next_token().cat() != catEscape) { + if (t.cs() == "fboxrule") + fboxrule = fboxrule + p.get_token().asInput(); + if (t.cs() == "fboxsep") + fboxsep = fboxsep + p.get_token().asInput(); + if (t.cs() == "shadowsize") + shadow_size = shadow_size + p.get_token().asInput(); + } + } else { + output_ert_inset(os, t.asInput(), context); + } + } + + //\framebox() is part of the picture environment and different from \framebox{} + //\framebox{} will be parsed by parse_outer_box else if (t.cs() == "framebox") { if (p.next_token().character() == '(') { //the syntax is: \framebox(x,y)[position]{content} @@ -4183,7 +4348,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else //the syntax is: \makebox[width][position]{content} parse_box(p, os, 0, FLAG_ITEM, outer, context, - "", "", t.cs()); + "", "", t.cs(), "", ""); } else if (t.cs() == "smallskip" || @@ -4299,11 +4464,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else if (t.cs() == "hspace" || t.cs() == "vspace") { - bool starred = false; - if (p.next_token().asInput() == "*") { + if (starred) p.get_token(); - starred = true; - } string name = t.asInput(); string const length = p.verbatim_item(); string unit; @@ -4357,13 +4519,42 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, case Length::MU: known_unit = true; break; - default: + default: { + //unitFromString(unit) fails for relative units like Length::PCW + // therefore handle them separately + if (unit == "\\paperwidth" || unit == "\\columnwidth" + || unit == "\\textwidth" || unit == "\\linewidth" + || unit == "\\textheight" || unit == "\\paperheight" + || unit == "\\baselineskip") + known_unit = true; break; + } } } } - if (t.cs()[0] == 'h' && (known_unit || known_hspace)) { + // check for glue lengths + bool is_gluelength = false; + string gluelength = length; + string::size_type i = length.find(" minus"); + if (i == string::npos) { + i = length.find(" plus"); + if (i != string::npos) + is_gluelength = true; + } else + is_gluelength = true; + // if yes transform "9xx minus 8yy plus 7zz" + // to "9xx-8yy+7zz" + if (is_gluelength) { + i = gluelength.find(" minus"); + if (i != string::npos) + gluelength.replace(i, 7, "-"); + i = gluelength.find(" plus"); + if (i != string::npos) + gluelength.replace(i, 6, "+"); + } + + if (t.cs()[0] == 'h' && (known_unit || known_hspace || is_gluelength)) { // Literal horizontal length or known variable context.check_layout(os); begin_inset(os, "space "); @@ -4375,16 +4566,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << unit; os << "}"; if (known_unit && !known_hspace) - os << "\n\\length " - << translate_len(length); + os << "\n\\length " << translate_len(length); + if (is_gluelength) + os << "\n\\length " << gluelength; end_inset(os); - } else if (known_unit || known_vspace) { + } else if (known_unit || known_vspace || is_gluelength) { // Literal vertical length or known variable context.check_layout(os); begin_inset(os, "VSpace "); - if (known_unit) - os << value; - os << unit; + if (known_vspace) + os << unit; + if (known_unit && !known_vspace) + os << translate_len(length); + if (is_gluelength) + os << gluelength; if (starred) os << '*'; end_inset(os); @@ -4405,12 +4600,21 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } // The single '=' is meant here. - else if ((newinsetlayout = findInsetLayout(context.textclass, t.cs(), true))) { + else if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true))) { + if (starred) + p.get_token(); p.skip_spaces(); context.check_layout(os); - begin_inset(os, "Flex "); - os << to_utf8(newinsetlayout->name()) << '\n' - << "status collapsed\n"; + docstring const name = newinsetlayout->name(); + bool const caption = name.find(from_ascii("Caption:")) == 0; + if (caption) { + begin_inset(os, "Caption "); + os << to_utf8(name.substr(8)) << '\n'; + } else { + begin_inset(os, "Flex "); + os << to_utf8(name) << '\n' + << "status collapsed\n"; + } if (newinsetlayout->isPassThru()) { // set catcodes to verbatim early, just in case. p.setCatcodes(VERBATIM_CATCODES); @@ -4424,8 +4628,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, newcontext.layout = &context.textclass.plainLayout(); output_ert(os, arg, newcontext); } else - parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout); + if (caption) + p.skip_spaces(); end_inset(os); } @@ -4541,8 +4746,9 @@ 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) string name = t.asInput(); - // handle the dingbats and Cyrillic - if (name == "\\ding" || name == "\\textcyr") + // handle the dingbats, cyrillic and greek + if (name == "\\ding" || name == "\\textcyr" || + (name == "\\textgreek" && !preamble.usePolyglossia())) name = name + '{' + p.getArg('{', '}') + '}'; // handle the ifsym characters else if (name == "\\textifsymbol") { @@ -4560,10 +4766,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } // handle some TIPA special characters else if (preamble.isPackageUsed("tipa")) { - if (name == "\\textglobfall") { - name = "End"; - skip_braces(p); - } else if (name == "\\s") { + if (name == "\\s") { // fromLaTeXCommand() does not yet // recognize tipa short cuts name = "\\textsyllabic"; @@ -4572,7 +4775,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // fromLaTeXCommand() does not yet // recognize tipa short cuts p.get_token(); - name = "\\b"; + name = "\\textsubbar"; } else if (name == "\\textdoublevertline") { // FIXME: This is not correct, // \textvertline is higher than \textbardbl @@ -4639,8 +4842,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, bool termination; docstring rem; set req; - docstring s = encodings.fromLaTeXCommand(from_utf8(name), - Encodings::TEXT_CMD, termination, rem, &req); + docstring s = normalize_c(encodings.fromLaTeXCommand(from_utf8(name), + Encodings::TEXT_CMD, termination, rem, &req)); if (!s.empty()) { context.check_layout(os); os << to_utf8(s);