]> git.lyx.org Git - lyx.git/blobdiff - src/tex2lyx/text.cpp
tex2lyx: support for plural and capitalized refstyle
[lyx.git] / src / tex2lyx / text.cpp
index c5d7ce21d086b9c64e3d1f685be35b0804632be0..38b03d91793f29dbab834e819492a968837f3e64 100644 (file)
@@ -47,14 +47,15 @@ namespace lyx {
 
 namespace {
 
-void output_arguments(ostream &, Parser &, bool, bool, bool, Context &,
+void output_arguments(ostream &, Parser &, bool, bool, string, Context &,
                       Layout::LaTeXArgMap const &);
 
 }
 
 
 void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
-               Context const & context, InsetLayout const * layout)
+               Context const & context, InsetLayout const * layout,
+               string const rdelim)
 {
        bool const forcePlainLayout =
                layout ? layout->forcePlainLayout() : false;
@@ -64,11 +65,18 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
        else
                newcontext.font = context.font;
        if (layout)
-               output_arguments(os, p, outer, false, false, newcontext,
+               output_arguments(os, p, outer, false, string(), newcontext,
                                 layout->latexargs());
-       parse_text(p, os, flags, outer, newcontext);
+       // If we have a latex param, we eat it here.
+       if (!context.latexparam.empty()) {
+               ostringstream oss;
+               Context dummy(true, context.textclass);
+               parse_text(p, oss, FLAG_RDELIM, outer, dummy,
+                          string(1, context.latexparam.back()));
+       }
+       parse_text(p, os, flags, outer, newcontext, rdelim);
        if (layout)
-               output_arguments(os, p, outer, false, true, newcontext,
+               output_arguments(os, p, outer, false, "post", newcontext,
                                 layout->postcommandargs());
        newcontext.check_end_layout(os);
 }
@@ -77,14 +85,15 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
 namespace {
 
 void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
-               Context const & context, string const & name)
+               Context const & context, string const & name,
+               string const rdelim = string())
 {
        InsetLayout const * layout = 0;
        DocumentClass::InsetLayouts::const_iterator it =
                context.textclass.insetLayouts().find(from_ascii(name));
        if (it != context.textclass.insetLayouts().end())
                layout = &(it->second);
-       parse_text_in_inset(p, os, flags, outer, context, layout);
+       parse_text_in_inset(p, os, flags, outer, context, layout, rdelim);
 }
 
 /// parses a paragraph snippet, useful for example for \\emph{...}
@@ -201,13 +210,14 @@ bool need_commentbib = false;
 char const * const known_quotes[] = { "dq", "guillemotleft", "flqq", "og",
 "guillemotright", "frqq", "fg", "glq", "glqq", "textquoteleft", "grq", "grqq",
 "quotedblbase", "textquotedblleft", "quotesinglbase", "textquoteright", "flq",
-"guilsinglleft", "frq", "guilsinglright", 0};
+"guilsinglleft", "frq", "guilsinglright", "textquotedblright", "textquotesingle",
+"textquotedbl", 0};
 
 /// the same as known_quotes with .lyx names
-char const * const known_coded_quotes[] = { "prd", "ard", "ard", "ard",
-"ald", "ald", "ald", "gls", "gld", "els", "els", "grd",
-"gld", "grd", "gls", "ers", "fls",
-"fls", "frs", "frs", 0};
+char const * const known_coded_quotes[] = { "qrd", "ard", "ard", "ard",
+"ald", "ald", "ald", "gls", "gld", "els", "els", "eld",
+"gld", "eld", "gls", "ers", "ars",
+"ars", "als", "als", "erd", "qrs", "qrd", 0};
 
 /// LaTeX names for font sizes
 char const * const known_sizes[] = { "tiny", "scriptsize", "footnotesize",
@@ -343,6 +353,10 @@ bool minted_float_has_caption = false;
 // The caption for non-floating minted listings
 string minted_nonfloat_caption = "";
 
+// Characters that have to be escaped by \\ in LaTeX
+char const * const known_escaped_chars[] = {
+               "&", "_", "$", "%", "#", "^", "{", "}", 0};
+
 
 /// splits "x=z, y=b" into a map and an ordered keyword vector
 void split_map(string const & s, map<string, string> & res, vector<string> & keys)
@@ -442,6 +456,107 @@ bool translate_len(string const & length, string & valstring, string & unit)
        return true;
 }
 
