]> git.lyx.org Git - lyx.git/blobdiff - src/tex2lyx/text.cpp
listerrors.lyx : Update a link.
[lyx.git] / src / tex2lyx / text.cpp
index 1886c08956895b135828f3336b06389c4a9b3258..2b5d0acb0bcce21293a0d124c28f565ea8ae7167 100644 (file)
@@ -163,7 +163,12 @@ char const * const known_old_font_families[] = { "rm", "sf", "tt", 0};
 char const * const known_font_families[] = { "rmfamily", "sffamily",
 "ttfamily", 0};
 
-/// the same as known_old_font_families and known_font_families with .lyx names
+/// LaTeX names for font family changing commands
+char const * const known_text_font_families[] = { "textrm", "textsf",
+"texttt", 0};
+
+/// The same as known_old_font_families, known_font_families and
+/// known_text_font_families with .lyx names
 char const * const known_coded_font_families[] = { "roman", "sans",
 "typewriter", 0};
 
@@ -173,7 +178,11 @@ char const * const known_old_font_series[] = { "bf", 0};
 /// LaTeX names for font series
 char const * const known_font_series[] = { "bfseries", "mdseries", 0};
 
-/// the same as known_old_font_series and known_font_series with .lyx names
+/// LaTeX names for font series changing commands
+char const * const known_text_font_series[] = { "textbf", "textmd", 0};
+
+/// The same as known_old_font_series, known_font_series and
+/// known_text_font_series with .lyx names
 char const * const known_coded_font_series[] = { "bold", "medium", 0};
 
 /// LaTeX 2.09 names for font shapes
@@ -183,10 +192,23 @@ char const * const known_old_font_shapes[] = { "it", "sl", "sc", 0};
 char const * const known_font_shapes[] = { "itshape", "slshape", "scshape",
 "upshape", 0};
 
-/// the same as known_old_font_shapes and known_font_shapes with .lyx names
+/// LaTeX names for font shape changing commands
+char const * const known_text_font_shapes[] = { "textit", "textsl", "textsc",
+"textup", 0};
+
+/// The same as known_old_font_shapes, known_font_shapes and
+/// known_text_font_shapes with .lyx names
 char const * const known_coded_font_shapes[] = { "italic", "slanted",
 "smallcaps", "up", 0};
 
