namespace {
-void output_arguments(ostream &, Parser &, bool, bool, bool, Context &,
+void output_arguments(ostream &, Parser &, bool, bool, string, Context &,
Layout::LaTeXArgMap const &);
}
void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
- Context const & context, InsetLayout const * layout)
+ Context const & context, InsetLayout const * layout,
+ string const rdelim)
{
bool const forcePlainLayout =
layout ? layout->forcePlainLayout() : false;
else
newcontext.font = context.font;
if (layout)
- output_arguments(os, p, outer, false, false, newcontext,
+ output_arguments(os, p, outer, false, string(), newcontext,
layout->latexargs());
- parse_text(p, os, flags, outer, newcontext);
+ // If we have a latex param, we eat it here.
+ if (!context.latexparam.empty()) {
+ ostringstream oss;
+ Context dummy(true, context.textclass);
+ parse_text(p, oss, FLAG_RDELIM, outer, dummy,
+ string(1, context.latexparam.back()));
+ }
+ parse_text(p, os, flags, outer, newcontext, rdelim);
if (layout)
- output_arguments(os, p, outer, false, true, newcontext,
+ output_arguments(os, p, outer, false, "post", newcontext,
layout->postcommandargs());
newcontext.check_end_layout(os);
}
namespace {
void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
- Context const & context, string const & name)
+ Context const & context, string const & name,
+ string const rdelim = string())
{
InsetLayout const * layout = 0;
DocumentClass::InsetLayouts::const_iterator it =
context.textclass.insetLayouts().find(from_ascii(name));
if (it != context.textclass.insetLayouts().end())
layout = &(it->second);
- parse_text_in_inset(p, os, flags, outer, context, layout);
+ parse_text_in_inset(p, os, flags, outer, context, layout, rdelim);
}
/// parses a paragraph snippet, useful for example for \\emph{...}
char const * const known_quotes[] = { "dq", "guillemotleft", "flqq", "og",
"guillemotright", "frqq", "fg", "glq", "glqq", "textquoteleft", "grq", "grqq",
"quotedblbase", "textquotedblleft", "quotesinglbase", "textquoteright", "flq",
-"guilsinglleft", "frq", "guilsinglright", 0};
+"guilsinglleft", "frq", "guilsinglright", "textquotedblright", "textquotesingle",
+"textquotedbl", 0};
/// the same as known_quotes with .lyx names
-char const * const known_coded_quotes[] = { "prd", "ard", "ard", "ard",
-"ald", "ald", "ald", "gls", "gld", "els", "els", "grd",
-"gld", "grd", "gls", "ers", "fls",
-"fls", "frs", "frs", 0};
+char const * const known_coded_quotes[] = { "qrd", "ard", "ard", "ard",
+"ald", "ald", "ald", "gls", "gld", "els", "els", "eld",
+"gld", "eld", "gls", "ers", "ars",
+"ars", "als", "als", "erd", "qrs", "qrd", 0};
/// LaTeX names for font sizes
char const * const known_sizes[] = { "tiny", "scriptsize", "footnotesize",
// The caption for non-floating minted listings
string minted_nonfloat_caption = "";
+// Characters that have to be escaped by \\ in LaTeX
+char const * const known_escaped_chars[] = {
+ "&", "_", "$", "%", "#", "^", "{", "}", 0};
+
/// splits "x=z, y=b" into a map and an ordered keyword vector
void split_map(string const & s, map<string, string> & res, vector<string> & keys)
return true;
}
+
+/// If we have ambiguous quotation marks, make a smart guess
+/// based on main quote style
+string guessQuoteStyle(string in, bool const opening)
+{
+ string res = in;
+ if (prefixIs(in, "qr")) {// straight quote
+ if (!opening)
+ res = subst(res, "r", "l");
+ } else if (in == "eld") {// ``
+ if (preamble.quotesStyle() == "german")
+ res = "grd";
+ else if (preamble.quotesStyle() == "british")
+ res = "bls";
+ else if (preamble.quotesStyle() == "french")
+ res = "fls";
+ else if (preamble.quotesStyle() == "russian")
+ res = "rrs";
+ } else if (in == "erd") {// ''
+ if (preamble.quotesStyle() == "polish")
+ res = "prd";
+ else if (preamble.quotesStyle() == "british")
+ res = "brs";
+ else if (preamble.quotesStyle() == "french")
+ res = "frs";
+ else if (preamble.quotesStyle() == "swedish")
+ res = opening ? "sld" : "srd";
+ } else if (in == "els") {// `
+ if (preamble.quotesStyle() == "german")
+ res = "grs";
+ else if (preamble.quotesStyle() == "british")
+ res = "bld";
+ } else if (in == "ers") {// '
+ if (preamble.quotesStyle() == "polish")
+ res = "prs";
+ else if (preamble.quotesStyle() == "british")
+ res = "brd";
+ else if (preamble.quotesStyle() == "swedish")
+ res = opening ? "sls" : "srs";
+ } else if (in == "ard") {// >>
+ if (preamble.quotesStyle() == "swiss")
+ res = "cld";
+ else if (preamble.quotesStyle() == "french")
+ res = "fld";
+ else if (preamble.quotesStyle() == "russian")
+ res = "rld";
+ } else if (in == "ald") {// <<
+ if (preamble.quotesStyle() == "swiss")
+ res = "crd";
+ else if (preamble.quotesStyle() == "french")
+ res = "frd";
+ else if (preamble.quotesStyle() == "russian")
+ res = "rrd";
+ } else if (in == "ars") {// >
+ if (preamble.quotesStyle() == "swiss")
+ res = "cls";
+ } else if (in == "als") {// <
+ if (preamble.quotesStyle() == "swiss")
+ res = "crs";
+ } else if (in == "gld") {// ,,
+ if (preamble.quotesStyle() == "polish")
+ res = "pld";
+ else if (preamble.quotesStyle() == "russian")
+ res = "rls";
+ } else if (in == "gls") {// ,
+ if (preamble.quotesStyle() == "polish")
+ res = "pls";
+ }
+ return res;
+}
+
+
} // namespace
}
-/*!
- * Find a file with basename \p name in path \p path and an extension
- * in \p extensions.
- */
-string find_file(string const & name, string const & path,
- char const * const * extensions)
-{
- for (char const * const * what = extensions; *what; ++what) {
- string const trial = addExtension(name, *what);
- if (makeAbsPath(trial, path).exists())
- return trial;
- }
- return string();
-}
-
-
void begin_inset(ostream & os, string const & name)
{
os << "\n\\begin_inset " << name;
pair<bool, docstring> convert_unicodesymbols(docstring s)
{
bool res = true;
- int const nchars_escape = 8;
- static char_type const chars_escape[nchars_escape] = {
- '&', '_', '$', '%', '#', '^', '{', '}'};
odocstringstream os;
for (size_t i = 0; i < s.size();) {
if (s[i] != '\\') {
i = 0;
else {
res = false;
- for (int k = 0; k < nchars_escape; k++)
- if (prefixIs(s, from_ascii("\\") + chars_escape[k]))
+ for (auto const & c : known_escaped_chars)
+ if (c != 0 && prefixIs(s, from_ascii("\\") + c))
res = true;
i = 1;
}
}
-Layout const * findLayout(TextClass const & textclass, string const & name, bool command)
+Layout const * findLayout(TextClass const & textclass, string const & name, bool command,
+ string const & latexparam = string())
{
- Layout const * layout = findLayoutWithoutModule(textclass, name, command);
+ Layout const * layout = findLayoutWithoutModule(textclass, name, command, latexparam);
if (layout)
return layout;
if (checkModule(name, command))
- return findLayoutWithoutModule(textclass, name, command);
+ return findLayoutWithoutModule(textclass, name, command, latexparam);
return layout;
}
-InsetLayout const * findInsetLayout(TextClass const & textclass, string const & name, bool command)
+InsetLayout const * findInsetLayout(TextClass const & textclass, string const & name, bool command,
+ string const & latexparam = string())
{
- InsetLayout const * insetlayout = findInsetLayoutWithoutModule(textclass, name, command);
+ InsetLayout const * insetlayout =
+ findInsetLayoutWithoutModule(textclass, name, command, latexparam);
if (insetlayout)
return insetlayout;
if (checkModule(name, command))
- return findInsetLayoutWithoutModule(textclass, name, command);
+ return findInsetLayoutWithoutModule(textclass, name, command, latexparam);
return insetlayout;
}
}
-void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bool post,
+void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, string const prefix,
Context & context, Layout::LaTeXArgMap const & latexargs)
{
- if (need_layout) {
- context.check_layout(os);
- need_layout = false;
- } else
- need_layout = true;
+ if (context.layout->latextype != LATEX_ITEM_ENVIRONMENT || !prefix.empty()) {
+ if (need_layout) {
+ context.check_layout(os);
+ need_layout = false;
+ } else
+ need_layout = true;
+ }
int i = 0;
Layout::LaTeXArgMap::const_iterator lait = latexargs.begin();
Layout::LaTeXArgMap::const_iterator const laend = latexargs.end();
if (lait->second.mandatory) {
if (p.next_token().cat() != catBegin)
break;
- p.get_token(); // eat '{'
+ string ldelim = to_utf8(lait->second.ldelim);
+ string rdelim = to_utf8(lait->second.rdelim);
+ if (ldelim.empty())
+ ldelim = "{";
+ if (rdelim.empty())
+ rdelim = "}";
+ p.get_token(); // eat ldelim
+ if (ldelim.size() > 1)
+ p.get_token(); // eat ldelim
if (need_layout) {
context.check_layout(os);
need_layout = false;
}
begin_inset(os, "Argument ");
- if (post)
- os << "post:";
+ if (!prefix.empty())
+ os << prefix << ':';
os << i << "\nstatus collapsed\n\n";
- parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context);
+ parse_text_in_inset(p, os, FLAG_RDELIM, outer, context, 0, rdelim);
end_inset(os);
} else {
- if (p.next_token().cat() == catEscape ||
- p.next_token().character() != '[')
+ string ldelim = to_utf8(lait->second.ldelim);
+ string rdelim = to_utf8(lait->second.rdelim);
+ if (ldelim.empty())
+ ldelim = "[";
+ if (rdelim.empty())
+ rdelim = "]";
+ string tok = p.next_token().asInput();
+ // we only support delimiters with max 2 chars for now.
+ if (ldelim.size() > 1)
+ tok += p.next_next_token().asInput();
+ if (p.next_token().cat() == catEscape || tok != ldelim)
continue;
- p.get_token(); // eat '['
+ p.get_token(); // eat ldelim
+ if (ldelim.size() > 1)
+ p.get_token(); // eat ldelim
if (need_layout) {
context.check_layout(os);
need_layout = false;
}
begin_inset(os, "Argument ");
- if (post)
- os << "post:";
+ if (!prefix.empty())
+ os << prefix << ':';
os << i << "\nstatus collapsed\n\n";
- parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context);
+ parse_text_in_inset(p, os, FLAG_RDELIM, outer, context, 0, rdelim);
end_inset(os);
}
eat_whitespace(p, os, context, false);
context.need_end_deeper = true;
}
context.check_deeper(os);
- output_arguments(os, p, outer, true, false, context,
+ output_arguments(os, p, outer, true, string(), context,
context.layout->latexargs());
+ // If we have a latex param, we eat it here.
+ if (!parent_context.latexparam.empty()) {
+ ostringstream oss;
+ Context dummy(true, parent_context.textclass);
+ parse_text(p, oss, FLAG_RDELIM, outer, dummy,
+ string(1, parent_context.latexparam.back()));
+ }
parse_text(p, os, FLAG_ITEM, outer, context);
- output_arguments(os, p, outer, false, true, context,
+ output_arguments(os, p, outer, false, "post", context,
context.layout->postcommandargs());
context.check_end_layout(os);
if (parent_context.deeper_paragraph) {
os << "inline true\n";
else
os << "inline false\n";
- os << "status collapsed\n";
+ os << "status open\n";
Context context(true, parent_context.textclass);
context.layout = &parent_context.textclass.plainLayout();
if (use_minted && prefixIs(minted_nonfloat_caption, "[t]")) {
// things like comments are completely wrong.
string const s = p.plainEnvironment("CJK");
for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
- if (*it == '\\')
- output_ert_inset(os, "\\", parent_context);
- else if (*it == '$')
- output_ert_inset(os, "$", parent_context);
+ string snip;
+ snip += *it;
+ if (snip == "\\" || is_known(snip, known_escaped_chars))
+ output_ert_inset(os, snip, parent_context);
else if (*it == '\n' && it + 1 != et && s.begin() + 1 != it)
os << "\n ";
else
parse_text_snippet(p, FLAG_ITEM,
false, parent_context);
minted_nonfloat_caption = "[b]" + caption;
+ eat_whitespace(p, os, parent_context, true);
}
}
p.popPosition();
break;
}
context.check_deeper(os);
+ if (newlayout->keepempty) {
+ // We need to start a new paragraph
+ // even if it is empty.
+ context.new_paragraph(os);
+ context.check_layout(os);
+ }
// handle known optional and required arguments
- // Unfortunately LyX can't handle arguments of list arguments (bug 7468):
- // It is impossible to place anything after the environment name,
- // but before the first \\item.
if (context.layout->latextype == LATEX_ENVIRONMENT)
- output_arguments(os, p, outer, false, false, context,
+ output_arguments(os, p, outer, false, string(), context,
+ context.layout->latexargs());
+ else if (context.layout->latextype == LATEX_ITEM_ENVIRONMENT) {
+ ostringstream oss;
+ output_arguments(oss, p, outer, false, string(), context,
context.layout->latexargs());
+ context.list_extra_stuff = oss.str();
+ }
parse_text(p, os, FLAG_END, outer, context);
if (context.layout->latextype == LATEX_ENVIRONMENT)
- output_arguments(os, p, outer, false, true, context,
+ output_arguments(os, p, outer, false, "post", context,
context.layout->postcommandargs());
context.check_end_layout(os);
if (parent_context.deeper_paragraph) {
}
-/// Convert filenames with TeX macros and/or quotes to something LyX
-/// can understand
-string const normalize_filename(string const & name)
-{
- Parser p(name);
- ostringstream os;
- while (p.good()) {
- Token const & t = p.get_token();
- if (t.cat() != catEscape)
- os << t.asInput();
- else if (t.cs() == "lyxdot") {
- // This is used by LyX for simple dots in relative
- // names
- os << '.';
- p.skip_spaces();
- } else if (t.cs() == "space") {
- os << ' ';
- p.skip_spaces();
- } else if (t.cs() == "string") {
- // Convert \string" to " and \string~ to ~
- Token const & n = p.next_token();
- if (n.asInput() != "\"" && n.asInput() != "~")
- os << t.asInput();
- } else
- os << t.asInput();
- }
- // Strip quotes. This is a bit complicated (see latex_path()).
- string full = os.str();
- if (!full.empty() && full[0] == '"') {
- string base = removeExtension(full);
- string ext = getExtension(full);
- if (!base.empty() && base[base.length()-1] == '"')
- // "a b"
- // "a b".tex
- return addExtension(trim(base, "\""), ext);
- if (full[full.length()-1] == '"')
- // "a b.c"
- // "a b.c".tex
- return trim(full, "\"");
- }
- return full;
-}
-
-
-/// Convert \p name from TeX convention (relative to master file) to LyX
-/// convention (relative to .lyx file) if it is relative
-void fix_child_filename(string & name)
-{
- string const absMasterTeX = getMasterFilePath(true);
- bool const isabs = FileName::isAbsolute(name);
- // convert from "relative to .tex master" to absolute original path
- if (!isabs)
- name = makeAbsPath(name, absMasterTeX).absFileName();
- bool copyfile = copyFiles();
- string const absParentLyX = getParentFilePath(false);
- string abs = name;
- if (copyfile) {
- // convert from absolute original path to "relative to master file"
- string const rel = to_utf8(makeRelPath(from_utf8(name),
- from_utf8(absMasterTeX)));
- // re-interpret "relative to .tex file" as "relative to .lyx file"
- // (is different if the master .lyx file resides in a
- // different path than the master .tex file)
- string const absMasterLyX = getMasterFilePath(false);
- abs = makeAbsPath(rel, absMasterLyX).absFileName();
- // Do not copy if the new path is impossible to create. Example:
- // absMasterTeX = "/foo/bar/"
- // absMasterLyX = "/bar/"
- // name = "/baz.eps" => new absolute name would be "/../baz.eps"
- if (contains(name, "/../"))
- copyfile = false;
- }
- if (copyfile) {
- if (isabs)
- name = abs;
- else {
- // convert from absolute original path to
- // "relative to .lyx file"
- name = to_utf8(makeRelPath(from_utf8(abs),
- from_utf8(absParentLyX)));
- }
- }
- else if (!isabs) {
- // convert from absolute original path to "relative to .lyx file"
- name = to_utf8(makeRelPath(from_utf8(name),
- from_utf8(absParentLyX)));
- }
-}
-
-
void copy_file(FileName const & src, string dstname)
{
if (!copyFiles())
} // anonymous namespace
+/*!
+ * Find a file with basename \p name in path \p path and an extension
+ * in \p extensions.
+ */
+string find_file(string const & name, string const & path,
+ char const * const * extensions)
+{
+ for (char const * const * what = extensions; *what; ++what) {
+ string const trial = addExtension(name, *what);
+ if (makeAbsPath(trial, path).exists())
+ return trial;
+ }
+ return string();
+}
+
+
+/// Convert filenames with TeX macros and/or quotes to something LyX
+/// can understand
+string const normalize_filename(string const & name)
+{
+ Parser p(name);
+ ostringstream os;
+ while (p.good()) {
+ Token const & t = p.get_token();
+ if (t.cat() != catEscape)
+ os << t.asInput();
+ else if (t.cs() == "lyxdot") {
+ // This is used by LyX for simple dots in relative
+ // names
+ os << '.';
+ p.skip_spaces();
+ } else if (t.cs() == "space") {
+ os << ' ';
+ p.skip_spaces();
+ } else if (t.cs() == "string") {
+ // Convert \string" to " and \string~ to ~
+ Token const & n = p.next_token();
+ if (n.asInput() != "\"" && n.asInput() != "~")
+ os << t.asInput();
+ } else
+ os << t.asInput();
+ }
+ // Strip quotes. This is a bit complicated (see latex_path()).
+ string full = os.str();
+ if (!full.empty() && full[0] == '"') {
+ string base = removeExtension(full);
+ string ext = getExtension(full);
+ if (!base.empty() && base[base.length()-1] == '"')
+ // "a b"
+ // "a b".tex
+ return addExtension(trim(base, "\""), ext);
+ if (full[full.length()-1] == '"')
+ // "a b.c"
+ // "a b.c".tex
+ return trim(full, "\"");
+ }
+ return full;
+}
+
+
+/// Convert \p name from TeX convention (relative to master file) to LyX
+/// convention (relative to .lyx file) if it is relative
+void fix_child_filename(string & name)
+{
+ string const absMasterTeX = getMasterFilePath(true);
+ bool const isabs = FileName::isAbsolute(name);
+ // convert from "relative to .tex master" to absolute original path
+ if (!isabs)
+ name = makeAbsPath(name, absMasterTeX).absFileName();
+ bool copyfile = copyFiles();
+ string const absParentLyX = getParentFilePath(false);
+ string abs = name;
+ if (copyfile) {
+ // convert from absolute original path to "relative to master file"
+ string const rel = to_utf8(makeRelPath(from_utf8(name),
+ from_utf8(absMasterTeX)));
+ // re-interpret "relative to .tex file" as "relative to .lyx file"
+ // (is different if the master .lyx file resides in a
+ // different path than the master .tex file)
+ string const absMasterLyX = getMasterFilePath(false);
+ abs = makeAbsPath(rel, absMasterLyX).absFileName();
+ // Do not copy if the new path is impossible to create. Example:
+ // absMasterTeX = "/foo/bar/"
+ // absMasterLyX = "/bar/"
+ // name = "/baz.eps" => new absolute name would be "/../baz.eps"
+ if (contains(name, "/../"))
+ copyfile = false;
+ }
+ if (copyfile) {
+ if (isabs)
+ name = abs;
+ else {
+ // convert from absolute original path to
+ // "relative to .lyx file"
+ name = to_utf8(makeRelPath(from_utf8(abs),
+ from_utf8(absParentLyX)));
+ }
+ }
+ else if (!isabs) {
+ // convert from absolute original path to "relative to .lyx file"
+ name = to_utf8(makeRelPath(from_utf8(name),
+ from_utf8(absParentLyX)));
+ }
+}
+
+
void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
- Context & context)
+ Context & context, string const rdelim)
{
Layout const * newlayout = 0;
InsetLayout const * newinsetlayout = 0;
return;
if (t.cat() == catEnd && (flags & FLAG_BRACE_LAST))
return;
+ string tok = t.asInput();
+ // we only support delimiters with max 2 chars for now.
+ if (rdelim.size() > 1)
+ tok += p.next_token().asInput();
+ if (t.cat() != catEscape && !rdelim.empty()
+ && tok == rdelim && (flags & FLAG_RDELIM)) {
+ if (rdelim.size() > 1)
+ p.get_token(); // eat rdelim
+ return;
+ }
// If there is anything between \end{env} and \begin{env} we
// don't need to output a separator.
continue;
}
- // Basic support for english quotes. This should be
- // extended to other quotes, but is not so easy (a
- // left english quote is the same as a right german
- // quote...)
+ // Basic support for quotes. We try to disambiguate
+ // quotes from the context (e.g., a left english quote is
+ // the same as a right german quote...).
+ // Try to make a smart guess about the side
+ Token const prev = p.prev_token();
+ bool const opening = (prev.cat() != catSpace && prev.character() != 0
+ && prev.character() != '\n' && prev.character() != '~');
if (t.asInput() == "`" && p.next_token().asInput() == "`") {
context.check_layout(os);
begin_inset(os, "Quotes ");
- os << "eld";
+ os << guessQuoteStyle("eld", opening);
end_inset(os);
p.get_token();
skip_braces(p);
if (t.asInput() == "'" && p.next_token().asInput() == "'") {
context.check_layout(os);
begin_inset(os, "Quotes ");
- os << "erd";
+ os << guessQuoteStyle("erd", opening);
end_inset(os);
p.get_token();
skip_braces(p);
if (t.asInput() == ">" && p.next_token().asInput() == ">") {
context.check_layout(os);
begin_inset(os, "Quotes ");
- os << "ald";
+ os << guessQuoteStyle("ald", opening);
end_inset(os);
p.get_token();
skip_braces(p);
if (!has_chunk) {
context.check_layout(os);
begin_inset(os, "Quotes ");
- //FIXME: this is a right danish quote;
- // why not a left french quote?
- os << "ard";
+ os << guessQuoteStyle("ard", opening);
end_inset(os);
p.get_token();
skip_braces(p);
is_known(next.cs(), known_quotes) &&
end.cat() == catEnd) {
// Something like {\textquoteright} (e.g.
- // from writer2latex). LyX writes
- // \textquoteright{}, so we may skip the
+ // from writer2latex). We may skip the
// braces here for better readability.
parse_text_snippet(p, os, FLAG_BRACE_LAST,
outer, context);
continue;
}
- if (t.cs() == "item") {
+ // "item" by default, but could be something else
+ if (t.cs() == context.layout->itemcommand()) {
string s;
- bool const optarg = p.hasOpt();
- if (optarg) {
+ if (context.layout->labeltype == LABEL_MANUAL) {
// FIXME: This swallows comments, but we cannot use
// eat_whitespace() since we must not output
// anything before the item.
// An item in an unknown list-like environment
// FIXME: Do this in check_layout()!
context.has_item = false;
- if (optarg)
- output_ert_inset(os, "\\item", context);
- else
- output_ert_inset(os, "\\item ", context);
+ string item = "\\" + context.layout->itemcommand();
+ if (!p.hasOpt())
+ item += " ";
+ output_ert_inset(os, item, context);
}
- if (optarg) {
- if (context.layout->labeltype != LABEL_MANUAL) {
- // handle option of itemize item
- begin_inset(os, "Argument item:1\n");
- os << "status open\n";
- os << "\n\\begin_layout Plain Layout\n";
- Parser p2(s + ']');
- os << parse_text_snippet(p2,
- FLAG_BRACK_LAST, outer, context);
- // we must not use context.check_end_layout(os)
- // because that would close the outer itemize layout
- os << "\n\\end_layout\n";
- end_inset(os);
- eat_whitespace(p, os, context, false);
- } else if (!s.empty()) {
+ if (context.layout->labeltype != LABEL_MANUAL)
+ output_arguments(os, p, outer, false, "item", context,
+ context.layout->itemargs());
+ if (!context.list_extra_stuff.empty()) {
+ os << context.list_extra_stuff;
+ context.list_extra_stuff.clear();
+ }
+ else if (!s.empty()) {
// LyX adds braces around the argument,
// so we need to remove them here.
if (s.size() > 2 && s[0] == '{' &&
os << ' ';
eat_whitespace(p, os, context, false);
}
- }
continue;
}
continue;
}
+ // Before we look for the layout name with star and alone below, we check the layouts including
+ // the LateXParam, which might be one or several options or a star.
+ // The single '=' is meant here.
+ if (context.new_layout_allowed &&
+ (newlayout = findLayout(context.textclass, t.cs(), true, p.getCommandLatexParam()))) {
+ // store the latexparam here. This is eaten in output_command_layout
+ context.latexparam = newlayout->latexparam();
+ // write the layout
+ output_command_layout(os, p, outer, context, newlayout);
+ context.latexparam.clear();
+ p.skip_spaces();
+ if (!preamble.titleLayoutFound())
+ preamble.titleLayoutFound(newlayout->intitle);
+ set<string> const & req = newlayout->requires();
+ for (set<string>::const_iterator it = req.begin(); it != req.end(); ++it)
+ preamble.registerAutomaticallyLoadedPackage(*it);
+ continue;
+ }
+
+
// Starred section headings
// Must attempt to parse "Section*" before "Section".
if ((p.next_token().asInput() == "*") &&
continue;
}
- else if (t.cs() == "makeindex" || t.cs() == "maketitle") {
+ else if (t.cs() == "makeindex" || t.cs() == "maketitle" || t.cs() == "makebeamertitle") {
if (preamble.titleLayoutFound()) {
// swallow this
skip_spaces_braces(p);
continue;
}
- if ((where = is_known(t.cs(), known_text_font_series))) {
+ // beamer has a \textbf<overlay>{} inset
+ if (!p.hasOpt("<") && (where = is_known(t.cs(), known_text_font_series))) {
parse_text_attributes(p, os, FLAG_ITEM, outer,
context, "\\series", context.font.series,
known_coded_font_series[where - known_text_font_series]);
continue;
}
- if ((where = is_known(t.cs(), known_text_font_shapes))) {
+ // beamer has a \textit<overlay>{} inset
+ if (!p.hasOpt("<") && (where = is_known(t.cs(), known_text_font_shapes))) {
parse_text_attributes(p, os, FLAG_ITEM, outer,
context, "\\shape", context.font.shape,
known_coded_font_shapes[where - known_text_font_shapes]);
continue;
}
- if (t.cs() == "uuline" || t.cs() == "uwave"
+ // beamer has an \emph<overlay>{} inset
+ if ((t.cs() == "uuline" || t.cs() == "uwave"
|| t.cs() == "emph" || t.cs() == "noun"
- || t.cs() == "xout") {
+ || t.cs() == "xout") && !p.hasOpt("<")) {
context.check_layout(os);
os << "\n\\" << t.cs() << " on\n";
parse_text_snippet(p, os, FLAG_ITEM, outer, context);
continue;
}
- if (t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") {
+ if ((preamble.isPackageUsed("tipa") && t.cs() == "t" && p.next_token().asInput() == "*")
+ || t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") {
context.check_layout(os);
- begin_inset(os, "IPADeco " + t.cs().substr(4) + "\n");
+ if (t.cs() == "t")
+ // swallow star
+ p.get_token();
+ string const type = (t.cs() == "t") ? "bottomtiebar" : t.cs().substr(4);
+ begin_inset(os, "IPADeco " + type + "\n");
os << "status open\n";
parse_text_in_inset(p, os, FLAG_ITEM, outer, context);
end_inset(os);
if (!before.empty()) {
before.erase(0, 1);
before.erase(before.length() - 1, 1);
- bef = convert_latexed_command_inset_arg(after);
+ bef = convert_latexed_command_inset_arg(before);
literal |= !bef.first;
before = literal ? subst(before, "\n", " ") : bef.second;
if (literal && !after.empty())
if (!before.empty()) {
before.erase(0, 1);
before.erase(before.length() - 1, 1);
- bef = convert_latexed_command_inset_arg(after);
+ bef = convert_latexed_command_inset_arg(before);
literal |= !bef.first;
before = literal ? subst(before, "\n", " ") : bef.second;
}
if (!before.empty()) {
before.erase(0, 1);
before.erase(before.length() - 1, 1);
- bef = convert_latexed_command_inset_arg(after);
+ bef = convert_latexed_command_inset_arg(before);
literal |= !bef.first;
before = literal ? subst(before, "\n", " ") : bef.second;
if (literal && !after.empty())
// so simply skip it.
parse_text_snippet(p, FLAG_ITEM, false, context);
}
+ eat_whitespace(p, os, context, true);
continue;
}
if ((where = is_known(t.cs(), known_quotes))) {
context.check_layout(os);
begin_inset(os, "Quotes ");
- os << known_coded_quotes[where - known_quotes];
+ string quotetype = known_coded_quotes[where - known_quotes];
+ // try to make a smart guess about the side
+ Token const prev = p.prev_token();
+ bool const opening = (prev.cat() != catSpace && prev.character() != 0
+ && prev.character() != '\n' && prev.character() != '~');
+ quotetype = guessQuoteStyle(quotetype, opening);
+ os << quotetype;
end_inset(os);
// LyX adds {} after the quote, so we have to eat
// spaces here if there are any before a possible
}
if ((where = is_known(t.cs(), known_sizes)) &&
- context.new_layout_allowed) {
+ context.new_layout_allowed) {
context.check_layout(os);
TeXFont const oldFont = context.font;
context.font.size = known_coded_sizes[where - known_sizes];
continue;
}
- if (t.cs() == "textquotedbl") {
- context.check_layout(os);
- os << "\"";
- skip_braces(p);
- continue;
- }
-
if (t.cs() == "_" || t.cs() == "&" || t.cs() == "#"
|| t.cs() == "$" || t.cs() == "{" || t.cs() == "}"
|| t.cs() == "%" || t.cs() == "-") {
}
if (t.cs() == "input" || t.cs() == "include"
- || t.cs() == "verbatiminput") {
+ || t.cs() == "verbatiminput"
+ || t.cs() == "lstinputlisting"
+ || t.cs() == "inputminted") {
string name = t.cs();
- if (t.cs() == "verbatiminput"
+ if (name == "verbatiminput"
&& p.next_token().asInput() == "*")
name += p.get_token().asInput();
context.check_layout(os);
+ string lstparams;
+ bool literal = false;
+ if (name == "lstinputlisting" && p.hasOpt()) {
+ lstparams = p.getArg('[', ']');
+ pair<bool, string> oa = convert_latexed_command_inset_arg(lstparams);
+ literal = !oa.first;
+ if (literal)
+ lstparams = subst(lstparams, "\n", " ");
+ else
+ lstparams = oa.second;
+ } else if (name == "inputminted") {
+ name = "lstinputlisting";
+ string const lang = p.getArg('{', '}');
+ if (lang != "tex") {
+ string cmd = "\\inputminted{" + lang + "}{";
+ cmd += p.getArg('{', '}') + "}";
+ output_ert_inset(os, cmd, context);
+ continue;
+ }
+ if (prefixIs(minted_nonfloat_caption, "[t]")) {
+ minted_nonfloat_caption.erase(0,3);
+ // extract label and caption from the already produced LyX code
+ vector<string> nfc = getVectorFromString(minted_nonfloat_caption, "\n");
+ string const caption = nfc.front();
+ string label;
+ vector<string>::iterator it =
+ find(nfc.begin(), nfc.end(), "LatexCommand label");
+ if (it != nfc.end()) {
+ ++it;
+ if (it != nfc.end())
+ label = *it;
+ label = support::split(label, '"');
+ label.pop_back();
+ }
+ minted_nonfloat_caption.clear();
+ lstparams = "caption=" + caption;
+ if (!label.empty())
+ lstparams += ",label=" + label;
+ pair<bool, string> oa = convert_latexed_command_inset_arg(lstparams);
+ literal = !oa.first;
+ if (literal)
+ lstparams = subst(lstparams, "\n", " ");
+ else
+ lstparams = oa.second;
+ }
+ }
+ string lit = literal ? "\"true\"" : "\"false\"";
string filename(normalize_filename(p.getArg('{', '}')));
string const path = getMasterFilePath(true);
// We want to preserve relative / absolute filenames,
outname = subst(outname, "\"", "\\\"");
os << "preview false\n"
"filename \"" << outname << "\"\n";
+ if (!lstparams.empty())
+ os << "lstparams \"" << lstparams << "\"\n";
+ os << "literal " << lit << "\n";
if (t.cs() == "verbatiminput")
preamble.registerAutomaticallyLoadedPackage("verbatim");
}
continue;
}
+ // Before we look for the layout name alone below, we check the layouts including the LateXParam, which
+ // might be one or several options or a star.
+ // The single '=' is meant here.
+ if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true, p.getCommandLatexParam()))) {
+ if (starred)
+ p.get_token();
+ p.skip_spaces();
+ context.check_layout(os);
+ // store the latexparam here. This is eaten in parse_text_in_inset
+ context.latexparam = newinsetlayout->latexparam();
+ docstring name = newinsetlayout->name();
+ bool const caption = name.find(from_ascii("Caption:")) == 0;
+ if (caption) {
+ // Already done for floating minted listings.
+ if (minted_float.empty()) {
+ begin_inset(os, "Caption ");
+ os << to_utf8(name.substr(8)) << '\n';
+ }
+ } else {
+ // FIXME: what do we do if the prefix is not Flex: ?
+ if (prefixIs(name, from_ascii("Flex:")))
+ name.erase(0, 5);
+ begin_inset(os, "Flex ");
+ os << to_utf8(name) << '\n'
+ << "status collapsed\n";
+ }
+ if (!minted_float.empty()) {
+ parse_text_snippet(p, os, FLAG_ITEM, false, context);
+ } else if (newinsetlayout->isPassThru()) {
+ // set catcodes to verbatim early, just in case.
+ p.setCatcodes(VERBATIM_CATCODES);
+ string delim = p.get_token().asInput();
+ if (delim != "{")
+ cerr << "Warning: bad delimiter for command " << t.asInput() << endl;
+ //FIXME: handle error condition
+ string const arg = p.verbatimStuff("}").second;
+ Context newcontext(true, context.textclass);
+ if (newinsetlayout->forcePlainLayout())
+ newcontext.layout = &context.textclass.plainLayout();
+ output_ert(os, arg, newcontext);
+ } else
+ parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout);
+ context.latexparam.clear();
+ if (caption)
+ p.skip_spaces();
+ // Minted caption insets are not closed here because
+ // we collect everything into the caption.
+ if (minted_float.empty())
+ end_inset(os);
+ continue;
+ }
+
// The single '=' is meant here.
if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true))) {
if (starred)
// and math commands may be invalid (bug 6797)
string name = t.asInput();
// handle the dingbats, cyrillic and greek
- if (name == "\\ding" || name == "\\textcyr" ||
+ if (name == "\\textcyr")
+ name = "\\textcyrillic";
+ if (name == "\\ding" || name == "\\textcyrillic" ||
(name == "\\textgreek" && !preamble.usePolyglossia()))
name = name + '{' + p.getArg('{', '}') + '}';
// handle the ifsym characters