+
+/// If we have ambiguous quotation marks, make a smart guess
+/// based on main quote style
+string guessQuoteStyle(string in, bool const opening)
+{
+       string res = in;
+       if (prefixIs(in, "qr")) {// straight quote
+               if (!opening)
+                       res = subst(res, "r", "l");
+       } else if (in == "eld") {// ``
+               if (preamble.quotesStyle() == "german")
+                       res = "grd";
+               else if (preamble.quotesStyle() == "british")
+                       res = "bls";
+               else if (preamble.quotesStyle() == "french")
+                       res = "fls";
+               else if (preamble.quotesStyle() == "russian")
+                       res = "rrs";
+       } else if (in == "erd") {// ''
+               if (preamble.quotesStyle() == "polish")
+                       res = "prd";
+               else if (preamble.quotesStyle() == "british")
+                       res = "brs";
+               else if (preamble.quotesStyle() == "french")
+                       res = "frs";
+               else if (preamble.quotesStyle() == "swedish")
+                       res = opening ? "sld" : "srd";
+       } else if (in == "els") {// `
+               if (preamble.quotesStyle() == "german")
+                       res = "grs";
+               else if (preamble.quotesStyle() == "british")
+                       res = "bld";
+       } else if (in == "ers") {// '
+               if (preamble.quotesStyle() == "polish")
+                       res = "prs";
+               else if (preamble.quotesStyle() == "british")
+                       res = "brd";
+               else if (preamble.quotesStyle() == "swedish")
+                       res = opening ? "sls" : "srs";
+       } else if (in == "ard") {// >>
+               if (preamble.quotesStyle() == "swiss")
+                       res = "cld";
+               else if (preamble.quotesStyle() == "french")
+                       res = "fld";
+               else if (preamble.quotesStyle() == "russian")
+                       res = "rld";
+       } else if (in == "ald") {// <<
+               if (preamble.quotesStyle() == "swiss")
+                       res = "crd";
+               else if (preamble.quotesStyle() == "french")
+                       res = "frd";
+               else if (preamble.quotesStyle() == "russian")
+                       res = "rrd";
+       } else if (in == "ars") {// >
+               if (preamble.quotesStyle() == "swiss")
+                       res = "cls";
+       } else if (in == "als") {// <
+               if (preamble.quotesStyle() == "swiss")
+                       res = "crs";
+       } else if (in == "gld") {// ,,
+               if (preamble.quotesStyle() == "polish")
+                       res = "pld";
+               else if (preamble.quotesStyle() == "russian")
+                       res = "rls";
+       } else if (in == "gls") {// ,
+               if (preamble.quotesStyle() == "polish")
+                       res = "pls";
+       }
+       return res;
+}
+
+
+string const fromPolyglossiaEnvironment(string const s)
+{
+       // Since \arabic is taken by the LaTeX kernel,
+       // the Arabic polyglossia environment is upcased
+       if (s == "Arabic")
+               return "arabic";
+       else
+               return s;
+}
+
+
+string uncapitalize(string const s)
+{
+       docstring in = from_ascii(s);
+       char_type t = lowercase(s[0]);
+       in[0] = t;
+       return to_ascii(in);
+}
+
+
+bool isCapitalized(string const s)
+{
+       docstring in = from_ascii(s);
+       char_type t = uppercase(s[0]);
+       in[0] = t;
+       return to_ascii(in) == s;
+}
+
+
 } // namespace
 
 