+/// Known special characters which need skip_spaces_braces() afterwards
+char const * const known_special_chars[] = {"ldots", "lyxarrow",
+"textcompwordmark", "slash", 0};
+
+/// the same as known_special_chars with .lyx names
+char const * const known_coded_special_chars[] = {"ldots{}", "menuseparator",
+"textcompwordmark{}", "slash{}", 0};
+
 /*!
  * Graphics file extensions known by the dvips driver of the graphics package.
  * These extensions are used to complete the filename of an included
@@ -433,8 +455,11 @@ docstring convert_unicodesymbols(docstring s)
                }
                s = s.substr(i);
                docstring rem;
-               docstring parsed = encodings.fromLaTeXCommand(s, rem,
-                               Encodings::TEXT_CMD);
+               set<string> req;
+               docstring parsed = encodings.fromLaTeXCommand(s,
+                               Encodings::TEXT_CMD, rem, &req);
+               for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+                       preamble.registerAutomaticallyLoadedPackage(*it);
                os << parsed;
                s = rem;
                if (s.empty() || s[0] != '\\')
@@ -674,10 +699,14 @@ void parse_arguments(string const & command,
        for (size_t i = 0; i < no_arguments; ++i) {
                switch (template_arguments[i]) {
                case required:
+               case req_group:
                        // This argument contains regular LaTeX
                        handle_ert(os, ert + '{', context);
                        eat_whitespace(p, os, context, false);
-                       parse_text(p, os, FLAG_ITEM, outer, context);
+                       if (template_arguments[i] == required)
+                               parse_text(p, os, FLAG_ITEM, outer, context);
+                       else
+                               parse_text_snippet(p, os, FLAG_ITEM, outer, context);
                        ert = "}";
                        break;
                case item:
@@ -689,11 +718,13 @@ void parse_arguments(string const & command,
                        else
                                ert += p.verbatim_item();
                        break;
+               case displaymath:
                case verbatim:
                        // This argument may contain special characters
                        ert += '{' + p.verbatim_item() + '}';
                        break;
                case optional:
+               case opt_group:
                        // true because we must not eat whitespace
                        // if an optional arg follows we must not strip the
                        // brackets from this one
@@ -1157,6 +1188,12 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                parse_math(p, os, FLAG_END, MATH_MODE);
                os << "\\end{" << name << "}";
                end_inset(os);
+               if (is_display_math_env(name)) {
+                       // Prevent the conversion of a line break to a space
+                       // (bug 7668). This does not change the output, but
+                       // looks ugly in LyX.
+                       eat_whitespace(p, os, parent_context, false);
+               }
        }
 
        else if (unstarred_name == "tabular" || name == "longtable") {
@@ -1174,6 +1211,8 @@ void parse_environment(Parser & p, ostream & os, bool outer,
        }
 
        else if (parent_context.textclass.floats().typeExist(unstarred_name)) {
+               eat_whitespace(p, os, parent_context, false);
+               string const opt = p.hasOpt() ? p.getArg('[', ']') : string();
                eat_whitespace(p, os, parent_context, false);
                parent_context.check_layout(os);
                begin_inset(os, "Float " + unstarred_name + "\n");
@@ -1185,8 +1224,17 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                        float_type = unstarred_name;
                else
                        float_type = "";
-               if (p.hasOpt())
-                       os << "placement " << p.getArg('[', ']') << '\n';
+               if (!opt.empty())
+                       os << "placement " << opt << '\n';
+               if (contains(opt, "H"))
+                       preamble.registerAutomaticallyLoadedPackage("float");
+               else {
+                       Floating const & fl = parent_context.textclass.floats()
+                               .getType(unstarred_name);
+                       if (!fl.floattype().empty() && fl.usesFloatPkg())
+                               preamble.registerAutomaticallyLoadedPackage("float");
+               }
+
                os << "wide " << convert<string>(is_starred)
                   << "\nsideways false"
                   << "\nstatus open\n\n";
@@ -1217,6 +1265,7 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                // we must make sure that the next item gets a \begin_layout.
                parent_context.new_paragraph(os);
                p.skip_spaces();
+                preamble.registerAutomaticallyLoadedPackage("rotfloat");
        }
 
        else if (name == "wrapfigure" || name == "wraptable") {
@@ -1249,6 +1298,7 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                // we must make sure that the next item gets a \begin_layout.
                parent_context.new_paragraph(os);
                p.skip_spaces();
+                preamble.registerAutomaticallyLoadedPackage("wrapfig");
        }
 
        else if (name == "minipage") {
@@ -1288,6 +1338,7 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                end_inset(os);
                p.skip_spaces();
                skip_braces(p); // eat {} that might by set by LyX behind comments
+               preamble.registerAutomaticallyLoadedPackage("verbatim");
        }
 
        else if (name == "lyxgreyedout") {
@@ -1350,12 +1401,16 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                        parent_context.add_extra_stuff("\\align center\n");
                else if (name == "singlespace")
                        parent_context.add_extra_stuff("\\paragraph_spacing single\n");
-               else if (name == "onehalfspace")
+               else if (name == "onehalfspace") {
                        parent_context.add_extra_stuff("\\paragraph_spacing onehalf\n");
-               else if (name == "doublespace")
+                       preamble.registerAutomaticallyLoadedPackage("setspace");
+               } else if (name == "doublespace") {
                        parent_context.add_extra_stuff("\\paragraph_spacing double\n");
-               else if (name == "spacing")
+                       preamble.registerAutomaticallyLoadedPackage("setspace");
+               } else if (name == "spacing") {
                        parent_context.add_extra_stuff("\\paragraph_spacing other " + p.verbatim_item() + "\n");
+                       preamble.registerAutomaticallyLoadedPackage("setspace");
+               }
                parse_text(p, os, FLAG_END, outer, parent_context);
                // Just in case the environment is empty
                parent_context.extra_stuff.erase();
@@ -1467,6 +1522,9 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                p.skip_spaces();
                if (!title_layout_found)
                        title_layout_found = newlayout->intitle;
+               set<string> const & req = newlayout->requires();
+               for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+                       preamble.registerAutomaticallyLoadedPackage(*it);
        }
 
        // The single '=' is meant here.
@@ -1849,6 +1907,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
 {
        Layout const * newlayout = 0;
        InsetLayout const * newinsetlayout = 0;
+       char const * const * where = 0;
        // Store the latest bibliographystyle and nocite{*} option
        // (needed for bibtex inset)
        string btprint;
@@ -1900,7 +1959,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        context.check_layout(os);
                        begin_inset(os, "Formula ");
                        Token const & n = p.get_token();
-                       if (n.cat() == catMath && outer) {
+                       bool const display(n.cat() == catMath && outer);
+                       if (display) {
                                // TeX's $$...$$ syntax for displayed math
                                os << "\\[";
                                parse_math(p, os, FLAG_SIMPLE, MATH_MODE);
@@ -1914,6 +1974,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                os << '$';
                        }
                        end_inset(os);
+                       if (display) {
+                               // Prevent the conversion of a line break to a
+                               // space (bug 7668). This does not change the
+                               // output, but looks ugly in LyX.
+                               eat_whitespace(p, os, context, false);
+                       }
                }
 
                else if (t.cat() == catSuper || t.cat() == catSub)
@@ -2035,8 +2101,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                os << t.cs();
                }
 
-               else if (t.cat() == catBegin &&
-                        p.next_token().cat() == catEnd) {
+               else if (t.cat() == catBegin) {
+                       Token const next = p.next_token();
+                       Token const end = p.next_next_token();
+                       if (next.cat() == catEnd) {
                        // {}
                        Token const prev = p.prev_token();
                        p.get_token();
@@ -2046,14 +2114,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                ; // ignore it in {}`` or -{}-
                        else
                                handle_ert(os, "{}", context);
-
-               }
-
-               else if (t.cat() == catBegin) {
+                       } else if (next.cat() == catEscape &&
+                                  is_known(next.cs(), known_quotes) &&
+                                  end.cat() == catEnd) {
+                               // Something like {\textquoteright} (e.g.
+                               // from writer2latex). LyX writes
+                               // \textquoteright{}, so we may skip the
+                               // braces here for better readability.
+                               parse_text_snippet(p, os, FLAG_BRACE_LAST,
+                                                  outer, context);
+                       } else {
                        context.check_layout(os);
                        // special handling of font attribute changes
                        Token const prev = p.prev_token();
-                       Token const next = p.next_token();
                        TeXFont const oldFont = context.font;
                        if (next.character() == '[' ||
                            next.character() == ']' ||
@@ -2126,6 +2199,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                parse_text_snippet(p, os, FLAG_BRACE_LAST,
                                                   outer, context);
                                handle_ert(os, "}", context);
+                               }
                        }
                }
 
@@ -2160,6 +2234,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        parse_math(p, os, FLAG_EQUATION, MATH_MODE);
                        os << "\\]";
                        end_inset(os);
+                       // Prevent the conversion of a line break to a space
+                       // (bug 7668). This does not change the output, but
+                       // looks ugly in LyX.
+                       eat_whitespace(p, os, context, false);
                }
 
                else if (t.cs() == "begin")
@@ -2185,7 +2263,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                // FIXME: This swallows comments, but we cannot use
                                //        eat_whitespace() since we must not output
                                //        anything before the item.
-                               s = p.getArg('[', ']');
+                               p.skip_spaces(true);
+                               s = p.verbatimOption();
                        } else
                                p.skip_spaces(false);
                        context.set_item();
@@ -2235,7 +2314,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                else if (t.cs() == "bibitem") {
                        context.set_item();
                        context.check_layout(os);
-                       string label = convert_command_inset_arg(p.getArg('[', ']'));
+                       eat_whitespace(p, os, context, false);
+                       string label = convert_command_inset_arg(p.verbatimOption());
                        string key = convert_command_inset_arg(p.verbatim_item());
                        if (contains(label, '\\') || contains(key, '\\')) {
                                // LyX can't handle LaTeX commands in labels or keys
@@ -2250,8 +2330,65 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        }
                }
 
-               else if (is_macro(p))
-                       parse_macro(p, os, context);
+               else if (is_macro(p)) {
+                       // catch the case of \def\inputGnumericTable
+                       bool macro = true;
+                       if (t.cs() == "def") {
+                               Token second = p.next_token();
+                               if (second.cs() == "inputGnumericTable") {
+                                       p.pushPosition();
+                                       p.get_token();
+                                       skip_braces(p);
+                                       Token third = p.get_token();
+                                       p.popPosition();
+                                       if (third.cs() == "input") {
+                                               p.get_token();
+                                               skip_braces(p);
+                                               p.get_token();
+                                               string name = normalize_filename(p.verbatim_item());
+                                               string const path = getMasterFilePath();
+                                               // We want to preserve relative / absolute filenames,
+                                               // therefore path is only used for testing
+                                               // The file extension is in every case ".tex".
+                                               // So we need to remove this extension and check for
+                                               // the original one.
+                                               name.erase(name.length() - 4, name.length());
+                                               if (!makeAbsPath(name, path).exists()) {
+                                                       char const * const Gnumeric_formats[] = {"gnumeric"
+                                                               "ods", "xls", 0};
+                                                       string const Gnumeric_name =
+                                                               find_file(name, path, Gnumeric_formats);
+                                                       if (!Gnumeric_name.empty())
+                                                               name = Gnumeric_name;
+                                               }
+                                               if (makeAbsPath(name, path).exists())
+                                                       fix_relative_filename(name);
+                                               else
+                                                       cerr << "Warning: Could not find file '"
+                                                            << name << "'." << endl;
+                                               context.check_layout(os);
+                                               begin_inset(os, "External\n\ttemplate ");
+                                               os << "GnumericSpreadsheet\n\tfilename "
+                                                  << name << "\n";
+                                               end_inset(os);
+                                               context.check_layout(os);
+                                               macro = false;
+                                               // register the packages that are automatically reloaded
+                                               // by the Gnumeric template
+                                               // Fixme: InsetExternal.cpp should give us that list
+                                               preamble.registerAutomaticallyLoadedPackage("array");
+                                               preamble.registerAutomaticallyLoadedPackage("calc");
+                                               preamble.registerAutomaticallyLoadedPackage("color");
+                                               preamble.registerAutomaticallyLoadedPackage("hhline");
+                                               preamble.registerAutomaticallyLoadedPackage("ifthen");
+                                               preamble.registerAutomaticallyLoadedPackage("longtable");
+                                               preamble.registerAutomaticallyLoadedPackage("multirow");
+                                       }
+                               }
+                       }
+                       if (macro)
+                               parse_macro(p, os, context);
+               }
 
                else if (t.cs() == "noindent") {
                        p.skip_spaces();
@@ -2297,6 +2434,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        p.skip_spaces();
                                        if (!title_layout_found)
                                                title_layout_found = newlayout->intitle;
+                                       set<string> const & req = newlayout->requires();
+                                       for (set<string>::const_iterator it = req.begin();
+                                            it != req.end(); it++)
+                                               preamble.registerAutomaticallyLoadedPackage(*it);
                                } else
                                        handle_ert(os, "\\date{" + date + '}',
                                                        context);
@@ -2314,6 +2455,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        p.skip_spaces();
                        if (!title_layout_found)
                                title_layout_found = newlayout->intitle;
+                       set<string> const & req = newlayout->requires();
+                       for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+                               preamble.registerAutomaticallyLoadedPackage(*it);
                }
 
                // Section headings and the like
@@ -2324,6 +2468,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        p.skip_spaces();
                        if (!title_layout_found)
                                title_layout_found = newlayout->intitle;
+                       set<string> const & req = newlayout->requires();
+                       for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+                               preamble.registerAutomaticallyLoadedPackage(*it);
                }
 
                else if (t.cs() == "caption") {
@@ -2647,50 +2794,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                handle_ert(os, "\\listof{" + name + "}", context);
                }
 
-               else if (t.cs() == "textrm")
-                       parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\family",
-                                             context.font.family, "roman");
-
-               else if (t.cs() == "textsf")
-                       parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\family",
-                                             context.font.family, "sans");
-
-               else if (t.cs() == "texttt")
-                       parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\family",
-                                             context.font.family, "typewriter");
-
-               else if (t.cs() == "textmd")
-                       parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\series",
-                                             context.font.series, "medium");
-
-               else if (t.cs() == "textbf")
-                       parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\series",
-                                             context.font.series, "bold");
-
-               else if (t.cs() == "textup")
+               else if ((where = is_known(t.cs(), known_text_font_families)))
                        parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\shape",
-                                             context.font.shape, "up");
+                               context, "\\family", context.font.family,
+                               known_coded_font_families[where - known_text_font_families]);
 
-               else if (t.cs() == "textit")
+               else if ((where = is_known(t.cs(), known_text_font_series)))
                        parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\shape",
-                                             context.font.shape, "italic");
+                               context, "\\series", context.font.series,
+                               known_coded_font_series[where - known_text_font_series]);
 
-               else if (t.cs() == "textsl")
+               else if ((where = is_known(t.cs(), known_text_font_shapes)))
                        parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\shape",
-                                             context.font.shape, "slanted");
-
-               else if (t.cs() == "textsc")
-                       parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                             context, "\\shape",
-                                             context.font.shape, "smallcaps");
+                               context, "\\shape", context.font.shape,
+                               known_coded_font_shapes[where - known_text_font_shapes]);
 
                else if (t.cs() == "textnormal" || t.cs() == "normalfont") {
                        context.check_layout(os);
@@ -2890,7 +3007,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                          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.
-                       char const * const * where = is_known(
+                       where = is_known(
                                t.cs() == "protect" ? p.get_token().cs() : t.cs(),
                                known_phrases);
                        context.check_layout(os);
@@ -2898,18 +3015,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        skip_spaces_braces(p);
                }
 
-               else if (is_known(t.cs(), known_ref_commands)) {
+               else if ((where = is_known(t.cs(), known_ref_commands))) {
                        string const opt = p.getOpt();
                        if (opt.empty()) {
                                context.check_layout(os);
-                               char const * const * where = is_known(t.cs(),
-                                       known_ref_commands);
                                begin_command_inset(os, "ref",
                                        known_coded_ref_commands[where - known_ref_commands]);
                                os << "reference \""
                                   << convert_command_inset_arg(p.verbatim_item())
                                   << "\"\n";
                                end_inset(os);
+                               if (t.cs() == "vref" || t.cs() == "vpageref")
+                                       preamble.registerAutomaticallyLoadedPackage("varioref");
+
                        } else {
                                // LyX does not support optional arguments of ref commands
                                handle_ert(os, t.asInput() + '[' + opt + "]{" +
@@ -3062,6 +3180,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                           << convert_command_inset_arg(p.verbatim_item())
                           << "\"\n";
                        end_inset(os);
+                       preamble.registerAutomaticallyLoadedPackage("nomencl");
                }
                
                else if (t.cs() == "label") {
@@ -3079,6 +3198,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        os << "type \"idx\"\n";
                        end_inset(os);
                        skip_spaces_braces(p);
+                       preamble.registerAutomaticallyLoadedPackage("makeidx");
+                       if (preamble.use_indices() == "true")
+                               preamble.registerAutomaticallyLoadedPackage("splitidx");
                }
 
                else if (t.cs() == "printnomenclature") {
@@ -3105,6 +3227,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                os << "width \"" << width << '\"';
                        end_inset(os);
                        skip_spaces_braces(p);
+                       preamble.registerAutomaticallyLoadedPackage("nomencl");
                }
 
                else if ((t.cs() == "textsuperscript" || t.cs() == "textsubscript")) {
@@ -3117,8 +3240,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                preamble.registerAutomaticallyLoadedPackage("subscript");
                }
 
-               else if (is_known(t.cs(), known_quotes)) {
-                       char const * const * where = is_known(t.cs(), known_quotes);
+               else if ((where = is_known(t.cs(), known_quotes))) {
                        context.check_layout(os);
                        begin_inset(os, "Quotes ");
                        os << known_coded_quotes[where - known_quotes];
@@ -3130,9 +3252,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        skip_braces(p);
                }
 
-               else if (is_known(t.cs(), known_sizes) &&
+               else if ((where = is_known(t.cs(), known_sizes)) &&
                         context.new_layout_allowed) {
-                       char const * const * where = is_known(t.cs(), known_sizes);
                        context.check_layout(os);
                        TeXFont const oldFont = context.font;
                        context.font.size = known_coded_sizes[where - known_sizes];
@@ -3140,10 +3261,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        eat_whitespace(p, os, context, false);
                }
 
-               else if (is_known(t.cs(), known_font_families) &&
+               else if ((where = is_known(t.cs(), known_font_families)) &&
                         context.new_layout_allowed) {
-                       char const * const * where =
-                               is_known(t.cs(), known_font_families);
                        context.check_layout(os);
                        TeXFont const oldFont = context.font;
                        context.font.family =
@@ -3152,10 +3271,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        eat_whitespace(p, os, context, false);
                }
 
-               else if (is_known(t.cs(), known_font_series) &&
+               else if ((where = is_known(t.cs(), known_font_series)) &&
                         context.new_layout_allowed) {
-                       char const * const * where =
-                               is_known(t.cs(), known_font_series);
                        context.check_layout(os);
                        TeXFont const oldFont = context.font;
                        context.font.series =
@@ -3164,10 +3281,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        eat_whitespace(p, os, context, false);
                }
 
-               else if (is_known(t.cs(), known_font_shapes) &&
+               else if ((where = is_known(t.cs(), known_font_shapes)) &&
                         context.new_layout_allowed) {
-                       char const * const * where =
-                               is_known(t.cs(), known_font_shapes);
                        context.check_layout(os);
                        TeXFont const oldFont = context.font;
                        context.font.shape =
@@ -3175,10 +3290,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        output_font_change(os, oldFont, context.font);
                        eat_whitespace(p, os, context, false);
                }
-               else if (is_known(t.cs(), known_old_font_families) &&
+               else if ((where = is_known(t.cs(), known_old_font_families)) &&
                         context.new_layout_allowed) {
-                       char const * const * where =
-                               is_known(t.cs(), known_old_font_families);
                        context.check_layout(os);
                        TeXFont const oldFont = context.font;
                        context.font.init();
@@ -3189,10 +3302,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        eat_whitespace(p, os, context, false);
                }
 
-               else if (is_known(t.cs(), known_old_font_series) &&
+               else if ((where = is_known(t.cs(), known_old_font_series)) &&
                         context.new_layout_allowed) {
-                       char const * const * where =
-                               is_known(t.cs(), known_old_font_series);
                        context.check_layout(os);
                        TeXFont const oldFont = context.font;
                        context.font.init();
@@ -3203,10 +3314,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        eat_whitespace(p, os, context, false);
                }
 
-               else if (is_known(t.cs(), known_old_font_shapes) &&
+               else if ((where = is_known(t.cs(), known_old_font_shapes)) &&
                         context.new_layout_allowed) {
-                       char const * const * where =
-                               is_known(t.cs(), known_old_font_shapes);
                        context.check_layout(os);
                        TeXFont const oldFont = context.font;
                        context.font.init();
@@ -3239,27 +3348,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        p.setEncoding(enc);
                }
 
-               else if (t.cs() == "ldots") {
+               else if ((where = is_known(t.cs(), known_special_chars))) {
                        context.check_layout(os);
-                       os << "\\SpecialChar \\ldots{}\n";
-                       skip_spaces_braces(p);
-               }
-
-               else if (t.cs() == "lyxarrow") {
-                       context.check_layout(os);
-                       os << "\\SpecialChar \\menuseparator\n";
-                       skip_spaces_braces(p);
-               }
-
-               else if (t.cs() == "textcompwordmark") {
-                       context.check_layout(os);
-                       os << "\\SpecialChar \\textcompwordmark{}\n";
-                       skip_spaces_braces(p);
-               }
-
-               else if (t.cs() == "slash") {
-                       context.check_layout(os);
-                       os << "\\SpecialChar \\slash{}\n";
+                       os << "\\SpecialChar \\"
+                          << known_coded_special_chars[where - known_special_chars]
+                          << '\n';
                        skip_spaces_braces(p);
                }
 
@@ -3351,13 +3444,17 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        string command = t.asInput() + "{" 
                                + trimSpaceAndEol(p.verbatim_item())
                                + "}";
-                       docstring s = encodings.fromLaTeXCommand(from_utf8(command), rem);
+                       set<string> req;
+                       docstring s = encodings.fromLaTeXCommand(from_utf8(command),
+                               Encodings::TEXT_CMD | Encodings::MATH_CMD, rem, &req);
                        if (!s.empty()) {
                                if (!rem.empty())
                                        cerr << "When parsing " << command 
                                             << ", result is " << to_utf8(s)
                                             << "+" << to_utf8(rem) << endl;
                                os << to_utf8(s);
+                               for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+                                       preamble.registerAutomaticallyLoadedPackage(*it);
                        } else
                                // we did not find a non-ert version
                                handle_ert(os, command, context);
@@ -3491,6 +3588,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                begin_command_inset(os, "include", name);
                                os << "preview false\n"
                                      "filename \"" << outname << "\"\n";
+                               if (t.cs() == "verbatiminput")
+                                       preamble.registerAutomaticallyLoadedPackage("verbatim");
                        }
                        end_inset(os);
                }
@@ -3575,17 +3674,30 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        parse_outer_box(p, os, FLAG_ITEM, outer, context, t.cs(), "");
 
                else if (t.cs() == "framebox") {
-                       string special = p.getFullOpt();
-                       special += p.getOpt();
-                       parse_outer_box(p, os, FLAG_ITEM, outer, context, t.cs(), special);
+                       if (p.next_token().character() == '(') {
+                               //the syntax is: \framebox(x,y)[position]{content}
+                               string arg = t.asInput();
+                               arg += p.getFullParentheseArg();
+                               arg += p.getFullOpt();
+                               eat_whitespace(p, os, context, false);
+                               handle_ert(os, arg + '{', context);
+                               eat_whitespace(p, os, context, false);
+                               parse_text(p, os, FLAG_ITEM, outer, context);
+                               handle_ert(os, "}", context);
+                       } else {
+                               string special = p.getFullOpt();
+                               special += p.getOpt();
+                               parse_outer_box(p, os, FLAG_ITEM, outer,
+                                               context, t.cs(), special);
+                       }
                }
 
                //\makebox() is part of the picture environment and different from \makebox{}
                //\makebox{} will be parsed by parse_box
                else if (t.cs() == "makebox") {
-                       string arg = t.asInput();
                        if (p.next_token().character() == '(') {
                                //the syntax is: \makebox(x,y)[position]{content}
+                               string arg = t.asInput();
                                arg += p.getFullParentheseArg();
                                arg += p.getFullOpt();
                                eat_whitespace(p, os, context, false);
@@ -3610,8 +3722,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        skip_spaces_braces(p);
                }
 
-               else if (is_known(t.cs(), known_spaces)) {
-                       char const * const * where = is_known(t.cs(), known_spaces);
+               else if ((where = is_known(t.cs(), known_spaces))) {
                        context.check_layout(os);
                        begin_inset(os, "space ");
                        os << '\\' << known_coded_spaces[where - known_spaces]
@@ -3645,7 +3756,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                         t.cs() == "DeclareRobustCommandx" ||
                         t.cs() == "newcommand" ||
                         t.cs() == "newcommandx" ||
-                        t.cs() == "providecommand" ||
+                        t.cs() == "providecommand" ||
                         t.cs() == "providecommandx" ||
                         t.cs() == "renewcommand" ||
                         t.cs() == "renewcommandx") {
@@ -3829,13 +3940,113 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        end_inset(os);
                }
 
+               else if (t.cs() == "includepdf") {
+                       p.skip_spaces();
+                       string const arg = p.getArg('[', ']');
+                       map<string, string> opts;
+                       vector<string> keys;
+                       split_map(arg, opts, keys);
+                       string name = normalize_filename(p.verbatim_item());
+                       string const path = getMasterFilePath();
+                       // We want to preserve relative / absolute filenames,
+                       // therefore path is only used for testing
+                       if (!makeAbsPath(name, path).exists()) {
+                               // The file extension is probably missing.
+                               // Now try to find it out.
+                               char const * const pdfpages_format[] = {"pdf", 0};
+                               string const pdftex_name =
+                                       find_file(name, path, pdfpages_format);
+                               if (!pdftex_name.empty()) {
+                                       name = pdftex_name;
+                                       pdflatex = true;
+                               }
+                       }
+                       if (makeAbsPath(name, path).exists())
+                               fix_relative_filename(name);
+                       else
+                               cerr << "Warning: Could not find file '"
+                                    << name << "'." << endl;
+                       // write output
+                       context.check_layout(os);
+                       begin_inset(os, "External\n\ttemplate ");
+                       os << "PDFPages\n\tfilename "
+                          << name << "\n";
+                       // parse the options
+                       if (opts.find("pages") != opts.end())
+                               os << "\textra LaTeX \"pages="
+                                  << opts["pages"] << "\"\n";
+                       if (opts.find("angle") != opts.end())
+                               os << "\trotateAngle "
+                                  << opts["angle"] << '\n';
+                       if (opts.find("origin") != opts.end()) {
+                               ostringstream ss;
+                               string const opt = opts["origin"];
+                               if (opt == "tl") ss << "topleft";
+                               if (opt == "bl") ss << "bottomleft";
+                               if (opt == "Bl") ss << "baselineleft";
+                               if (opt == "c") ss << "center";
+                               if (opt == "tc") ss << "topcenter";
+                               if (opt == "bc") ss << "bottomcenter";
+                               if (opt == "Bc") ss << "baselinecenter";
+                               if (opt == "tr") ss << "topright";
+                               if (opt == "br") ss << "bottomright";
+                               if (opt == "Br") ss << "baselineright";
+                               if (!ss.str().empty())
+                                       os << "\trotateOrigin " << ss.str() << '\n';
+                               else
+                                       cerr << "Warning: Ignoring unknown includegraphics origin argument '" << opt << "'\n";
+                       }
+                       if (opts.find("width") != opts.end())
+                               os << "\twidth "
+                                  << translate_len(opts["width"]) << '\n';
+                       if (opts.find("height") != opts.end())
+                               os << "\theight "
+                                  << translate_len(opts["height"]) << '\n';
+                       if (opts.find("keepaspectratio") != opts.end())
+                               os << "\tkeepAspectRatio\n";
+                       end_inset(os);
+                       context.check_layout(os);
+               }
+
+               else if (t.cs() == "loadgame") {
+                       p.skip_spaces();
+                       string name = normalize_filename(p.verbatim_item());
+                       string const path = getMasterFilePath();
+                       // We want to preserve relative / absolute filenames,
+                       // therefore path is only used for testing
+                       if (!makeAbsPath(name, path).exists()) {
+                               // The file extension is probably missing.
+                               // Now try to find it out.
+                               char const * const lyxskak_format[] = {"fen", 0};
+                               string const lyxskak_name =
+                                       find_file(name, path, lyxskak_format);
+                               if (!lyxskak_name.empty())
+                                       name = lyxskak_name;
+                       }
+                       if (makeAbsPath(name, path).exists())
+                               fix_relative_filename(name);
+                       else
+                               cerr << "Warning: Could not find file '"
+                                    << name << "'." << endl;
+                       context.check_layout(os);
+                       begin_inset(os, "External\n\ttemplate ");
+                       os << "ChessDiagram\n\tfilename "
+                          << name << "\n";
+                       end_inset(os);
+                       context.check_layout(os);
+                       // after a \loadgame follows a \showboard
+                       if (p.get_token().asInput() == "showboard")
+                               p.get_token();
+               }
+
                else {
                        // try to see whether the string is in unicodesymbols
                        // Only use text mode commands, since we are in text mode here,
                        // and math commands may be invalid (bug 6797)
                        docstring rem;
+                       set<string> req;
                        docstring s = encodings.fromLaTeXCommand(from_utf8(t.asInput()),
-                                                                rem, Encodings::TEXT_CMD);
+                                                                Encodings::TEXT_CMD, rem, &req);
                        if (!s.empty()) {
                                if (!rem.empty())
                                        cerr << "When parsing " << t.cs() 
@@ -3844,6 +4055,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                context.check_layout(os);
                                os << to_utf8(s);
                                skip_spaces_braces(p);
+                               for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+                                       preamble.registerAutomaticallyLoadedPackage(*it);
                        }
                        //cerr << "#: " << t << " mode: " << mode << endl;
                        // heuristic: read up to next non-nested space