#include "FloatList.h"
#include "LaTeXPackages.h"
#include "Layout.h"
-#include "Length.h"
#include "Preamble.h"
#include "insets/ExternalTemplate.h"
#include "support/convert.h"
#include "support/FileName.h"
#include "support/filetools.h"
+#include "support/Length.h"
#include "support/lstrings.h"
#include "support/lyxtime.h"
namespace {
-void output_arguments(ostream &, Parser &, bool, bool, string, Context &,
+void output_arguments(ostream &, Parser &, bool, bool, const string &, Context &,
Layout::LaTeXArgMap const &);
}
void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
Context const & context, InsetLayout const * layout,
- string const rdelim)
+ string const & rdelim)
{
bool const forcePlainLayout =
layout ? layout->forcePlainLayout() : false;
void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
Context const & context, string const & name,
- string const rdelim = string())
+ string const & rdelim = string())
{
InsetLayout const * layout = 0;
DocumentClass::InsetLayouts::const_iterator it =
/// spaces known by InsetSpace
char const * const known_spaces[] = { " ", "space", ",",
"thinspace", "quad", "qquad", "enspace", "enskip",
-"negthinspace", "negmedspace", "negthickspace", "textvisiblespace",
-"hfill", "dotfill", "hrulefill", "leftarrowfill", "rightarrowfill",
-"upbracefill", "downbracefill", 0};
+"medspace", "thickspace", "negthinspace", "negmedspace", "negthickspace",
+"textvisiblespace", "hfill", "dotfill", "hrulefill", "leftarrowfill",
+"rightarrowfill", "upbracefill", "downbracefill", 0};
/// the same as known_spaces with .lyx names
char const * const known_coded_spaces[] = { "space{}", "space{}",
"thinspace{}", "thinspace{}", "quad{}", "qquad{}", "enspace{}", "enskip{}",
-"negthinspace{}", "negmedspace{}", "negthickspace{}", "textvisiblespace{}",
-"hfill{}", "dotfill{}", "hrulefill{}", "leftarrowfill{}", "rightarrowfill{}",
-"upbracefill{}", "downbracefill{}", 0};
+"medspace{}", "thickspace{}", "negthinspace{}", "negmedspace{}", "negthickspace{}",
+"textvisiblespace{}", "hfill{}", "dotfill{}", "hrulefill{}", "leftarrowfill{}",
+"rightarrowfill{}", "upbracefill{}", "downbracefill{}", 0};
/// known TIPA combining diacritical marks
char const * const known_tipa_marks[] = {"textsubwedge", "textsubumlaut",
/// If we have ambiguous quotation marks, make a smart guess
/// based on main quote style
-string guessQuoteStyle(string in, bool const opening)
+string guessQuoteStyle(string const & in, bool const opening)
{
string res = in;
if (prefixIs(in, "qr")) {// straight quote
res = "brs";
else if (preamble.quotesStyle() == "french")
res = "frs";
+ else if (preamble.quotesStyle() == "hungarian")
+ res = "hrd";
else if (preamble.quotesStyle() == "swedish")
res = opening ? "sld" : "srd";
} else if (in == "els") {// `
res = "fld";
else if (preamble.quotesStyle() == "russian")
res = "rld";
+ else if (preamble.quotesStyle() == "hungarian")
+ res = "hrs";
} else if (in == "ald") {// <<
if (preamble.quotesStyle() == "swiss")
res = "crd";
res = "frd";
else if (preamble.quotesStyle() == "russian")
res = "rrd";
+ else if (preamble.quotesStyle() == "hungarian")
+ res = "hls";
} else if (in == "ars") {// >
if (preamble.quotesStyle() == "swiss")
res = "cls";
} else if (in == "gld") {// ,,
if (preamble.quotesStyle() == "polish")
res = "pld";
+ else if (preamble.quotesStyle() == "hungarian")
+ res = "hld";
else if (preamble.quotesStyle() == "russian")
res = "rls";
} else if (in == "gls") {// ,
}
+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
/// try to convert \p s to a valid InsetCommand argument
/// without trying to recode macros.
-string convert_literate_command_inset_arg(string s)
+string convert_literate_command_inset_arg(string const & s)
{
// LyX cannot handle newlines in a latex command
return subst(s, "\n", " ");
void output_ert(ostream & os, string const & s, Context & context)
{
context.check_layout(os);
- for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
- if (*it == '\\')
+ for (char const c : s) {
+ if (c == '\\')
os << "\n\\backslash\n";
- else if (*it == '\n') {
+ else if (c == '\n') {
context.new_paragraph(os);
context.check_layout(os);
} else
- os << *it;
+ os << c;
}
context.check_end_layout(os);
}
}
-void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, string const prefix,
+void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, string const & prefix,
Context & context, Layout::LaTeXArgMap const & latexargs)
{
if (context.layout->latextype != LATEX_ITEM_ENVIRONMENT || !prefix.empty()) {
*
* 2. could be used to suppress as many spaces as possible. This has two effects:
* - Reimporting LyX generated LaTeX files changes almost no whitespace
- * - Superflous whitespace from non LyX generated LaTeX files is removed.
+ * - Superfluous whitespace from non LyX generated LaTeX files is removed.
* The drawback is that the logic inside the function becomes
* complicated, and that is the reason why it is not implemented.
*/
os << "use_makebox " << (inner_type == "makebox") << '\n';
if (outer_type == "mbox" || (outer_type == "fbox" && inner_type.empty()))
os << "width \"\"\n";
- // for values like "1.5\width" LyX uses "1.5in" as width ad sets "width" as sepecial
+ // for values like "1.5\width" LyX uses "1.5in" as width and sets "width" as special
else if (contains(width_unit, '\\'))
os << "width \"" << width_value << "in" << "\"\n";
else
if (specialfont)
parent_context.new_layout_allowed = false;
output_ert_inset(os, "\\begin{" + name + "}", parent_context);
+ // Try to handle options: Look if we have 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)
string const unstarred_name = rtrim(name, "*");
active_environments.push_back(name);
- if (is_math_env(name)) {
- parent_context.check_layout(os);
- begin_inset(os, "Formula ");
- os << "\\begin{" << name << "}";
- 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);
+ // We use this loop and break out after a condition is met
+ // rather than a huge else-if-chain.
+ while (true) {
+ if (is_math_env(name)) {
+ parent_context.check_layout(os);
+ begin_inset(os, "Formula ");
+ os << "\\begin{" << name << "}";
+ 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);
+ }
+ break;
}
- }
- else if (is_known(name, preamble.polyglossia_languages)) {
- // We must begin a new paragraph if not already done
- if (! parent_context.atParagraphStart()) {
- parent_context.check_end_layout(os);
+ // We need to use fromPolyglossiaEnvironment due to Arabic > arabic
+ 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);
+ parent_context.new_paragraph(os);
+ }
+ // store previous language because we must reset it at the end
+ string const lang_old = parent_context.font.language;
+ // save new language in context so that it is
+ // handled by parse_text
+ parent_context.font.language =
+ preamble.polyglossia2lyx(fromPolyglossiaEnvironment(name));
+ parse_text(p, os, FLAG_END, outer, parent_context);
+ // reset previous language
+ parent_context.font.language = lang_old;
+ // Just in case the environment is empty
+ parent_context.extra_stuff.erase();
+ // We must begin a new paragraph to reset the language
parent_context.new_paragraph(os);
+ p.skip_spaces();
+ break;
}
- // save the language in the context so that it is
- // handled by parse_text
- parent_context.font.language = preamble.polyglossia2lyx(name);
- 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 to reset the language
- parent_context.new_paragraph(os);
- p.skip_spaces();
- }
- else if (unstarred_name == "tabular" || name == "longtable"
- || name == "tabularx" || name == "xltabular") {
- eat_whitespace(p, os, parent_context, false);
- string width = "0pt";
- string halign;
- if ((name == "longtable" || name == "xltabular") && 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*" || name == "tabularx" || name == "xltabular") {
- width = lyx::translate_len(p.getArg('{', '}'));
+ if (unstarred_name == "tabular" || name == "longtable"
+ || name == "tabularx" || name == "xltabular") {
eat_whitespace(p, os, parent_context, false);
+ string width = "0pt";
+ string halign;
+ if ((name == "longtable" || name == "xltabular") && 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*" || name == "tabularx" || name == "xltabular") {
+ 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, halign, parent_context);
+ end_inset(os);
+ p.skip_spaces();
+ break;
}
- parent_context.check_layout(os);
- begin_inset(os, "Tabular ");
- handle_tabular(p, os, name, width, halign, parent_context);
- end_inset(os);
- p.skip_spaces();
- }
- 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");
- // store the float type for subfloats
- // subfloats only work with figures and tables
- if (unstarred_name == "figure")
- float_type = unstarred_name;
- else if (unstarred_name == "table")
- float_type = unstarred_name;
- else
- float_type = "";
- if (!opt.empty())
- os << "placement " << opt << '\n';
- if (contains(opt, "H"))
- preamble.registerAutomaticallyLoadedPackage("float");
- else {
- Floating const & fl = parent_context.textclass.floats()
- .getType(unstarred_name);
- if (!fl.floattype().empty() && fl.usesFloatPkg())
+ 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");
+ // store the float type for subfloats
+ // subfloats only work with figures and tables
+ if (unstarred_name == "figure")
+ float_type = unstarred_name;
+ else if (unstarred_name == "table")
+ float_type = unstarred_name;
+ else
+ float_type = "";
+ if (!opt.empty())
+ os << "placement " << opt << '\n';
+ if (contains(opt, "H"))
preamble.registerAutomaticallyLoadedPackage("float");
- }
+ else {
+ Floating const & fl = parent_context.textclass.floats()
+ .getType(unstarred_name);
+ if (!fl.floattype().empty() && fl.usesFloatPkg())
+ preamble.registerAutomaticallyLoadedPackage("float");
+ }
- os << "wide " << convert<string>(is_starred)
- << "\nsideways false"
- << "\nstatus open\n\n";
- parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
- end_inset(os);
- // We don't need really a new paragraph, but
- // we must make sure that the next item gets a \begin_layout.
- parent_context.new_paragraph(os);
- p.skip_spaces();
- // the float is parsed thus delete the type
- float_type = "";
- }
+ os << "wide " << convert<string>(is_starred)
+ << "\nsideways false"
+ << "\nstatus open\n\n";
+ parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+ end_inset(os);
+ // We don't need really a new paragraph, but
+ // we must make sure that the next item gets a \begin_layout.
+ parent_context.new_paragraph(os);
+ p.skip_spaces();
+ // the float is parsed thus delete the type
+ float_type = "";
+ break;
+ }
- else if (unstarred_name == "sidewaysfigure"
- || unstarred_name == "sidewaystable"
- || unstarred_name == "sidewaysalgorithm") {
- string const opt = p.hasOpt() ? p.getArg('[', ']') : string();
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_layout(os);
- if (unstarred_name == "sidewaysfigure")
- begin_inset(os, "Float figure\n");
- else if (unstarred_name == "sidewaystable")
- begin_inset(os, "Float table\n");
- else if (unstarred_name == "sidewaysalgorithm")
- begin_inset(os, "Float algorithm\n");
- if (!opt.empty())
- os << "placement " << opt << '\n';
- if (contains(opt, "H"))
- preamble.registerAutomaticallyLoadedPackage("float");
- os << "wide " << convert<string>(is_starred)
- << "\nsideways true"
- << "\nstatus open\n\n";
- parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
- end_inset(os);
- // We don't need really a new paragraph, but
- // we must make sure that the next item gets a \begin_layout.
- parent_context.new_paragraph(os);
- p.skip_spaces();
- preamble.registerAutomaticallyLoadedPackage("rotfloat");
- }
+ if (unstarred_name == "sidewaysfigure"
+ || unstarred_name == "sidewaystable"
+ || unstarred_name == "sidewaysalgorithm") {
+ string const opt = p.hasOpt() ? p.getArg('[', ']') : string();
+ eat_whitespace(p, os, parent_context, false);
+ parent_context.check_layout(os);
+ if (unstarred_name == "sidewaysfigure")
+ begin_inset(os, "Float figure\n");
+ else if (unstarred_name == "sidewaystable")
+ begin_inset(os, "Float table\n");
+ else if (unstarred_name == "sidewaysalgorithm")
+ begin_inset(os, "Float algorithm\n");
+ if (!opt.empty())
+ os << "placement " << opt << '\n';
+ if (contains(opt, "H"))
+ preamble.registerAutomaticallyLoadedPackage("float");
+ os << "wide " << convert<string>(is_starred)
+ << "\nsideways true"
+ << "\nstatus open\n\n";
+ parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+ end_inset(os);
+ // We don't need really a new paragraph, but
+ // we must make sure that the next item gets a \begin_layout.
+ parent_context.new_paragraph(os);
+ p.skip_spaces();
+ preamble.registerAutomaticallyLoadedPackage("rotfloat");
+ break;
+ }
- else if (name == "wrapfigure" || name == "wraptable") {
- // syntax is \begin{wrapfigure}[lines]{placement}[overhang]{width}
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_layout(os);
- // default values
- string lines = "0";
- string overhang = "0col%";
- // parse
- if (p.hasOpt())
- lines = p.getArg('[', ']');
- string const placement = p.getArg('{', '}');
- if (p.hasOpt())
- overhang = p.getArg('[', ']');
- string const width = p.getArg('{', '}');
- // write
- if (name == "wrapfigure")
- begin_inset(os, "Wrap figure\n");
- else
- begin_inset(os, "Wrap table\n");
- os << "lines " << lines
- << "\nplacement " << placement
- << "\noverhang " << lyx::translate_len(overhang)
- << "\nwidth " << lyx::translate_len(width)
- << "\nstatus open\n\n";
- parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
- end_inset(os);
- // We don't need really a new paragraph, but
- // we must make sure that the next item gets a \begin_layout.
- parent_context.new_paragraph(os);
- p.skip_spaces();
- preamble.registerAutomaticallyLoadedPackage("wrapfig");
- }
+ if (name == "wrapfigure" || name == "wraptable") {
+ // syntax is \begin{wrapfigure}[lines]{placement}[overhang]{width}
+ eat_whitespace(p, os, parent_context, false);
+ parent_context.check_layout(os);
+ // default values
+ string lines = "0";
+ string overhang = "0col%";
+ // parse
+ if (p.hasOpt())
+ lines = p.getArg('[', ']');
+ string const placement = p.getArg('{', '}');
+ if (p.hasOpt())
+ overhang = p.getArg('[', ']');
+ string const width = p.getArg('{', '}');
+ // write
+ if (name == "wrapfigure")
+ begin_inset(os, "Wrap figure\n");
+ else
+ begin_inset(os, "Wrap table\n");
+ os << "lines " << lines
+ << "\nplacement " << placement
+ << "\noverhang " << lyx::translate_len(overhang)
+ << "\nwidth " << lyx::translate_len(width)
+ << "\nstatus open\n\n";
+ parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+ end_inset(os);
+ // We don't need really a new paragraph, but
+ // we must make sure that the next item gets a \begin_layout.
+ parent_context.new_paragraph(os);
+ p.skip_spaces();
+ preamble.registerAutomaticallyLoadedPackage("wrapfig");
+ break;
+ }
- else if (name == "minipage") {
- eat_whitespace(p, os, parent_context, false);
- // Test whether this is an outer box of a shaded box
- p.pushPosition();
- // swallow arguments
- while (p.hasOpt()) {
- p.getArg('[', ']');
+ if (name == "minipage") {
+ eat_whitespace(p, os, parent_context, false);
+ // Test whether this is an outer box of a shaded box
+ p.pushPosition();
+ // swallow arguments
+ while (p.hasOpt()) {
+ p.getArg('[', ']');
+ p.skip_spaces(true);
+ }
+ p.getArg('{', '}');
p.skip_spaces(true);
+ Token t = p.get_token();
+ bool shaded = false;
+ if (t.asInput() == "\\begin") {
+ p.skip_spaces(true);
+ if (p.getArg('{', '}') == "shaded")
+ shaded = true;
+ }
+ p.popPosition();
+ if (shaded)
+ parse_outer_box(p, os, FLAG_END, outer,
+ parent_context, name, "shaded");
+ else
+ parse_box(p, os, 0, FLAG_END, outer, parent_context,
+ "", "", name, "", "");
+ p.skip_spaces();
+ break;
}
- p.getArg('{', '}');
- p.skip_spaces(true);
- Token t = p.get_token();
- bool shaded = false;
- if (t.asInput() == "\\begin") {
- p.skip_spaces(true);
- if (p.getArg('{', '}') == "shaded")
- shaded = true;
+
+ if (name == "comment") {
+ eat_whitespace(p, os, parent_context, false);
+ parent_context.check_layout(os);
+ begin_inset(os, "Note Comment\n");
+ os << "status open\n";
+ parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+ end_inset(os);
+ p.skip_spaces();
+ skip_braces(p); // eat {} that might by set by LyX behind comments
+ preamble.registerAutomaticallyLoadedPackage("verbatim");
+ break;
}
- p.popPosition();
- if (shaded)
- parse_outer_box(p, os, FLAG_END, outer,
- parent_context, name, "shaded");
- else
- parse_box(p, os, 0, FLAG_END, outer, parent_context,
- "", "", name, "", "");
- p.skip_spaces();
- }
- else if (name == "comment") {
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_layout(os);
- begin_inset(os, "Note Comment\n");
- os << "status open\n";
- parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
- end_inset(os);
- p.skip_spaces();
- skip_braces(p); // eat {} that might by set by LyX behind comments
- preamble.registerAutomaticallyLoadedPackage("verbatim");
- }
+ if (unstarred_name == "verbatim") {
+ // FIXME: this should go in the generic code that
+ // handles environments defined in layout file that
+ // have "PassThru 1". However, the code over there is
+ // already too complicated for my taste.
+ string const ascii_name =
+ (name == "verbatim*") ? "Verbatim*" : "Verbatim";
+ parent_context.new_paragraph(os);
+ Context context(true, parent_context.textclass,
+ &parent_context.textclass[from_ascii(ascii_name)]);
+ string s = p.verbatimEnvironment(name);
+ output_ert(os, s, context);
+ p.skip_spaces();
+ break;
+ }
- else if (unstarred_name == "verbatim") {
- // FIXME: this should go in the generic code that
- // handles environments defined in layout file that
- // have "PassThru 1". However, the code over there is
- // already too complicated for my taste.
- string const ascii_name =
- (name == "verbatim*") ? "Verbatim*" : "Verbatim";
- parent_context.new_paragraph(os);
- Context context(true, parent_context.textclass,
- &parent_context.textclass[from_ascii(ascii_name)]);
- string s = p.verbatimEnvironment(name);
- output_ert(os, s, context);
- p.skip_spaces();
- }
+ if (name == "IPA") {
+ eat_whitespace(p, os, parent_context, false);
+ parent_context.check_layout(os);
+ begin_inset(os, "IPA\n");
+ parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+ end_inset(os);
+ p.skip_spaces();
+ preamble.registerAutomaticallyLoadedPackage("tipa");
+ preamble.registerAutomaticallyLoadedPackage("tipx");
+ break;
+ }
- else if (name == "IPA") {
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_layout(os);
- begin_inset(os, "IPA\n");
- parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
- end_inset(os);
- p.skip_spaces();
- preamble.registerAutomaticallyLoadedPackage("tipa");
- preamble.registerAutomaticallyLoadedPackage("tipx");
- }
-
- else if (name == parent_context.textclass.titlename()
- && parent_context.textclass.titletype() == TITLE_ENVIRONMENT) {
+ 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();
- }
+ break;
+ }
- else if (name == "CJK") {
- // the scheme is \begin{CJK}{encoding}{mapping}text\end{CJK}
- // It is impossible to decide if a CJK environment was in its own paragraph or within
- // a line. We therefore always assume a paragraph since the latter is a rare case.
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_end_layout(os);
- // store the encoding to be able to reset it
- string const encoding_old = p.getEncoding();
- string const encoding = p.getArg('{', '}');
- // FIXME: For some reason JIS does not work. Although the text
- // in tests/CJK.tex is identical with the SJIS version if you
- // convert both snippets using the recode command line utility,
- // the resulting .lyx file contains some extra characters if
- // you set buggy_encoding to false for JIS.
- bool const buggy_encoding = encoding == "JIS";
- if (!buggy_encoding)
- p.setEncoding(encoding, Encoding::CJK);
- else {
- // FIXME: This will read garbage, since the data is not encoded in utf8.
- p.setEncoding("UTF-8");
+ if (name == "CJK") {
+ // the scheme is \begin{CJK}{encoding}{mapping}text\end{CJK}
+ // It is impossible to decide if a CJK environment was in its own paragraph or within
+ // a line. We therefore always assume a paragraph since the latter is a rare case.
+ eat_whitespace(p, os, parent_context, false);
+ parent_context.check_end_layout(os);
+ // store the encoding to be able to reset it
+ string const encoding_old = p.getEncoding();
+ string const encoding = p.getArg('{', '}');
+ // FIXME: For some reason JIS does not work. Although the text
+ // in tests/CJK.tex is identical with the SJIS version if you
+ // convert both snippets using the recode command line utility,
+ // the resulting .lyx file contains some extra characters if
+ // you set buggy_encoding to false for JIS.
+ bool const buggy_encoding = encoding == "JIS";
+ if (!buggy_encoding)
+ p.setEncoding(encoding, Encoding::CJK);
+ else {
+ // FIXME: This will read garbage, since the data is not encoded in utf8.
+ p.setEncoding("UTF-8");
+ }
+ // LyX only supports the same mapping for all CJK
+ // environments, so we might need to output everything as ERT
+ string const mapping = trim(p.getArg('{', '}'));
+ char const * const * const where =
+ is_known(encoding, supported_CJK_encodings);
+ if (!buggy_encoding && !preamble.fontCJKSet())
+ preamble.fontCJK(mapping);
+ bool knownMapping = mapping == preamble.fontCJK();
+ if (buggy_encoding || !knownMapping || !where) {
+ parent_context.check_layout(os);
+ output_ert_inset(os, "\\begin{" + name + "}{" + encoding + "}{" + mapping + "}",
+ parent_context);
+ // we must parse the content as verbatim because e.g. JIS can contain
+ // normally invalid characters
+ // FIXME: This works only for the most simple cases.
+ // Since TeX control characters are not parsed,
+ // 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) {
+ 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
+ os << *it;
+ }
+ output_ert_inset(os, "\\end{" + name + "}",
+ parent_context);
+ } else {
+ string const lang =
+ supported_CJK_languages[where - supported_CJK_encodings];
+ // store the language because we must reset it at the end
+ string const lang_old = parent_context.font.language;
+ parent_context.font.language = lang;
+ parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+ parent_context.font.language = lang_old;
+ parent_context.new_paragraph(os);
+ }
+ p.setEncoding(encoding_old);
+ p.skip_spaces();
+ break;
}
- // LyX only supports the same mapping for all CJK
- // environments, so we might need to output everything as ERT
- string const mapping = trim(p.getArg('{', '}'));
- char const * const * const where =
- is_known(encoding, supported_CJK_encodings);
- if (!buggy_encoding && !preamble.fontCJKSet())
- preamble.fontCJK(mapping);
- bool knownMapping = mapping == preamble.fontCJK();
- if (buggy_encoding || !knownMapping || !where) {
+
+ if (name == "lyxgreyedout") {
+ eat_whitespace(p, os, parent_context, false);
parent_context.check_layout(os);
- output_ert_inset(os, "\\begin{" + name + "}{" + encoding + "}{" + mapping + "}",
- parent_context);
- // we must parse the content as verbatim because e.g. JIS can contain
- // normally invalid characters
- // FIXME: This works only for the most simple cases.
- // Since TeX control characters are not parsed,
- // 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) {
- 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
- os << *it;
- }
- output_ert_inset(os, "\\end{" + name + "}",
- parent_context);
- } else {
- string const lang =
- supported_CJK_languages[where - supported_CJK_encodings];
- // store the language because we must reset it at the end
- string const lang_old = parent_context.font.language;
- parent_context.font.language = lang;
+ begin_inset(os, "Note Greyedout\n");
+ os << "status open\n";
parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
- parent_context.font.language = lang_old;
- parent_context.new_paragraph(os);
+ end_inset(os);
+ p.skip_spaces();
+ if (!preamble.notefontcolor().empty())
+ preamble.registerAutomaticallyLoadedPackage("color");
+ break;
}
- p.setEncoding(encoding_old);
- p.skip_spaces();
- }
-
- else if (name == "lyxgreyedout") {
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_layout(os);
- begin_inset(os, "Note Greyedout\n");
- os << "status open\n";
- parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
- end_inset(os);
- p.skip_spaces();
- if (!preamble.notefontcolor().empty())
- preamble.registerAutomaticallyLoadedPackage("color");
- }
- else if (name == "btSect") {
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_layout(os);
- begin_command_inset(os, "bibtex", "bibtex");
- string bibstyle = "plain";
- if (p.hasOpt()) {
- bibstyle = p.getArg('[', ']');
- p.skip_spaces(true);
- }
- string const bibfile = p.getArg('{', '}');
- eat_whitespace(p, os, parent_context, false);
- Token t = p.get_token();
- if (t.asInput() == "\\btPrintCited") {
- p.skip_spaces(true);
- os << "btprint " << '"' << "btPrintCited" << '"' << "\n";
- }
- if (t.asInput() == "\\btPrintNotCited") {
- p.skip_spaces(true);
- os << "btprint " << '"' << "btPrintNotCited" << '"' << "\n";
+ if (name == "btSect") {
+ eat_whitespace(p, os, parent_context, false);
+ parent_context.check_layout(os);
+ begin_command_inset(os, "bibtex", "bibtex");
+ string bibstyle = "plain";
+ if (p.hasOpt()) {
+ bibstyle = p.getArg('[', ']');
+ p.skip_spaces(true);
+ }
+ string const bibfile = p.getArg('{', '}');
+ eat_whitespace(p, os, parent_context, false);
+ Token t = p.get_token();
+ if (t.asInput() == "\\btPrintCited") {
+ p.skip_spaces(true);
+ os << "btprint " << '"' << "btPrintCited" << '"' << "\n";
+ }
+ if (t.asInput() == "\\btPrintNotCited") {
+ p.skip_spaces(true);
+ os << "btprint " << '"' << "btPrintNotCited" << '"' << "\n";
+ }
+ if (t.asInput() == "\\btPrintAll") {
+ p.skip_spaces(true);
+ os << "btprint " << '"' << "btPrintAll" << '"' << "\n";
+ }
+ os << "bibfiles " << '"' << bibfile << "\"\n"
+ << "options " << '"' << bibstyle << "\"\n";
+ parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+ end_inset(os);
+ p.skip_spaces();
+ break;
}
- if (t.asInput() == "\\btPrintAll") {
- p.skip_spaces(true);
- os << "btprint " << '"' << "btPrintAll" << '"' << "\n";
+
+ 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);
+ break;
}
- os << "bibfiles " << '"' << bibfile << "\"\n"
- << "options " << '"' << bibstyle << "\"\n";
- parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
- end_inset(os);
- p.skip_spaces();
- }
- else if (name == "btUnit") {
- string const nt = p.next_next_token().cs();
- if (nt == "part" || nt == "chapter"
- || nt == "section" || nt == "subsection") {
- active_environments.push_back("btUnit");
- preamble.multibib(nt);
- } else
- parse_unknown_environment(p, name, os, FLAG_END, outer,
- parent_context);
- }
+ // This is only attempted at turn environments that consist only
+ // of a tabular (this is how tables in LyX, modulo longtables, are rotated).
+ // Thus we will fall through in other cases.
+ if (name == "turn") {
+ // We check if the next thing is a tabular[*|x]
+ p.pushPosition();
+ p.getArg('{', '}');// eat turn argument
+ bool found_end = false;
+ bool only_table = false;
+ bool end_table = false;
+ p.get_token();
+ p.get_token();
+ string envname = p.getArg('{', '}');
+ if (rtrim(envname, "*") == "tabular" || envname == "tabularx") {
+ // Now we check if the table is the only content
+ // of the turn environment
+ string const tenv = envname;
+ while (!found_end && !end_table && p.good()) {
+ envname = p.next_token().cat() == catBegin
+ ? p.getArg('{', '}') : string();
+ Token const & t = p.get_token();
+ p.skip_spaces();
+ end_table = t.asInput() != "\\end"
+ && envname == tenv;
+ found_end = t.asInput() == "\\end"
+ && envname == "turn";
+ }
+ if (end_table) {
+ p.get_token();
+ envname = p.getArg('{', '}');
+ only_table = p.next_next_token().asInput() == "\\end"
+ && envname == "turn";
+ }
+ if (only_table) {
+ p.popPosition();
+ string const angle = p.getArg('{', '}');
+ p.skip_spaces();
+ int const save_tablerotation = parent_context.tablerotation;
+ parent_context.tablerotation = convert<int>(angle);
+ parse_text(p, os, FLAG_END, outer, parent_context);
+ parent_context.tablerotation = save_tablerotation;
+ p.skip_spaces();
+ break;
+ }
+ // fall through
+ }
+ // fall through
+ p.popPosition();
+ }
- else if (name == "framed" || name == "shaded") {
- eat_whitespace(p, os, parent_context, false);
- parse_outer_box(p, os, FLAG_END, outer, parent_context, name, "");
- p.skip_spaces();
- preamble.registerAutomaticallyLoadedPackage("framed");
- }
+ // This is only attempted at landscape environments that consist only
+ // of a longtable (this is how longtables in LyX are rotated by 90 degs).
+ // Other landscape environment is handled via the landscape module, thus
+ // we will fall through in that case.
+ if (name == "landscape") {
+ // We check if the next thing is a longtable
+ p.pushPosition();
+ bool found_end = false;
+ bool only_longtable = false;
+ bool end_longtable = false;
+ p.get_token();
+ p.get_token();
+ string envname = p.getArg('{', '}');
+ if (envname == "longtable" || envname == "xltabular") {
+ // Now we check if the longtable is the only content
+ // of the landscape environment
+ string const ltenv = envname;
+ while (!found_end && !end_longtable && p.good()) {
+ envname = p.next_token().cat() == catBegin
+ ? p.getArg('{', '}') : string();
+ Token const & t = p.get_token();
+ p.skip_spaces();
+ end_longtable = t.asInput() != "\\end"
+ && envname == ltenv;
+ found_end = t.asInput() == "\\end"
+ && envname == "landscape";
+ }
+ if (end_longtable) {
+ p.get_token();
+ envname = p.getArg('{', '}');
+ only_longtable = p.next_next_token().asInput() == "\\end"
+ && envname == "landscape";
+ }
+ if (only_longtable) {
+ p.popPosition();
+ p.skip_spaces();
+ int const save_tablerotation = parent_context.tablerotation;
+ parent_context.tablerotation = 90;
+ parse_text(p, os, FLAG_END, outer, parent_context);
+ parent_context.tablerotation = save_tablerotation;
+ p.skip_spaces();
+ break;
+ }
+ // fall through
+ }
+ // fall through
+ p.popPosition();
+ }
- else if (name == "listing") {
- minted_float = "float";
- eat_whitespace(p, os, parent_context, false);
- string const opt = p.hasOpt() ? p.getArg('[', ']') : string();
- if (!opt.empty())
- minted_float += "=" + opt;
- // If something precedes \begin{minted}, we output it at the end
- // as a caption, in order to keep it inside the listings inset.
- eat_whitespace(p, os, parent_context, true);
- p.pushPosition();
- Token const & t = p.get_token();
- p.skip_spaces(true);
- string const envname = p.next_token().cat() == catBegin
- ? p.getArg('{', '}') : string();
- bool prologue = t.asInput() != "\\begin" || envname != "minted";
- p.popPosition();
- minted_float_has_caption = false;
- string content = parse_text_snippet(p, FLAG_END, outer,
- parent_context);
- size_t i = content.find("\\begin_inset listings");
- bool minted_env = i != string::npos;
- string caption;
- if (prologue) {
- caption = content.substr(0, i);
- content.erase(0, i);
+ if (name == "framed" || name == "shaded") {
+ eat_whitespace(p, os, parent_context, false);
+ parse_outer_box(p, os, FLAG_END, outer, parent_context, name, "");
+ p.skip_spaces();
+ preamble.registerAutomaticallyLoadedPackage("framed");
+ break;
}
- parent_context.check_layout(os);
- if (minted_env && minted_float_has_caption) {
+
+ if (name == "listing") {
+ minted_float = "float";
+ eat_whitespace(p, os, parent_context, false);
+ string const opt = p.hasOpt() ? p.getArg('[', ']') : string();
+ if (!opt.empty())
+ minted_float += "=" + opt;
+ // If something precedes \begin{minted}, we output it at the end
+ // as a caption, in order to keep it inside the listings inset.
eat_whitespace(p, os, parent_context, true);
- os << content << "\n";
- if (!caption.empty())
+ p.pushPosition();
+ Token const & t = p.get_token();
+ p.skip_spaces(true);
+ string const envname = p.next_token().cat() == catBegin
+ ? p.getArg('{', '}') : string();
+ bool prologue = t.asInput() != "\\begin" || envname != "minted";
+ p.popPosition();
+ minted_float_has_caption = false;
+ string content = parse_text_snippet(p, FLAG_END, outer,
+ parent_context);
+ size_t i = content.find("\\begin_inset listings");
+ bool minted_env = i != string::npos;
+ string caption;
+ if (prologue) {
+ caption = content.substr(0, i);
+ content.erase(0, i);
+ }
+ parent_context.check_layout(os);
+ if (minted_env && minted_float_has_caption) {
+ eat_whitespace(p, os, parent_context, true);
+ os << content << "\n";
+ if (!caption.empty())
+ os << caption << "\n";
+ os << "\n\\end_layout\n"; // close inner layout
+ end_inset(os); // close caption inset
+ os << "\n\\end_layout\n"; // close outer layout
+ } else if (!caption.empty()) {
+ if (!minted_env) {
+ begin_inset(os, "listings\n");
+ os << "lstparams " << '"' << minted_float << '"' << '\n';
+ os << "inline false\n";
+ os << "status collapsed\n";
+ }
+ os << "\n\\begin_layout Plain Layout\n";
+ begin_inset(os, "Caption Standard\n");
+ Context newcontext(true, parent_context.textclass,
+ 0, 0, parent_context.font);
+ newcontext.check_layout(os);
os << caption << "\n";
- os << "\n\\end_layout\n"; // close inner layout
- end_inset(os); // close caption inset
- os << "\n\\end_layout\n"; // close outer layout
- } else if (!caption.empty()) {
- if (!minted_env) {
+ newcontext.check_end_layout(os);
+ end_inset(os);
+ os << "\n\\end_layout\n";
+ } else if (content.empty()) {
begin_inset(os, "listings\n");
os << "lstparams " << '"' << minted_float << '"' << '\n';
os << "inline false\n";
os << "status collapsed\n";
+ } else {
+ os << content << "\n";
}
- os << "\n\\begin_layout Plain Layout\n";
- begin_inset(os, "Caption Standard\n");
- Context newcontext(true, parent_context.textclass,
- 0, 0, parent_context.font);
- newcontext.check_layout(os);
- os << caption << "\n";
- newcontext.check_end_layout(os);
- end_inset(os);
- os << "\n\\end_layout\n";
- } else if (content.empty()) {
- begin_inset(os, "listings\n");
- os << "lstparams " << '"' << minted_float << '"' << '\n';
- os << "inline false\n";
- os << "status collapsed\n";
- } else {
- os << content << "\n";
+ end_inset(os); // close listings inset
+ parent_context.check_end_layout(os);
+ parent_context.new_paragraph(os);
+ p.skip_spaces();
+ minted_float.clear();
+ minted_float_has_caption = false;
+ break;
}
- end_inset(os); // close listings inset
- parent_context.check_end_layout(os);
- parent_context.new_paragraph(os);
- p.skip_spaces();
- minted_float.clear();
- minted_float_has_caption = false;
- }
- else if (name == "lstlisting" || name == "minted") {
- bool use_minted = name == "minted";
- // with listings, we do not eat newlines here since
- // \begin{lstlistings}
- // [foo]
- // and
- // // \begin{lstlistings}%
- //
- // [foo]
- // reads [foo] as content, whereas
- // // \begin{lstlistings}%
- // [foo]
- // or
- // \begin{lstlistings}[foo,
- // bar]
- // reads [foo...] as argument.
- eat_whitespace(p, os, parent_context, false, use_minted);
- if (use_minted && minted_float.empty()) {
- // look ahead for a bottom caption
- p.pushPosition();
- bool found_end_minted = false;
- while (!found_end_minted && p.good()) {
+ if (name == "lstlisting" || name == "minted") {
+ bool use_minted = name == "minted";
+ // with listings, we do not eat newlines here since
+ // \begin{lstlistings}
+ // [foo]
+ // and
+ // // \begin{lstlistings}%
+ //
+ // [foo]
+ // reads [foo] as content, whereas
+ // // \begin{lstlistings}%
+ // [foo]
+ // or
+ // \begin{lstlistings}[foo,
+ // bar]
+ // reads [foo...] as argument.
+ eat_whitespace(p, os, parent_context, false, use_minted);
+ if (use_minted && minted_float.empty()) {
+ // look ahead for a bottom caption
+ p.pushPosition();
+ bool found_end_minted = false;
+ while (!found_end_minted && p.good()) {
+ Token const & t = p.get_token();
+ p.skip_spaces();
+ string const envname =
+ p.next_token().cat() == catBegin
+ ? p.getArg('{', '}') : string();
+ found_end_minted = t.asInput() == "\\end"
+ && envname == "minted";
+ }
+ eat_whitespace(p, os, parent_context, true);
Token const & t = p.get_token();
- p.skip_spaces();
- string const envname =
- p.next_token().cat() == catBegin
- ? p.getArg('{', '}') : string();
- found_end_minted = t.asInput() == "\\end"
- && envname == "minted";
- }
- eat_whitespace(p, os, parent_context, true);
- Token const & t = p.get_token();
- p.skip_spaces(true);
- if (t.asInput() == "\\lyxmintcaption") {
- string const pos = p.getArg('[', ']');
- if (pos == "b") {
- string const caption =
- parse_text_snippet(p, FLAG_ITEM,
- false, parent_context);
- minted_nonfloat_caption = "[b]" + caption;
- eat_whitespace(p, os, parent_context, true);
+ p.skip_spaces(true);
+ if (t.asInput() == "\\lyxmintcaption") {
+ string const pos = p.getArg('[', ']');
+ if (pos == "b") {
+ string const caption =
+ parse_text_snippet(p, FLAG_ITEM,
+ false, parent_context);
+ minted_nonfloat_caption = "[b]" + caption;
+ eat_whitespace(p, os, parent_context, true);
+ }
}
+ p.popPosition();
}
- p.popPosition();
+ parse_listings(p, os, parent_context, false, use_minted);
+ p.skip_spaces();
+ break;
}
- parse_listings(p, os, parent_context, false, use_minted);
- p.skip_spaces();
- }
- else if (!parent_context.new_layout_allowed)
- parse_unknown_environment(p, name, os, FLAG_END, outer,
- parent_context);
-
- // Alignment and spacing settings
- // FIXME (bug xxxx): These settings can span multiple paragraphs and
- // therefore are totally broken!
- // Note that \centering, \raggedright, and \raggedleft cannot be handled, as
- // they are commands not environments. They are furthermore switches that
- // can be ended by another switches, but also by commands like \footnote or
- // \parbox. So the only safe way is to leave them untouched.
- // However, we support the pseudo-environments
- // \begin{centering} ... \end{centering}
- // \begin{raggedright} ... \end{raggedright}
- // \begin{raggedleft} ... \end{raggedleft}
- // since they are used by LyX in floats (for spacing reasons)
- else if (name == "center" || name == "centering" ||
- name == "flushleft" || name == "raggedright" ||
- name == "flushright" || name == "raggedleft" ||
- name == "singlespace" || name == "onehalfspace" ||
- name == "doublespace" || name == "spacing") {
- eat_whitespace(p, os, parent_context, false);
- // We must begin a new paragraph if not already done
- if (! parent_context.atParagraphStart()) {
- parent_context.check_end_layout(os);
- parent_context.new_paragraph(os);
+ if (!parent_context.new_layout_allowed) {
+ parse_unknown_environment(p, name, os, FLAG_END, outer,
+ parent_context);
+ break;
}
- if (name == "flushleft" || name == "raggedright")
- parent_context.add_extra_stuff("\\align left\n");
- else if (name == "flushright" || name == "raggedleft")
- parent_context.add_extra_stuff("\\align right\n");
- else if (name == "center" || name == "centering")
- 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") {
- parent_context.add_extra_stuff("\\paragraph_spacing onehalf\n");
- preamble.registerAutomaticallyLoadedPackage("setspace");
- } else if (name == "doublespace") {
- parent_context.add_extra_stuff("\\paragraph_spacing double\n");
- 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();
- // We must begin a new paragraph to reset the alignment
- parent_context.new_paragraph(os);
- p.skip_spaces();
- }
- // The single '=' is meant here.
- else if ((newlayout = findLayout(parent_context.textclass, name, false))) {
- eat_whitespace(p, os, parent_context, false);
- Context context(true, parent_context.textclass, newlayout,
- parent_context.layout, parent_context.font);
- if (parent_context.deeper_paragraph) {
- // We are beginning a nested environment after a
- // deeper paragraph inside the outer list environment.
- // Therefore we don't need to output a "begin deeper".
- context.need_end_deeper = true;
- }
- parent_context.check_end_layout(os);
- if (last_env == name) {
- // we need to output a separator since LyX would export
- // the two environments as one otherwise (bug 5716)
- TeX2LyXDocClass const & textclass(parent_context.textclass);
- Context newcontext(true, textclass,
- &(textclass.defaultLayout()));
- newcontext.check_layout(os);
- begin_inset(os, "Separator plain\n");
- end_inset(os);
- newcontext.check_end_layout(os);
- }
- switch (context.layout->latextype) {
- case LATEX_LIST_ENVIRONMENT:
- context.add_par_extra_stuff("\\labelwidthstring "
- + p.verbatim_item() + '\n');
+ // Alignment and spacing settings
+ // FIXME (bug xxxx): These settings can span multiple paragraphs and
+ // therefore are totally broken!
+ // Note that \centering, \raggedright, and \raggedleft cannot be handled, as
+ // they are commands not environments. They are furthermore switches that
+ // can be ended by another switches, but also by commands like \footnote or
+ // \parbox. So the only safe way is to leave them untouched.
+ // However, we support the pseudo-environments
+ // \begin{centering} ... \end{centering}
+ // \begin{raggedright} ... \end{raggedright}
+ // \begin{raggedleft} ... \end{raggedleft}
+ // since they are used by LyX in floats (for spacing reasons)
+ if (name == "center" || name == "centering"
+ || name == "flushleft" || name == "raggedright"
+ || name == "flushright" || name == "raggedleft"
+ || name == "singlespace" || name == "onehalfspace"
+ || name == "doublespace" || name == "spacing") {
+ eat_whitespace(p, os, parent_context, false);
+ // We must begin a new paragraph if not already done
+ if (! parent_context.atParagraphStart()) {
+ parent_context.check_end_layout(os);
+ parent_context.new_paragraph(os);
+ }
+ if (name == "flushleft" || name == "raggedright")
+ parent_context.add_extra_stuff("\\align left\n");
+ else if (name == "flushright" || name == "raggedleft")
+ parent_context.add_extra_stuff("\\align right\n");
+ else if (name == "center" || name == "centering")
+ 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") {
+ parent_context.add_extra_stuff("\\paragraph_spacing onehalf\n");
+ preamble.registerAutomaticallyLoadedPackage("setspace");
+ } else if (name == "doublespace") {
+ parent_context.add_extra_stuff("\\paragraph_spacing double\n");
+ 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();
+ // We must begin a new paragraph to reset the alignment
+ parent_context.new_paragraph(os);
p.skip_spaces();
break;
- case LATEX_BIB_ENVIRONMENT:
- p.verbatim_item(); // swallow next arg
+ }
+
+ // The single '=' is meant here.
+ if ((newlayout = findLayout(parent_context.textclass, name, false))) {
+ eat_whitespace(p, os, parent_context, false);
+ Context context(true, parent_context.textclass, newlayout,
+ parent_context.layout, parent_context.font);
+ if (parent_context.deeper_paragraph) {
+ // We are beginning a nested environment after a
+ // deeper paragraph inside the outer list environment.
+ // Therefore we don't need to output a "begin deeper".
+ context.need_end_deeper = true;
+ }
+ parent_context.check_end_layout(os);
+ if (last_env == name) {
+ // we need to output a separator since LyX would export
+ // the two environments as one otherwise (bug 5716)
+ TeX2LyXDocClass const & textclass(parent_context.textclass);
+ Context newcontext(true, textclass,
+ &(textclass.defaultLayout()));
+ newcontext.check_layout(os);
+ begin_inset(os, "Separator plain\n");
+ end_inset(os);
+ newcontext.check_end_layout(os);
+ }
+ switch (context.layout->latextype) {
+ case LATEX_LIST_ENVIRONMENT:
+ context.in_list_preamble =
+ !context.layout->listpreamble().empty()
+ && p.hasListPreamble(context.layout->itemcommand());
+ context.add_par_extra_stuff("\\labelwidthstring "
+ + p.verbatim_item() + '\n');
+ p.skip_spaces();
+ break;
+ case LATEX_BIB_ENVIRONMENT:
+ p.verbatim_item(); // swallow next arg
+ p.skip_spaces();
+ break;
+ default:
+ 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
+ if (context.layout->latextype == LATEX_ENVIRONMENT)
+ output_arguments(os, p, outer, false, string(), context,
+ context.layout->latexargs());
+ else if (context.layout->latextype == LATEX_ITEM_ENVIRONMENT) {
+ context.in_list_preamble =
+ !context.layout->listpreamble().empty()
+ && p.hasListPreamble(context.layout->itemcommand());
+ ostringstream oss;
+ output_arguments(oss, p, outer, false, string(), context,
+ context.layout->latexargs());
+ context.list_extra_stuff = oss.str();
+ }
+ if (context.in_list_preamble) {
+ // Collect the stuff between \begin and first \item
+ context.list_preamble =
+ parse_text_snippet(p, FLAG_END, outer, context);
+ context.in_list_preamble = false;
+ }
+ parse_text(p, os, FLAG_END, outer, context);
+ if (context.layout->latextype == LATEX_ENVIRONMENT)
+ output_arguments(os, p, outer, false, "post", context,
+ context.layout->postcommandargs());
+ context.check_end_layout(os);
+ if (parent_context.deeper_paragraph) {
+ // We must suppress the "end deeper" because we
+ // suppressed the "begin deeper" above.
+ context.need_end_deeper = false;
+ }
+ context.check_end_deeper(os);
+ parent_context.new_paragraph(os);
p.skip_spaces();
+ if (!preamble.titleLayoutFound())
+ preamble.titleLayoutFound(newlayout->intitle);
+ set<string> const & req = newlayout->required();
+ set<string>::const_iterator it = req.begin();
+ set<string>::const_iterator en = req.end();
+ for (; it != en; ++it)
+ preamble.registerAutomaticallyLoadedPackage(*it);
break;
- default:
+ }
+
+ // The single '=' is meant here.
+ if ((newinsetlayout = findInsetLayout(parent_context.textclass, name, false))) {
+ eat_whitespace(p, os, parent_context, false);
+ parent_context.check_layout(os);
+ begin_inset(os, "Flex ");
+ docstring flex_name = newinsetlayout->name();
+ // FIXME: what do we do if the prefix is not Flex: ?
+ if (prefixIs(flex_name, from_ascii("Flex:")))
+ flex_name.erase(0, 5);
+ os << to_utf8(flex_name) << '\n'
+ << "status collapsed\n";
+ if (newinsetlayout->isPassThru()) {
+ string const arg = p.verbatimEnvironment(name);
+ Context context(true, parent_context.textclass,
+ &parent_context.textclass.plainLayout(),
+ parent_context.layout);
+ output_ert(os, arg, parent_context);
+ } else
+ parse_text_in_inset(p, os, FLAG_END, false, parent_context, newinsetlayout);
+ end_inset(os);
break;
}
- context.check_deeper(os);
- if (newlayout->keepempty) {
- // We need to start a new paragraph
- // even if it is empty.
- context.new_paragraph(os);
+
+ if (name == "appendix") {
+ // This is no good latex style, but it works and is used in some documents...
+ eat_whitespace(p, os, parent_context, false);
+ parent_context.check_end_layout(os);
+ Context context(true, parent_context.textclass, parent_context.layout,
+ parent_context.layout, parent_context.font);
context.check_layout(os);
+ os << "\\start_of_appendix\n";
+ parse_text(p, os, FLAG_END, outer, context);
+ context.check_end_layout(os);
+ p.skip_spaces();
+ break;
}
- // handle known optional and required arguments
- if (context.layout->latextype == LATEX_ENVIRONMENT)
- 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, "post", context,
- context.layout->postcommandargs());
- context.check_end_layout(os);
- if (parent_context.deeper_paragraph) {
- // We must suppress the "end deeper" because we
- // suppressed the "begin deeper" above.
- context.need_end_deeper = false;
- }
- context.check_end_deeper(os);
- parent_context.new_paragraph(os);
- p.skip_spaces();
- if (!preamble.titleLayoutFound())
- preamble.titleLayoutFound(newlayout->intitle);
- set<string> const & req = newlayout->requires();
- set<string>::const_iterator it = req.begin();
- set<string>::const_iterator en = req.end();
- for (; it != en; ++it)
- preamble.registerAutomaticallyLoadedPackage(*it);
- }
-
- // The single '=' is meant here.
- else if ((newinsetlayout = findInsetLayout(parent_context.textclass, name, false))) {
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_layout(os);
- begin_inset(os, "Flex ");
- docstring flex_name = newinsetlayout->name();
- // FIXME: what do we do if the prefix is not Flex: ?
- if (prefixIs(flex_name, from_ascii("Flex:")))
- flex_name.erase(0, 5);
- os << to_utf8(flex_name) << '\n'
- << "status collapsed\n";
- if (newinsetlayout->isPassThru()) {
- string const arg = p.verbatimEnvironment(name);
- Context context(true, parent_context.textclass,
- &parent_context.textclass.plainLayout(),
- parent_context.layout);
- output_ert(os, arg, parent_context);
- } else
- parse_text_in_inset(p, os, FLAG_END, false, parent_context, newinsetlayout);
- end_inset(os);
- }
-
- else if (name == "appendix") {
- // This is no good latex style, but it works and is used in some documents...
- eat_whitespace(p, os, parent_context, false);
- parent_context.check_end_layout(os);
- Context context(true, parent_context.textclass, parent_context.layout,
- parent_context.layout, parent_context.font);
- context.check_layout(os);
- os << "\\start_of_appendix\n";
- parse_text(p, os, FLAG_END, outer, context);
- context.check_end_layout(os);
- p.skip_spaces();
- }
- else if (known_environments.find(name) != known_environments.end()) {
- vector<ArgumentType> arguments = known_environments[name];
- // The last "argument" denotes wether we may translate the
- // environment contents to LyX
- // The default required if no argument is given makes us
- // compatible with the reLyXre environment.
- ArgumentType contents = arguments.empty() ?
- required :
- arguments.back();
- if (!arguments.empty())
- arguments.pop_back();
- // See comment in parse_unknown_environment()
- bool const specialfont =
- (parent_context.font != parent_context.normalfont);
- bool const new_layout_allowed =
- parent_context.new_layout_allowed;
- if (specialfont)
- parent_context.new_layout_allowed = false;
- parse_arguments("\\begin{" + name + "}", arguments, p, os,
- outer, parent_context);
- if (contents == verbatim)
- output_ert_inset(os, p.ertEnvironment(name),
- parent_context);
- else
- parse_text_snippet(p, os, FLAG_END, outer,
+ if (known_environments.find(name) != known_environments.end()) {
+ vector<ArgumentType> arguments = known_environments[name];
+ // The last "argument" denotes whether we may translate the
+ // environment contents to LyX
+ // The default required if no argument is given makes us
+ // compatible with the reLyXre environment.
+ ArgumentType contents = arguments.empty() ?
+ required :
+ arguments.back();
+ if (!arguments.empty())
+ arguments.pop_back();
+ // See comment in parse_unknown_environment()
+ bool const specialfont =
+ (parent_context.font != parent_context.normalfont);
+ bool const new_layout_allowed =
+ parent_context.new_layout_allowed;
+ if (specialfont)
+ parent_context.new_layout_allowed = false;
+ parse_arguments("\\begin{" + name + "}", arguments, p, os,
+ outer, parent_context);
+ if (contents == verbatim)
+ output_ert_inset(os, p.ertEnvironment(name),
parent_context);
- output_ert_inset(os, "\\end{" + name + "}", parent_context);
- if (specialfont)
- parent_context.new_layout_allowed = new_layout_allowed;
- }
+ else
+ parse_text_snippet(p, os, FLAG_END, outer,
+ parent_context);
+ output_ert_inset(os, "\\end{" + name + "}", parent_context);
+ if (specialfont)
+ parent_context.new_layout_allowed = new_layout_allowed;
+ break;
+ }
- else
- parse_unknown_environment(p, name, os, FLAG_END, outer,
- parent_context);
+ parse_unknown_environment(p, name, os, FLAG_END, outer, parent_context);
+ break;
+ }// end of loop
last_env = name;
active_environments.pop_back();
}
-void copy_file(FileName const & src, string dstname)
+void copy_file(FileName const & src, string const & dstname)
{
if (!copyFiles())
return;
void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
- Context & context, string const rdelim)
+ Context & context, string const & rdelim)
{
Layout const * newlayout = 0;
InsetLayout const * newinsetlayout = 0;
debugToken(cerr, t, flags);
#endif
+ if (context.in_list_preamble
+ && p.next_token().cs() == context.layout->itemcommand()) {
+ // We are parsing a list preamble. End before first \item.
+ flags |= FLAG_LEAVE;
+ context.in_list_preamble = false;
+ }
+
if (flags & FLAG_ITEM) {
if (t.cat() == catSpace)
continue;
if (context.layout->labeltype != LABEL_MANUAL)
output_arguments(os, p, outer, false, "item", context,
context.layout->itemargs());
+ if (!context.list_preamble.empty()) {
+ // We have a list preamble. Output it here.
+ begin_inset(os, "Argument listpreamble:1");
+ os << "\nstatus collapsed\n\n"
+ << "\\begin_layout Plain Layout\n\n"
+ << rtrim(context.list_preamble)
+ << "\n\\end_layout";
+ end_inset(os);
+ context.list_preamble.clear();
+ }
if (!context.list_extra_stuff.empty()) {
os << context.list_extra_stuff;
context.list_extra_stuff.clear();
parse_text_snippet(p, os, FLAG_ITEM, outer, context);
if (!preamble.titleLayoutFound())
preamble.titleLayoutFound(newlayout->intitle);
- set<string> const & req = newlayout->requires();
+ set<string> const & req = newlayout->required();
set<string>::const_iterator it = req.begin();
set<string>::const_iterator en = req.end();
for (; it != en; ++it)
p.skip_spaces();
if (!preamble.titleLayoutFound())
preamble.titleLayoutFound(newlayout->intitle);
- set<string> const & req = newlayout->requires();
+ set<string> const & req = newlayout->required();
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() == "*") &&
p.skip_spaces();
if (!preamble.titleLayoutFound())
preamble.titleLayoutFound(newlayout->intitle);
- set<string> const & req = newlayout->requires();
+ set<string> const & req = newlayout->required();
for (set<string>::const_iterator it = req.begin(); it != req.end(); ++it)
preamble.registerAutomaticallyLoadedPackage(*it);
continue;
p.skip_spaces();
if (!preamble.titleLayoutFound())
preamble.titleLayoutFound(newlayout->intitle);
- set<string> const & req = newlayout->requires();
+ set<string> const & req = newlayout->required();
for (set<string>::const_iterator it = req.begin(); it != req.end(); ++it)
preamble.registerAutomaticallyLoadedPackage(*it);
continue;
if (opts.find("width") != opts.end())
os << "\twidth "
<< translate_len(opts["width"]) << '\n';
- if (opts.find("height") != opts.end())
+ if (opts.find("totalheight") != opts.end())
os << "\theight "
- << translate_len(opts["height"]) << '\n';
+ << translate_len(opts["totalheight"]) << '\n';
if (opts.find("scale") != opts.end()) {
istringstream iss(opts["scale"]);
double val;
vector<string>::const_iterator s =
find(keys.begin(), keys.end(), "width");
if (s == keys.end())
- s = find(keys.begin(), keys.end(), "height");
+ s = find(keys.begin(), keys.end(), "totalheight");
if (s == keys.end())
s = find(keys.begin(), keys.end(), "scale");
if (s != keys.end() && distance(s, a) > 0)
special << "trim,";
if (opts.find("viewport") != opts.end())
special << "viewport=" << opts["viewport"] << ',';
- if (opts.find("totalheight") != opts.end())
- special << "totalheight=" << opts["totalheight"] << ',';
+ if (opts.find("height") != opts.end())
+ special << "height=" << opts["height"] << ',';
if (opts.find("type") != opts.end())
special << "type=" << opts["type"] << ',';
if (opts.find("ext") != opts.end())
if (t.cs() == "listof") {
p.skip_spaces(true);
- string const name = p.get_token().cs();
+ string const name = p.verbatim_item();
if (context.textclass.floats().typeExist(name)) {
context.check_layout(os);
begin_inset(os, "FloatList ");
os << name << "\n";
end_inset(os);
- p.get_token(); // swallow second arg
+ p.verbatim_item(); // swallow second arg
} else
output_ert_inset(os, "\\listof{" + name + "}", context);
continue;
}
+ if (t.cs() == "theendnotes"
+ || (t.cs() == "printendnotes"
+ && p.next_token().asInput() != "*"
+ && !p.hasOpt())) {
+ context.check_layout(os);
+ begin_inset(os, "FloatList endnote\n");
+ end_inset(os);
+ skip_spaces_braces(p);
+ continue;
+ }
+
if ((where = is_known(t.cs(), known_text_font_families))) {
parse_text_attributes(p, os, FLAG_ITEM, outer,
context, "\\family", context.font.family,
continue;
}
- if (t.cs() == "lyxadded" || t.cs() == "lyxdeleted") {
+ if (t.cs() == "lyxadded" || t.cs() == "lyxdeleted" || t.cs() == "lyxobjdeleted"
+ || t.cs() == "lyxdisplayobjdeleted" || t.cs() == "lyxudisplayobjdeleted") {
context.check_layout(os);
+ string initials;
+ if (p.hasOpt()) {
+ initials = p.getArg('[', ']');
+ }
string name = p.getArg('{', '}');
string localtime = p.getArg('{', '}');
- preamble.registerAuthor(name);
+ preamble.registerAuthor(name, initials);
Author const & author = preamble.getAuthor(name);
// from_asctime_utc() will fail if LyX decides to output the
// time in the text language.
os << "\n\\change_deleted ";
os << author.bufferId() << ' ' << ptime << '\n';
parse_text_snippet(p, os, FLAG_ITEM, outer, context);
- bool dvipost = LaTeXPackages::isAvailable("dvipost");
bool xcolorulem = LaTeXPackages::isAvailable("ulem") &&
LaTeXPackages::isAvailable("xcolor");
// No need to test for luatex, since luatex comes in
preamble.registerAutomaticallyLoadedPackage("pdfcolmk");
}
} else {
- if (dvipost) {
- preamble.registerAutomaticallyLoadedPackage("dvipost");
- } else if (xcolorulem) {
+ if (xcolorulem) {
preamble.registerAutomaticallyLoadedPackage("ulem");
preamble.registerAutomaticallyLoadedPackage("xcolor");
}
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");
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;
}
}
string keys, pretextlist, posttextlist;
if (qualified) {
- map<string, string> pres, posts, preslit, postslit;
+ vector<pair<string, string>> pres, posts, preslit, postslit;
vector<string> lkeys;
// text before the citation
string lbefore, lbeforelit;
// text after the citation
string lafter, lafterlit;
- string lkey;
+ string lkey;
pair<bool, string> laft, lbef;
while (true) {
get_cite_arguments(p, true, lbefore, lafter);
laft = convert_latexed_command_inset_arg(lafter);
literal |= !laft.first;
lafter = laft.second;
- lafterlit = subst(lbefore, "\n", " ");
+ lafterlit = subst(lafter, "\n", " ");
}
if (!lbefore.empty()) {
lbefore.erase(0, 1);
lkey = p.getArg('{', '}');
if (lkey.empty())
break;
- if (!lbefore.empty()) {
- pres.insert(make_pair(lkey, lbefore));
- preslit.insert(make_pair(lkey, lbeforelit));
- }
- if (!lafter.empty()) {
- posts.insert(make_pair(lkey, lafter));
- postslit.insert(make_pair(lkey, lafterlit));
- }
+ pres.push_back(make_pair(lkey, lbefore));
+ preslit.push_back(make_pair(lkey, lbeforelit));
+ posts.push_back(make_pair(lkey, lafter));
+ postslit.push_back(make_pair(lkey, lafterlit));
lkeys.push_back(lkey);
}
keys = convert_literate_command_inset_arg(getStringFromVector(lkeys));
for (auto const & ptl : pres) {
if (!pretextlist.empty())
pretextlist += '\t';
- pretextlist += ptl.first + " " + ptl.second;
+ pretextlist += ptl.first;
+ if (!ptl.second.empty())
+ pretextlist += " " + ptl.second;
}
for (auto const & potl : posts) {
if (!posttextlist.empty())
posttextlist += '\t';
- posttextlist += potl.first + " " + potl.second;
+ posttextlist += potl.first;
+ if (!potl.second.empty())
+ posttextlist += " " + potl.second;
}
} else
keys = convert_literate_command_inset_arg(p.verbatim_item());
} else
os << "encoding " << '"' << enc->name() << '"' << "\n";
}
+ string bibfileencs;
+ for (auto const & bf : preamble.biblatex_encodings) {
+ if (!bibfileencs.empty())
+ bibfileencs += "\t";
+ bibfileencs += bf;
+ }
+ if (!bibfileencs.empty())
+ os << "file_encodings " << '"' << bibfileencs << '"' << "\n";
end_inset(os);
need_commentbib = false;
continue;
if (t.cs() == "newpage" ||
(t.cs() == "pagebreak" && !p.hasOpt()) ||
t.cs() == "clearpage" ||
- t.cs() == "cleardoublepage") {
+ t.cs() == "cleardoublepage" ||
+ t.cs() == "nopagebreak") {
context.check_layout(os);
begin_inset(os, "Newpage ");
os << t.cs();
} else if (unit == "\\bigskipamount") {
unit = "bigskip";
known_vspace = true;
+ } else if (length == "\\baselineskip") {
+ unit = "fullline";
+ known_vspace = true;
} else if (unit == "\\fill") {
unit = "vfill";
known_vspace = true;
}
}
}
+ if (value == 0.5 && t.cs()[0] != 'h' && unit == "\\baselineskip") {
+ unit = "halfline";
+ known_vspace = true;
+ }
if (!known_hspace && !known_vspace) {
switch (unitFromString(unit)) {
case Length::SP:
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 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);
+ }
+ }
}
}
}
}
if (!bibfiles.empty())
os << "bibfiles " << '"' << bibfiles << '"' << "\n";
+ string bibfileencs;
+ for (auto const & bf : preamble.biblatex_encodings) {
+ if (!bibfileencs.empty())
+ bibfileencs += "\t";
+ bibfileencs += bf;
+ }
+ if (!bibfileencs.empty())
+ os << "file_encodings " << '"' << bibfileencs << '"' << "\n";
end_inset(os);// Bibtex
os << "\\end_layout\n";
end_inset(os);// Note