@@ -521,9 +636,6 @@ bool skip_braces(Parser & p)
 pair<bool, docstring> convert_unicodesymbols(docstring s)
 {
        bool res = true;
-       int const nchars_escape = 8;
-       static char_type const chars_escape[nchars_escape] = {
-                       '&', '_', '$', '%', '#', '^', '{', '}'};
        odocstringstream os;
        for (size_t i = 0; i < s.size();) {
                if (s[i] != '\\') {
@@ -546,8 +658,8 @@ pair<bool, docstring> convert_unicodesymbols(docstring s)
                        i = 0;
                else {
                        res = false;
-                       for (int k = 0; k < nchars_escape; k++)
-                               if (prefixIs(s, from_ascii("\\") + chars_escape[k]))
+                       for (auto const & c : known_escaped_chars)
+                               if (c != 0 && prefixIs(s, from_ascii("\\") + c))
                                        res = true;
                        i = 1;
                }
@@ -621,24 +733,27 @@ void output_comment(Parser & p, ostream & os, string const & s,
 }
 
 
-Layout const * findLayout(TextClass const & textclass, string const & name, bool command)
+Layout const * findLayout(TextClass const & textclass, string const & name, bool command,
+                         string const & latexparam = string())
 {
-       Layout const * layout = findLayoutWithoutModule(textclass, name, command);
+       Layout const * layout = findLayoutWithoutModule(textclass, name, command, latexparam);
        if (layout)
                return layout;
        if (checkModule(name, command))
-               return findLayoutWithoutModule(textclass, name, command);
+               return findLayoutWithoutModule(textclass, name, command, latexparam);
        return layout;
 }
 
 
-InsetLayout const * findInsetLayout(TextClass const & textclass, string const & name, bool command)
+InsetLayout const * findInsetLayout(TextClass const & textclass, string const & name, bool command,
+                                   string const & latexparam = string())
 {
-       InsetLayout const * insetlayout = findInsetLayoutWithoutModule(textclass, name, command);
+       InsetLayout const * insetlayout =
+               findInsetLayoutWithoutModule(textclass, name, command, latexparam);
        if (insetlayout)
                return insetlayout;
        if (checkModule(name, command))
-               return findInsetLayoutWithoutModule(textclass, name, command);
+               return findInsetLayoutWithoutModule(textclass, name, command, latexparam);
        return insetlayout;
 }
 
@@ -673,14 +788,16 @@ void skip_spaces_braces(Parser & p, bool keepws = false)
 }
 
 
-void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bool post,
+void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, string const prefix,
                       Context & context, Layout::LaTeXArgMap const & latexargs)
 {
-       if (need_layout) {
-               context.check_layout(os);
-               need_layout = false;
-       } else
-               need_layout = true;
+       if (context.layout->latextype != LATEX_ITEM_ENVIRONMENT || !prefix.empty()) {
+               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();
@@ -690,31 +807,50 @@ void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bo
                if (lait->second.mandatory) {
                        if (p.next_token().cat() != catBegin)
                                break;
-                       p.get_token(); // eat '{'
+                       string ldelim = to_utf8(lait->second.ldelim);
+                       string rdelim = to_utf8(lait->second.rdelim);
+                       if (ldelim.empty())
+                               ldelim = "{";
+                       if (rdelim.empty())
+                               rdelim = "}";
+                       p.get_token(); // eat ldelim
+                       if (ldelim.size() > 1)
+                               p.get_token(); // eat ldelim
                        if (need_layout) {
                                context.check_layout(os);
                                need_layout = false;
                        }
                        begin_inset(os, "Argument ");
-                       if (post)
-                               os << "post:";
+                       if (!prefix.empty())
+                               os << prefix << ':';
                        os << i << "\nstatus collapsed\n\n";
-                       parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context);
+                       parse_text_in_inset(p, os, FLAG_RDELIM, outer, context, 0, rdelim);
                        end_inset(os);
                } else {
-                       if (p.next_token().cat() == catEscape ||
-                           p.next_token().character() != '[')
+                       string ldelim = to_utf8(lait->second.ldelim);
+                       string rdelim = to_utf8(lait->second.rdelim);
+                       if (ldelim.empty())
+                               ldelim = "[";
+                       if (rdelim.empty())
+                               rdelim = "]";
+                       string tok = p.next_token().asInput();
+                       // we only support delimiters with max 2 chars for now.
+                       if (ldelim.size() > 1)
+                               tok += p.next_next_token().asInput();
+                       if (p.next_token().cat() == catEscape || tok != ldelim)
                                continue;
-                       p.get_token(); // eat '['
+                       p.get_token(); // eat ldelim
+                       if (ldelim.size() > 1)
+                               p.get_token(); // eat ldelim
                        if (need_layout) {
                                context.check_layout(os);
                                need_layout = false;
                        }
                        begin_inset(os, "Argument ");
-                       if (post)
-                               os << "post:";
+                       if (!prefix.empty())
+                               os << prefix << ':';
                        os << i << "\nstatus collapsed\n\n";
-                       parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context);
+                       parse_text_in_inset(p, os, FLAG_RDELIM, outer, context, 0, rdelim);
                        end_inset(os);
                }
                eat_whitespace(p, os, context, false);
@@ -745,10 +881,17 @@ void output_command_layout(ostream & os, Parser & p, bool outer,
                context.need_end_deeper = true;
        }
        context.check_deeper(os);
-       output_arguments(os, p, outer, true, false, context,
+       output_arguments(os, p, outer, true, string(), context,
                         context.layout->latexargs());
+       // If we have a latex param, we eat it here.
+       if (!parent_context.latexparam.empty()) {
+               ostringstream oss;
+               Context dummy(true, parent_context.textclass);
+               parse_text(p, oss, FLAG_RDELIM, outer, dummy,
+                          string(1, parent_context.latexparam.back()));
+       }
        parse_text(p, os, FLAG_ITEM, outer, context);
-       output_arguments(os, p, outer, false, true, context,
+       output_arguments(os, p, outer, false, "post", context,
                         context.layout->postcommandargs());
        context.check_end_layout(os);
        if (parent_context.deeper_paragraph) {
@@ -1369,7 +1512,7 @@ void parse_listings(Parser & p, ostream & os, Context & parent_context,
                os << "inline true\n";
        else
                os << "inline false\n";
-       os << "status collapsed\n";
+       os << "status open\n";
        Context context(true, parent_context.textclass);
        context.layout = &parent_context.textclass.plainLayout();
        if (use_minted && prefixIs(minted_nonfloat_caption, "[t]")) {
@@ -1451,6 +1594,14 @@ void parse_unknown_environment(Parser & p, string const & name, ostream & os,
        if (specialfont)
                parent_context.new_layout_allowed = false;
        output_ert_inset(os, "\\begin{" + name + "}", parent_context);
+       // Try to handle options: Look if we have an optional arguments,
+       // and if so, put the brackets in ERT.
+       while (p.hasOpt()) {
+               p.get_token(); // eat '['
+               output_ert_inset(os, "[", parent_context);
+               os << parse_text_snippet(p, FLAG_BRACK_LAST, outer, parent_context);
+               output_ert_inset(os, "]", parent_context);
+       }
        parse_text_snippet(p, os, flags, outer, parent_context);
        output_ert_inset(os, "\\end{" + name + "}", parent_context);
        if (specialfont)
@@ -1483,7 +1634,8 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                }
        }
 
-       else if (is_known(name, preamble.polyglossia_languages)) {
+       // We need to use fromPolyglossiaEnvironment die to Arabic > arabic
+       else if (is_known(fromPolyglossiaEnvironment(name), preamble.polyglossia_languages)) {
                // We must begin a new paragraph if not already done
                if (! parent_context.atParagraphStart()) {
                        parent_context.check_end_layout(os);
@@ -1491,7 +1643,8 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                }
                // save the language in the context so that it is
                // handled by parse_text
-               parent_context.font.language = preamble.polyglossia2lyx(name);
+               parent_context.font.language =
+                       preamble.polyglossia2lyx(fromPolyglossiaEnvironment(name));
                parse_text(p, os, FLAG_END, outer, parent_context);
                // Just in case the environment is empty
                parent_context.extra_stuff.erase();
@@ -1503,13 +1656,23 @@ void parse_environment(Parser & p, ostream & os, bool outer,
        else if (unstarred_name == "tabular" || name == "longtable") {
                eat_whitespace(p, os, parent_context, false);
                string width = "0pt";
+               string halign;
+               if (name == "longtable" && p.hasOpt()) {
+                       string const opt = p.getArg('[', ']');
+                       if (opt == "c")
+                               halign = "center";
+                       else if (opt == "l")
+                               halign = "left";
+                       else if (opt == "r")
+                               halign = "right";
+               }
                if (name == "tabular*") {
                        width = lyx::translate_len(p.getArg('{', '}'));
                        eat_whitespace(p, os, parent_context, false);
                }
                parent_context.check_layout(os);
                begin_inset(os, "Tabular ");
-               handle_tabular(p, os, name, width, parent_context);
+               handle_tabular(p, os, name, width, halign, parent_context);
                end_inset(os);
                p.skip_spaces();
        }
@@ -1678,6 +1841,16 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                preamble.registerAutomaticallyLoadedPackage("tipa");
                preamble.registerAutomaticallyLoadedPackage("tipx");
        }
+       
+       else if (name == parent_context.textclass.titlename()
+                && parent_context.textclass.titletype() == TITLE_ENVIRONMENT) {
+                       parse_text(p, os, FLAG_END, outer, parent_context);
+                       // Just in case the environment is empty
+                       parent_context.extra_stuff.erase();
+                       // We must begin a new paragraph
+                       parent_context.new_paragraph(os);
+                       p.skip_spaces();
+       }
 
        else if (name == "CJK") {
                // the scheme is \begin{CJK}{encoding}{mapping}text\end{CJK}
@@ -1719,10 +1892,10 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                        //        things like comments are completely wrong.
                        string const s = p.plainEnvironment("CJK");
                        for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
-                               if (*it == '\\')
-                                       output_ert_inset(os, "\\", parent_context);
-                               else if (*it == '$')
-                                       output_ert_inset(os, "$", parent_context);
+                               string snip;
+                               snip += *it;
+                               if (snip == "\\" || is_known(snip, known_escaped_chars))
+                                       output_ert_inset(os, snip, parent_context);
                                else if (*it == '\n' && it + 1 != et && s.begin() + 1 != it)
                                        os << "\n ";
                                else
@@ -1787,6 +1960,20 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                p.skip_spaces();
        }
 
+       else if (name == "btUnit") {
+               string const nt = p.next_next_token().cs();
+               // Do not attempt to overwrite a former diverging multibib.
+               // Those are output as ERT instead.
+               if ((nt == "part" || nt == "chapter"
+                    || nt == "section" || nt == "subsection")
+                  && (preamble.multibib().empty() || preamble.multibib() == nt)) {
+                       parse_text(p, os, FLAG_END, outer, parent_context);
+                       preamble.multibib(nt);
+               } else
+                       parse_unknown_environment(p, name, os, FLAG_END, outer,
+                                                 parent_context);
+       }
+
        else if (name == "framed" || name == "shaded") {
                eat_whitespace(p, os, parent_context, false);
                parse_outer_box(p, os, FLAG_END, outer, parent_context, name, "");
@@ -1887,6 +2074,7 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                                                parse_text_snippet(p, FLAG_ITEM,
                                                        false, parent_context);
                                        minted_nonfloat_caption = "[b]" + caption;
+                                       eat_whitespace(p, os, parent_context, true);
                                }
                        }
                        p.popPosition();
@@ -1985,16 +2173,25 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                        break;
                }
                context.check_deeper(os);
+               if (newlayout->keepempty) {
+                       // We need to start a new paragraph
+                       // even if it is empty.
+                       context.new_paragraph(os);
+                       context.check_layout(os);
+               }
                // handle known optional and required arguments
-               // 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)
-                       output_arguments(os, p, outer, false, false, context,
+                       output_arguments(os, p, outer, false, string(), context,
+                                        context.layout->latexargs());
+               else if (context.layout->latextype == LATEX_ITEM_ENVIRONMENT) {
+                       ostringstream oss;
+                       output_arguments(oss, p, outer, false, string(), context,
                                         context.layout->latexargs());
+                       context.list_extra_stuff = oss.str();
+               }
                parse_text(p, os, FLAG_END, outer, context);
                if (context.layout->latextype == LATEX_ENVIRONMENT)
-                       output_arguments(os, p, outer, false, true, context,
+                       output_arguments(os, p, outer, false, "post", context,
                                         context.layout->postcommandargs());
                context.check_end_layout(os);
                if (parent_context.deeper_paragraph) {
@@ -2505,7 +2702,7 @@ void fix_child_filename(string & name)
 
 
 void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
-               Context & context)
+               Context & context, string const rdelim)
 {
        Layout const * newlayout = 0;
        InsetLayout const * newinsetlayout = 0;
@@ -2514,7 +2711,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
        // nocite{*} option (needed for bibtex inset)
        string btprint;
        string contentslineContent;
-       string bibliographystyle = "default";
+       // Some classes provide a \bibliographystyle, so do not output
+       // any if none is explicitly set.
+       string bibliographystyle;
        bool const use_natbib = isProvided("natbib");
        bool const use_jurabib = isProvided("jurabib");
        bool const use_biblatex = isProvided("biblatex")
@@ -2580,6 +2779,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        return;
                if (t.cat() == catEnd && (flags & FLAG_BRACE_LAST))
                        return;
+               string tok = t.asInput();
+               // we only support delimiters with max 2 chars for now.
+               if (rdelim.size() > 1)
+                       tok += p.next_token().asInput();
+               if (t.cat() != catEscape && !rdelim.empty()
+                   && tok == rdelim && (flags & FLAG_RDELIM)) {
+                       if (rdelim.size() > 1)
+                               p.get_token(); // eat rdelim
+                       return;
+               }
 
                // If there is anything between \end{env} and \begin{env} we
                // don't need to output a separator.
@@ -2627,14 +2836,17 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
-               // Basic support for english quotes. This should be
-               // extended to other quotes, but is not so easy (a
-               // left english quote is the same as a right german
-               // quote...)
+               // Basic support for quotes. We try to disambiguate
+               // quotes from the context (e.g., a left english quote is
+               // the same as a right german quote...).
+               // Try to make a smart guess about the side
+               Token const prev = p.prev_token();
+               bool const opening = (prev.cat() != catSpace && prev.character() != 0
+                               && prev.character() != '\n' && prev.character() != '~');
                if (t.asInput() == "`" && p.next_token().asInput() == "`") {
                        context.check_layout(os);
                        begin_inset(os, "Quotes ");
-                       os << "eld";
+                       os << guessQuoteStyle("eld", opening);
                        end_inset(os);
                        p.get_token();
                        skip_braces(p);
@@ -2643,7 +2855,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                if (t.asInput() == "'" && p.next_token().asInput() == "'") {
                        context.check_layout(os);
                        begin_inset(os, "Quotes ");
-                       os << "erd";
+                       os << guessQuoteStyle("erd", opening);
                        end_inset(os);
                        p.get_token();
                        skip_braces(p);
@@ -2653,7 +2865,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                if (t.asInput() == ">" && p.next_token().asInput() == ">") {
                        context.check_layout(os);
                        begin_inset(os, "Quotes ");
-                       os << "ald";
+                       os << guessQuoteStyle("ald", opening);
                        end_inset(os);
                        p.get_token();
                        skip_braces(p);
@@ -2674,9 +2886,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        if (!has_chunk) {
                                context.check_layout(os);
                                begin_inset(os, "Quotes ");
-                               //FIXME: this is a right danish quote;
-                               // why not a left french quote?
-                               os << "ard";
+                               os << guessQuoteStyle("ard", opening);
                                end_inset(os);
                                p.get_token();
                                skip_braces(p);
@@ -2802,8 +3012,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                   is_known(next.cs(), known_quotes) &&
                                   end.cat() == catEnd) {
                                // Something like {\textquoteright} (e.g.
-                               // from writer2latex). LyX writes
-                               // \textquoteright{}, so we may skip the
+                               // from writer2latex). We may skip the
                                // braces here for better readability.
                                parse_text_snippet(p, os, FLAG_BRACE_LAST,
                                                   outer, context);
@@ -2968,10 +3177,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
-               if (t.cs() == "item") {
+               // "item" by default, but could be something else
+               if (t.cs() == context.layout->itemcommand()) {
                        string s;
-                       bool const optarg = p.hasOpt();
-                       if (optarg) {
+                       if (context.layout->labeltype == LABEL_MANUAL) {
                                // FIXME: This swallows comments, but we cannot use
                                //        eat_whitespace() since we must not output
                                //        anything before the item.
@@ -2985,26 +3194,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                // An item in an unknown list-like environment
                                // FIXME: Do this in check_layout()!
                                context.has_item = false;
-                               if (optarg)
-                                       output_ert_inset(os, "\\item", context);
-                               else
-                                       output_ert_inset(os, "\\item ", context);
+                               string item = "\\" + context.layout->itemcommand();
+                               if (!p.hasOpt())
+                                       item += " ";
+                               output_ert_inset(os, item, context);
                        }
-                       if (optarg) {
-                               if (context.layout->labeltype != LABEL_MANUAL) {
-                                       // 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()) {
+                       if (context.layout->labeltype != LABEL_MANUAL)
+                               output_arguments(os, p, outer, false, "item", context,
+                                                context.layout->itemargs());
+                       if (!context.list_extra_stuff.empty()) {
+                               os << context.list_extra_stuff;
+                               context.list_extra_stuff.clear();
+                       }
+                       else if (!s.empty()) {
                                        // LyX adds braces around the argument,
                                        // so we need to remove them here.
                                        if (s.size() > 2 && s[0] == '{' &&
@@ -3026,7 +3228,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        os << ' ';
                                        eat_whitespace(p, os, context, false);
                                }
-                       }
                        continue;
                }
 
@@ -3167,6 +3368,25 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
+               // Before we look for the layout name with star and alone below, we check the layouts including
+               // the LateXParam, which might be one or several options or a star.
+               // The single '=' is meant here.
+               if (context.new_layout_allowed &&
+                  (newlayout = findLayout(context.textclass, t.cs(), true, p.getCommandLatexParam()))) {
+                       // store the latexparam here. This is eaten in output_command_layout
+                       context.latexparam = newlayout->latexparam();
+                       // write the layout
+                       output_command_layout(os, p, outer, context, newlayout);
+                       context.latexparam.clear();
+                       p.skip_spaces();
+                       if (!preamble.titleLayoutFound())
+                               preamble.titleLayoutFound(newlayout->intitle);
+                       set<string> const & req = newlayout->requires();
+                       for (set<string>::const_iterator it = req.begin(); it != req.end(); ++it)
+                               preamble.registerAutomaticallyLoadedPackage(*it);
+                       continue;
+               }
+
                // Starred section headings
                // Must attempt to parse "Section*" before "Section".
                if ((p.next_token().asInput() == "*") &&
@@ -3261,6 +3481,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
+               if (t.cs() == "xymatrix") {
+                       // we must open a new math because LyX's xy support is in math
+                       context.check_layout(os);
+                       begin_inset(os, "Formula ");
+                       os << '$';
+                       os << "\\" << t.cs() << '{';
+                       parse_math(p, os, FLAG_ITEM, MATH_MODE);
+                       os << '}' << '$';
+                       end_inset(os);
+                       preamble.registerAutomaticallyLoadedPackage("xy");
+                       continue;
+               }
+
                if (t.cs() == "includegraphics") {
                        bool const clip = p.next_token().asInput() == "*";
                        if (clip)
@@ -3465,7 +3698,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
-               else if (t.cs() == "makeindex" || t.cs() == "maketitle") {
+               else if (t.cs() == "makeindex"
+                        || (t.cs() == context.textclass.titlename()
+                            && context.textclass.titletype() == TITLE_COMMAND_AFTER)) {
                        if (preamble.titleLayoutFound()) {
                                // swallow this
                                skip_spaces_braces(p);
@@ -3525,14 +3760,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
-               if ((where = is_known(t.cs(), known_text_font_series))) {
+               // beamer has a \textbf<overlay>{} inset
+               if (!p.hasOpt("<") && (where = is_known(t.cs(), known_text_font_series))) {
                        parse_text_attributes(p, os, FLAG_ITEM, outer,
                                context, "\\series", context.font.series,
                                known_coded_font_series[where - known_text_font_series]);
                        continue;
                }
 
-               if ((where = is_known(t.cs(), known_text_font_shapes))) {
+               // beamer has a \textit<overlay>{} inset
+               if (!p.hasOpt("<") && (where = is_known(t.cs(), known_text_font_shapes))) {
                        parse_text_attributes(p, os, FLAG_ITEM, outer,
                                context, "\\shape", context.font.shape,
                                known_coded_font_shapes[where - known_text_font_shapes]);
@@ -3611,9 +3848,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
-               if (t.cs() == "uuline" || t.cs() == "uwave"
+               // beamer has an \emph<overlay>{} inset
+               if ((t.cs() == "uuline" || t.cs() == "uwave"
                        || t.cs() == "emph" || t.cs() == "noun"
-                       || t.cs() == "xout") {
+                       || t.cs() == "xout") && !p.hasOpt("<")) {
                        context.check_layout(os);
                        os << "\n\\" << t.cs() << " on\n";
                        parse_text_snippet(p, os, FLAG_ITEM, outer, context);
@@ -3680,9 +3918,14 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
-               if (t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") {
+               if ((preamble.isPackageUsed("tipa") && t.cs() == "t" && p.next_token().asInput() == "*")
+                   || t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") {
                        context.check_layout(os);
-                       begin_inset(os, "IPADeco " + t.cs().substr(4) + "\n");
+                       if (t.cs() == "t")
+                               // swallow star
+                               p.get_token();
+                       string const type = (t.cs() == "t") ? "bottomtiebar" : t.cs().substr(4);
+                       begin_inset(os, "IPADeco " + type + "\n");
                        os << "status open\n";
                        parse_text_in_inset(p, os, FLAG_ITEM, outer, context);
                        end_inset(os);
@@ -3816,21 +4059,37 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
-               // handle refstyle first to catch \eqref which can also occur
-               // without refstyle. Only recognize these commands if
+               // Handle refstyle first in order to to catch \eqref, because this
+               // can also occur without refstyle. Only recognize these commands if
                // refstyle.sty was found in the preamble (otherwise \eqref
                // and user defined ref commands could be misdetected).
-               if ((where = is_known(t.cs(), known_refstyle_commands))
+               // We uncapitalize the input in order to catch capitalized commands
+               // such as \Eqref.
+               if ((where = is_known(uncapitalize(t.cs()), known_refstyle_commands))
                     && preamble.refstyle()) {
+                       string const cap = isCapitalized(t.cs()) ? "true" : "false";
+                       string plural = "false";
+                       // Catch the plural option [s]
+                       if (p.hasOpt()) {
+                               string const opt = p.getOpt();
+                               if (opt == "[s]")
+                                       plural = "true";
+                               else {
+                                       // LyX does not yet support other optional arguments of ref commands
+                                       output_ert_inset(os, t.asInput() + opt + "{" +
+                                              p.verbatim_item() + '}', context);
+                                       continue;
+                               }
+                       }
                        context.check_layout(os);
                        begin_command_inset(os, "ref", "formatted");
                        os << "reference \"";
                        os << known_refstyle_prefixes[where - known_refstyle_commands]
                           << ":";
-                       os << convert_literate_command_inset_arg(p.verbatim_item())
+                       os << convert_literate_command_inset_arg(p.getArg('{', '}'))
                           << "\"\n";
-                       os << "plural \"false\"\n";
-                       os << "caps \"false\"\n";
+                       os << "plural \"" << plural << "\"\n";
+                       os << "caps \"" << cap << "\"\n";
                        os << "noprefix \"false\"\n";
                        end_inset(os);
                        preamble.registerAutomaticallyLoadedPackage("refstyle");
@@ -3859,8 +4118,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        preamble.registerAutomaticallyLoadedPackage("prettyref");
                        } else {
                                // LyX does not yet support optional arguments of ref commands
-                               output_ert_inset(os, t.asInput() + '[' + opt + "]{" +
-                                      p.verbatim_item() + '}', context);
+                               output_ert_inset(os, t.asInput() + opt + "{" +
+                                                p.verbatim_item() + '}', context);
                        }
                        continue;
                }
@@ -4278,6 +4537,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                // so simply skip it.
                                parse_text_snippet(p, FLAG_ITEM, false, context);
                        }
+                       eat_whitespace(p, os, context, true);
                        continue;
                }
 
@@ -4350,7 +4610,13 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                if ((where = is_known(t.cs(), known_quotes))) {
                        context.check_layout(os);
                        begin_inset(os, "Quotes ");
-                       os << known_coded_quotes[where - known_quotes];
+                       string quotetype = known_coded_quotes[where - known_quotes];
+                       // try to make a smart guess about the side
+                       Token const prev = p.prev_token();
+                       bool const opening = (prev.cat() != catSpace && prev.character() != 0
+                                       && prev.character() != '\n' && prev.character() != '~');
+                       quotetype = guessQuoteStyle(quotetype, opening);
+                       os << quotetype;
                        end_inset(os);
                        // LyX adds {} after the quote, so we have to eat
                        // spaces here if there are any before a possible
@@ -4361,7 +4627,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                }
 
                if ((where = is_known(t.cs(), known_sizes)) &&
-                        context.new_layout_allowed) {
+                       context.new_layout_allowed) {
                        context.check_layout(os);
                        TeXFont const oldFont = context.font;
                        context.font.size = known_coded_sizes[where - known_sizes];
@@ -4526,13 +4792,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
-               if (t.cs() == "textquotedbl") {
-                       context.check_layout(os);
-                       os << "\"";
-                       skip_braces(p);
-                       continue;
-               }
-
                if (t.cs() == "_" || t.cs() == "&" || t.cs() == "#"
                            || t.cs() == "$" || t.cs() == "{" || t.cs() == "}"
                            || t.cs() == "%" || t.cs() == "-") {
@@ -4612,12 +4871,49 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                }
 
                if (t.cs() == "input" || t.cs() == "include"
-                   || t.cs() == "verbatiminput") {
+                   || t.cs() == "verbatiminput"
+                   || t.cs() == "lstinputlisting"
+                   || t.cs() == "inputminted") {
                        string name = t.cs();
-                       if (t.cs() == "verbatiminput"
+                       if (name == "verbatiminput"
                            && p.next_token().asInput() == "*")
                                name += p.get_token().asInput();
                        context.check_layout(os);
+                       string lstparams;
+                       if (name == "lstinputlisting" && p.hasOpt()) {
+                               lstparams = p.getArg('[', ']');
+                               lstparams = subst(lstparams, "\n", " ");
+                       } else if (name == "inputminted") {
+                               name = "lstinputlisting";
+                               string const lang = p.getArg('{', '}');
+                               if (lang != "tex") {
+                                       string cmd = "\\inputminted{" + lang + "}{";
+                                       cmd += p.getArg('{', '}') + "}";
+                                       output_ert_inset(os, cmd, context);
+                                       continue;
+                               }
+                               if (prefixIs(minted_nonfloat_caption, "[t]")) {
+                                       minted_nonfloat_caption.erase(0,3);
+                                       // extract label and caption from the already produced LyX code
+                                       vector<string> nfc = getVectorFromString(minted_nonfloat_caption, "\n");
+                                       string const caption = nfc.front();
+                                       string label;
+                                       vector<string>::iterator it =
+                                               find(nfc.begin(), nfc.end(), "LatexCommand label");
+                                       if (it != nfc.end()) {
+                                               ++it;
+                                               if (it != nfc.end())
+                                                       label = *it;
+                                               label = support::split(label, '"');
+                                               label.pop_back();
+                                       }
+                                       minted_nonfloat_caption.clear();
+                                       lstparams = "caption=" + caption;
+                                       if (!label.empty())
+                                               lstparams += ",label=" + label;
+                                       lstparams = subst(lstparams, "\n", " ");
+                               }
+                       }
                        string filename(normalize_filename(p.getArg('{', '}')));
                        string const path = getMasterFilePath(true);
                        // We want to preserve relative / absolute filenames,
@@ -4725,6 +5021,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                outname = subst(outname, "\"", "\\\"");
                                os << "preview false\n"
                                      "filename \"" << outname << "\"\n";
+                               if (!lstparams.empty())
+                                       os << "lstparams \"" << lstparams << "\"\n";
                                if (t.cs() == "verbatiminput")
                                        preamble.registerAutomaticallyLoadedPackage("verbatim");
                        }
@@ -5280,6 +5578,58 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        continue;
                }
 
+               // Before we look for the layout name alone below, we check the layouts including the LateXParam, which
+               // might be one or several options or a star.
+               // The single '=' is meant here.
+               if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true, p.getCommandLatexParam()))) {
+                       if (starred)
+                               p.get_token();
+                       p.skip_spaces();
+                       context.check_layout(os);
+                       // store the latexparam here. This is eaten in parse_text_in_inset
+                       context.latexparam = newinsetlayout->latexparam();
+                       docstring name = newinsetlayout->name();
+                       bool const caption = name.find(from_ascii("Caption:")) == 0;
+                       if (caption) {
+                               // Already done for floating minted listings.
+                               if (minted_float.empty()) {
+                                       begin_inset(os, "Caption ");
+                                       os << to_utf8(name.substr(8)) << '\n';
+                               }
+                       } else {
+                               // FIXME: what do we do if the prefix is not Flex: ?
+                               if (prefixIs(name, from_ascii("Flex:")))
+                                       name.erase(0, 5);
+                               begin_inset(os, "Flex ");
+                               os << to_utf8(name) << '\n'
+                                  << "status collapsed\n";
+                       }
+                       if (!minted_float.empty()) {
+                               parse_text_snippet(p, os, FLAG_ITEM, false, context);
+                       } else if (newinsetlayout->isPassThru()) {
+                               // set catcodes to verbatim early, just in case.
+                               p.setCatcodes(VERBATIM_CATCODES);
+                               string delim = p.get_token().asInput();
+                               if (delim != "{")
+                                       cerr << "Warning: bad delimiter for command " << t.asInput() << endl;
+                               //FIXME: handle error condition
+                               string const arg = p.verbatimStuff("}").second;
+                               Context newcontext(true, context.textclass);
+                               if (newinsetlayout->forcePlainLayout())
+                                       newcontext.layout = &context.textclass.plainLayout();
+                               output_ert(os, arg, newcontext);
+                       } else
+                               parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout);
+                       context.latexparam.clear();
+                       if (caption)
+                               p.skip_spaces();
+                       // Minted caption insets are not closed here because
+                       // we collect everything into the caption.
+                       if (minted_float.empty())
+                               end_inset(os);
+                       continue;
+               }
+
                // The single '=' is meant here.
                if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true))) {
                        if (starred)
@@ -5565,8 +5915,18 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                p.get_token();  // Eat '*'
                                name += '*';
                        }
-                       if (!parse_command(name, p, os, outer, context))
+                       if (!parse_command(name, p, os, outer, context)) {
                                output_ert_inset(os, name, context);
+                               // Try to handle options of unknown commands:
+                               // Look if we have an optional arguments,
+                               // and if so, put the brackets in ERT.
+                               while (p.hasOpt()) {
+                                       p.get_token(); // eat '['
+                                       output_ert_inset(os, "[", context);
+                                       os << parse_text_snippet(p, FLAG_BRACK_LAST, outer, context);
+                                       output_ert_inset(os, "]", context);
+                               }
+                       }
                }
        }
 }