]> git.lyx.org Git - lyx.git/blobdiff - src/tex2lyx/text.cpp
Some more oxygen svg icon fixes
[lyx.git] / src / tex2lyx / text.cpp
index 32c08acd3777137ef69668f8ab9b4484fe689c83..68f4ec9dd051086b5beec66cee8d68240fef63b0 100644 (file)
@@ -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);
 }
 
@@ -112,10 +126,10 @@ string parse_text_snippet(Parser & p, unsigned flags, const bool outer,
 
 
 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",
@@ -235,12 +249,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};
+"\\SpecialChar \\slash{}\n", "~", "^", "\n\\backslash\n",
+"\\SpecialChar \\LyX\n", "\\SpecialChar \\TeX\n", "\\SpecialChar \\LaTeXe\n",
+"\\SpecialChar \\LaTeX\n", 0};
 
 /*!
  * Graphics file extensions known by the dvips driver of the graphics package.
@@ -281,12 +303,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",
@@ -613,6 +629,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 +701,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
@@ -1525,6 +1553,37 @@ 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";
+               os << "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, "");
@@ -1622,60 +1681,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
@@ -1703,7 +1718,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);
@@ -2183,8 +2198,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
        bool const use_natbib = isProvided("natbib");
        bool const use_jurabib = isProvided("jurabib");
        string last_env;
-       while (p.good()) {
-               Token const & t = p.get_token();
 
        // it is impossible to determine the correct encoding for non-CJK Japanese.
        // Therefore write a note at the beginning of the document
@@ -2208,6 +2221,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                is_nonCJKJapanese = false;
        }
 
+       while (p.good()) {
+               Token const & t = p.get_token();
 #ifdef FILEDEBUG
                debugToken(cerr, t, flags);
 #endif
@@ -2243,6 +2258,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                //
                // cat codes
                //
+               bool const starred = p.next_token().asInput() == "*";
+               string const starredname(starred ? (t.cs() + '*') : t.cs());
                if (t.cat() == catMath) {
                        // we are inside some text mode thingy, so opening new math is allowed
                        context.check_layout(os);
@@ -2345,36 +2362,28 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
 
                else if (t.cat() == catLetter) {
                        context.check_layout(os);
-                       // Workaround for bug 4752.
-                       // FIXME: This whole code block needs to be removed
-                       //        when the bug is fixed and tex2lyx produces
-                       //        the updated file format.
-                       // The replacement algorithm in LyX is so stupid that
-                       // it even translates a phrase if it is part of a word.
-                       bool handled = false;
-                       for (int const * l = known_phrase_lengths; *l; ++l) {
-                               string phrase = t.cs();
-                               for (int i = 1; i < *l && p.next_token().isAlnumASCII(); ++i)
-                                       phrase += p.get_token().cs();
-                               if (is_known(phrase, known_coded_phrases)) {
-                                       output_ert_inset(os, phrase, context);
-                                       handled = true;
-                                       break;
-                               } else {
-                                       for (size_t i = 1; i < phrase.length(); ++i)
-                                               p.putback();
-                               }
-                       }
-                       if (!handled)
-                               os << t.cs();
+                       os << t.cs();
                }
 
                else if (t.cat() == catOther ||
                               t.cat() == catAlign ||
                               t.cat() == catParameter) {
-                       // This translates "&" to "\\&" which may be wrong...
                        context.check_layout(os);
-                       os << t.cs();
+                       if (t.asInput() == "-" && p.next_token().asInput() == "-" &&
+                           context.merging_hyphens_allowed &&
+                           context.font.family != "ttfamily" &&
+                           !context.layout->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()) {
@@ -2405,10 +2414,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 &&
@@ -2597,11 +2604,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.
@@ -2617,8 +2631,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.
@@ -2791,45 +2804,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
+                       // FIXME: second optional argument is not parsed
                        bool has_caption = false;
                        p.skip_spaces();
                        // do nothing if there is no outer float
@@ -3256,7 +3234,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");
@@ -3387,20 +3368,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
@@ -3668,7 +3635,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");
@@ -3775,7 +3743,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;
@@ -3811,14 +3779,26 @@ 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';
@@ -3863,7 +3843,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;
@@ -4300,11 +4280,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;
@@ -4358,13 +4335,41 @@ 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")
+                                                       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 ");
@@ -4376,16 +4381,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);
@@ -4406,12 +4415,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);
@@ -4425,8 +4443,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);
                }
 
@@ -4542,8 +4561,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") {