}
-void Parser::skip_spaces(bool skip_comments)
+bool Parser::skip_spaces(bool skip_comments)
{
// We just silently return if we have no more tokens.
// skip_spaces() should be callable at any time,
// the caller must check p::good() anyway.
+ bool skipped = false;
while (good()) {
get_token();
if (isParagraph()) {
putback();
break;
}
- if ( curr_token().cat() == catSpace ||
- curr_token().cat() == catNewline ||
- (curr_token().cat() == catComment && curr_token().cs().empty()))
+ if (curr_token().cat() == catSpace ||
+ curr_token().cat() == catNewline) {
+ skipped = true;
+ continue;
+ }
+ if ((curr_token().cat() == catComment && curr_token().cs().empty()))
continue;
if (skip_comments && curr_token().cat() == catComment)
cerr << " Ignoring comment: " << curr_token().asInput();
break;
}
}
+ return skipped;
}
}
-string Parser::getOpt()
+string Parser::getOpt(bool keepws)
{
string const res = getArg('[', ']');
- return res.empty() ? string() : '[' + res + ']';
+ if (res.empty()) {
+ if (keepws)
+ unskip_spaces(true);
+ return string();
+ }
+ return '[' + res + ']';
}
/*!
* \returns getArg('[', ']') including the brackets or the
* empty string if there is no such argument.
+ * No whitespace is eaten if \p keepws is true and no optional
+ * argument exists. This is important if an optional argument is
+ * parsed that would go after a command in ERT: In this case the
+ * whitespace is needed to separate the ERT from the subsequent
+ * word. Without it, the ERT and the next word would be concatenated
+ * during .tex export, thus creating an invalid command.
*/
- std::string getOpt();
+ std::string getOpt(bool keepws = false);
/*!
- * \returns getFullArg('[', ']') including the parentheses or the
- * empty string if there is no such argument.
+ * the same as getOpt but without the brackets
*/
std::string getOptContent();
/*!
- * the same as getOpt but without the brackets
+ * \returns getFullArg('(', ')') including the parentheses or the
+ * empty string if there is no such argument.
*/
std::string getFullParentheseArg();
/*!
/// \return whether the current token starts a new paragraph
bool isParagraph();
/// skips spaces (and comments if \p skip_comments is true)
- void skip_spaces(bool skip_comments = false);
+ /// \return whether whitespace was skipped (not comments)
+ bool skip_spaces(bool skip_comments = false);
/// puts back spaces (and comments if \p skip_comments is true)
void unskip_spaces(bool skip_comments = false);
///
+%% LyX trick_preamble_code_into_believing_that_this_was_created_by_lyx created this file. For more info, see http://www.lyx.org/.
+%% Do not edit unless you really know what you are doing.
\documentclass[a4paper,12pt]{article}
\usepackage[T1]{fontenc}
\usepackage[latin9]{inputenc}
\providecommand{\makenomenclature}{\makeglossary}
\usepackage{varioref}
\usepackage{prettyref}
-\usepackage{subscript}
+\usepackage{makeidx}
\usepackage{graphicx}
\newcommand{\lyxarrow}{\leavevmode\,$\triangleright$\,\allowbreak}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.
+\usepackage{subscript} % user specified as long as tex2lyx
+% produces a format less than 408
+
+\def\mycommand{\textquestiondown}
+
\begin{document}
\tableofcontents
\section{Input files\index{Input files}}
We can input files too, like this \input{DummyDocument}, or with the include
-variant \include{DummyDocument}
+variant \include{DummyDocument} % unfortunately, including the doc twice
+% generates a multiply defined label
If you prefer verbatim input, you can choose
between~\verbatiminput{foo} or~\verbatiminput*{foo}.
ellipsis\ldots, and end-of-sentence\@. LyX also supports a menu
separator\lyxarrow{}and a spif\textcompwordmark{}fy ligature break.
+Test for whitespace handling of commands: The following lines should
+result in identical output:
+
+builtin \textasciicircum{} unicodesymbols \j{} user \mycommand{} xx\par
+builtin \textasciicircum {} unicodesymbols \j {} user \mycommand{} xx\par
+builtin \textasciicircum % with a comment
+{} unicodesymbols \j % and a second one
+{} user \mycommand % and another
+{} xx
+
A sub\textsubscript{sc\emph{ript}} and super\textsuperscript{script
with $a^2+b^2=c^2$ math}.
}
-void skip_braces(Parser & p)
+bool skip_braces(Parser & p)
{
if (p.next_token().cat() != catBegin)
- return;
+ return false;
p.get_token();
if (p.next_token().cat() == catEnd) {
p.get_token();
- return;
+ return true;
}
p.putback();
+ return false;
}
void eat_whitespace(Parser &, ostream &, Context &, bool);
+/*!
+ * Skips whitespace and braces.
+ * This should be called after a command has been parsed that is not put into
+ * ERT, and where LyX adds "{}" if needed.
+ */
+void skip_spaces_braces(Parser & p)
+{
+ /* The following four examples produce the same typeset output and
+ should be handled by this function:
+ - abc \j{} xyz
+ - abc \j {} xyz
+ - abc \j
+ {} xyz
+ - abc \j %comment
+ {} xyz
+ */
+ // Unfortunately we need to skip comments, too.
+ // We can't use eat_whitespace since writing them after the {}
+ // results in different output in some cases.
+ bool const skipped_spaces = p.skip_spaces(true);
+ bool const skipped_braces = skip_braces(p);
+ if (skipped_spaces && !skipped_braces)
+ // put back the space (it is better handled by check_space)
+ p.unskip_spaces(true);
+}
+
+
void output_command_layout(ostream & os, Parser & p, bool outer,
Context & parent_context,
Layout const * newlayout)
ert += '{' + p.verbatim_item() + '}';
break;
case optional:
- ert += p.getOpt();
+ // true because we must not eat whitespace
+ ert += p.getOpt(true);
break;
}
}
else if (t.cs() == "makeindex" || t.cs() == "maketitle") {
// FIXME: Somehow prevent title layouts if
// "maketitle" was not found
- p.skip_spaces();
- skip_braces(p); // swallow this
+ // swallow this
+ skip_spaces_braces(p);
}
else if (t.cs() == "tableofcontents") {
- p.skip_spaces();
context.check_layout(os);
begin_command_inset(os, "toc", "tableofcontents");
end_inset(os);
- skip_braces(p); // swallow this
+ skip_spaces_braces(p);
}
else if (t.cs() == "listoffigures") {
- p.skip_spaces();
context.check_layout(os);
begin_inset(os, "FloatList figure\n");
end_inset(os);
- skip_braces(p); // swallow this
+ skip_spaces_braces(p);
}
else if (t.cs() == "listoftables") {
- p.skip_spaces();
context.check_layout(os);
begin_inset(os, "FloatList table\n");
end_inset(os);
- skip_braces(p); // swallow this
+ skip_spaces_braces(p);
}
else if (t.cs() == "listof") {
context.check_layout(os);
begin_command_inset(os, "index_print", "printindex");
end_inset(os);
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (t.cs() == "printnomenclature") {
context.check_layout(os);
begin_command_inset(os, "nomencl_print", "printnomenclature");
end_inset(os);
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (t.cs() == "url") {
|| t.cs() == "LaTeX") {
context.check_layout(os);
os << t.cs();
- skip_braces(p); // eat {}
+ skip_spaces_braces(p);
}
else if (t.cs() == "LaTeXe") {
context.check_layout(os);
os << "LaTeX2e";
- skip_braces(p); // eat {}
+ skip_spaces_braces(p);
}
else if (t.cs() == "ldots") {
context.check_layout(os);
- skip_braces(p);
os << "\\SpecialChar \\ldots{}\n";
+ skip_spaces_braces(p);
}
else if (t.cs() == "lyxarrow") {
context.check_layout(os);
os << "\\SpecialChar \\menuseparator\n";
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (t.cs() == "textcompwordmark") {
context.check_layout(os);
os << "\\SpecialChar \\textcompwordmark{}\n";
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (LYX_FORMAT >= 307 && t.cs() == "slash") {
context.check_layout(os);
os << "\\SpecialChar \\slash{}\n";
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (LYX_FORMAT >= 307 && t.cs() == "nobreakdash") {
else if (t.cs() == "textasciitilde") {
context.check_layout(os);
os << '~';
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (t.cs() == "textasciicircum") {
context.check_layout(os);
os << '^';
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (t.cs() == "textbackslash") {
context.check_layout(os);
os << "\n\\backslash\n";
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (t.cs() == "_" || t.cs() == "&" || t.cs() == "#"
else if (t.cs() == "newline") {
context.check_layout(os);
os << "\n\\" << t.cs() << "\n";
- skip_braces(p); // eat {}
+ skip_spaces_braces(p);
}
else if (t.cs() == "input" || t.cs() == "include"
begin_inset(os, "VSpace ");
os << t.cs();
end_inset(os);
- skip_braces(p);
+ skip_spaces_braces(p);
}
else if (is_known(t.cs(), known_spaces)) {
t.cs() == "cleardoublepage") {
context.check_layout(os);
os << "\n\\" << t.cs() << "\n";
- skip_braces(p); // eat {}
+ skip_spaces_braces(p);
}
else if (t.cs() == "newcommand" ||
<< "+" << to_utf8(rem) << endl;
context.check_layout(os);
os << to_utf8(s);
- p.skip_spaces();
- skip_braces(p); // eat {}
+ skip_spaces_braces(p);
}
//cerr << "#: " << t << " mode: " << mode << endl;
// heuristic: read up to next non-nested space