mirror of
https://git.lyx.org/repos/lyx.git
synced 2025-01-03 08:28:25 +00:00
Really fix bug #4468.
The old fix was incomplete (\verb~\~ was translated to \verb~~ in roundtrip). The real cause for this bug (and also the mistranslation of \href{...}{\}}) was the misbehaviour of Token::character() (see comment in Parser.h): This method even returns a character if the category is catEscape, and this is not wanted in most (all?) cases.
This commit is contained in:
parent
5afe35cc59
commit
2f7f0c7631
@ -383,7 +383,7 @@ bool Parser::hasOpt()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Parser::Arg Parser::getFullArg(char left, char right)
|
Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping)
|
||||||
{
|
{
|
||||||
skip_spaces(true);
|
skip_spaces(true);
|
||||||
|
|
||||||
@ -393,36 +393,40 @@ Parser::Arg Parser::getFullArg(char left, char right)
|
|||||||
return make_pair(false, string());
|
return make_pair(false, string());
|
||||||
|
|
||||||
string result;
|
string result;
|
||||||
char c = getChar();
|
Token t = get_token();
|
||||||
|
|
||||||
if (c != left) {
|
if (t.cat() == catComment || t.cat() == catEscape ||
|
||||||
|
t.character() != left) {
|
||||||
putback();
|
putback();
|
||||||
return make_pair(false, string());
|
return make_pair(false, string());
|
||||||
} else {
|
} else {
|
||||||
// a single '\' is only allowed within \verb, no matter what the delimiter is,
|
for (t = get_token(); good(); t = get_token()) {
|
||||||
// for example "\verb+\+" (reported as bug #4468)
|
|
||||||
// To support this, we allow single '\' if it is the only character
|
|
||||||
// within equal delimiters
|
|
||||||
if (next_token().cat() == catEscape)
|
|
||||||
if (next_token().character() == right && right == left)
|
|
||||||
result += '\\';
|
|
||||||
while ((c = getChar()) != right && good()) {
|
|
||||||
// Ignore comments
|
// Ignore comments
|
||||||
if (curr_token().cat() == catComment) {
|
if (t.cat() == catComment) {
|
||||||
if (!curr_token().cs().empty())
|
if (!t.cs().empty())
|
||||||
cerr << "Ignoring comment: " << curr_token().asInput();
|
cerr << "Ignoring comment: " << t.asInput();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
if (allow_escaping) {
|
||||||
result += curr_token().asInput();
|
if (t.cat() != catEscape && t.character() == right)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (t.character() == right) {
|
||||||
|
if (t.cat() == catEscape)
|
||||||
|
result += '\\';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += t.asInput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return make_pair(true, result);
|
return make_pair(true, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string Parser::getArg(char left, char right)
|
string Parser::getArg(char left, char right, bool allow_escaping)
|
||||||
{
|
{
|
||||||
return getFullArg(left, right).second;
|
return getFullArg(left, right, allow_escaping).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ public:
|
|||||||
* ../mathed/MathParser.cpp (which is the anchestor of this
|
* ../mathed/MathParser.cpp (which is the anchestor of this
|
||||||
* class) uses a separate char member for this method. I
|
* class) uses a separate char member for this method. I
|
||||||
* believe that the intended usage is to not cover tokens with
|
* believe that the intended usage is to not cover tokens with
|
||||||
* catEscape, e.g. \code
|
* catEscape or catComment, e.g. \code
|
||||||
* return (cs_.empty() || cat_ == catEscape) ? 0 : cs_[0];
|
* return (cs_.empty() || cat_ == catEscape || cat_ == catComment) ? 0 : cs_[0];
|
||||||
* \endcode
|
* \endcode
|
||||||
* All usages of this method should be checked. gb 2011-01-05
|
* All usages of this method should be checked. gb 2011-01-05
|
||||||
*/
|
*/
|
||||||
@ -157,18 +157,24 @@ public:
|
|||||||
typedef std::pair<bool, std::string> Arg;
|
typedef std::pair<bool, std::string> Arg;
|
||||||
/*!
|
/*!
|
||||||
* Get an argument enclosed by \p left and \p right.
|
* Get an argument enclosed by \p left and \p right.
|
||||||
|
* If \p allow_escaping is true, a right delimiter escaped by a
|
||||||
|
* backslash does not count as delimiter, but is included in the
|
||||||
|
* argument.
|
||||||
* \returns wether an argument was found in \p Arg.first and the
|
* \returns wether an argument was found in \p Arg.first and the
|
||||||
* argument in \p Arg.second. \see getArg().
|
* argument in \p Arg.second. \see getArg().
|
||||||
*/
|
*/
|
||||||
Arg getFullArg(char left, char right);
|
Arg getFullArg(char left, char right, bool allow_escaping = true);
|
||||||
/*!
|
/*!
|
||||||
* Get an argument enclosed by \p left and \p right.
|
* Get an argument enclosed by \p left and \p right.
|
||||||
|
* If \p allow_escaping is true, a right delimiter escaped by a
|
||||||
|
* backslash does not count as delimiter, but is included in the
|
||||||
|
* argument.
|
||||||
* \returns the argument (without \p left and \p right) or the empty
|
* \returns the argument (without \p left and \p right) or the empty
|
||||||
* string if the next non-space token is not \p left. Use
|
* string if the next non-space token is not \p left. Use
|
||||||
* getFullArg() if you need to know wether there was an empty
|
* getFullArg() if you need to know wether there was an empty
|
||||||
* argument or no argument at all.
|
* argument or no argument at all.
|
||||||
*/
|
*/
|
||||||
std::string getArg(char left, char right);
|
std::string getArg(char left, char right, bool allow_escaping = true);
|
||||||
/*!
|
/*!
|
||||||
* Like getOpt(), but distinguishes between a missing argument ""
|
* Like getOpt(), but distinguishes between a missing argument ""
|
||||||
* and an empty argument "[]".
|
* and an empty argument "[]".
|
||||||
|
@ -968,6 +968,19 @@ target "http://www.test.test"
|
|||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
|
||||||
|
parser test (escaped):
|
||||||
|
\begin_inset CommandInset href
|
||||||
|
LatexCommand href
|
||||||
|
name "a brace } and another one { and something"
|
||||||
|
target "http://www.test.test"
|
||||||
|
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Section
|
\begin_layout Section
|
||||||
|
@ -160,6 +160,8 @@ ftp2:\href{ftp://www.test.test}{www.test.test}
|
|||||||
|
|
||||||
parser test (stupid, but valid):\href{http://www.test.test}{\}}
|
parser test (stupid, but valid):\href{http://www.test.test}{\}}
|
||||||
|
|
||||||
|
parser test (escaped):\href{http://www.test.test}{a brace \} and another one \{ and something}
|
||||||
|
|
||||||
|
|
||||||
\section{Lists\index{Lists}}
|
\section{Lists\index{Lists}}
|
||||||
|
|
||||||
|
@ -1119,7 +1119,9 @@ status collapsed
|
|||||||
|
|
||||||
|
|
||||||
\backslash
|
\backslash
|
||||||
verb~~
|
verb~
|
||||||
|
\backslash
|
||||||
|
~
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\end_inset
|
\end_inset
|
||||||
@ -1140,6 +1142,21 @@ item[ABC] first item+
|
|||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\begin_inset ERT
|
||||||
|
status collapsed
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
|
||||||
|
|
||||||
|
\backslash
|
||||||
|
verb+something
|
||||||
|
\backslash
|
||||||
|
+
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
bug 4468
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
|
@ -321,6 +321,7 @@ zzz \section{
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
\verb~\~
|
\verb~\~
|
||||||
\verb+\item[ABC] first item+
|
\verb+\item[ABC] first item+
|
||||||
|
\verb+something\+ bug 4468
|
||||||
|
|
||||||
and bibliography:
|
and bibliography:
|
||||||
\begin{thebibliography}{9}
|
\begin{thebibliography}{9}
|
||||||
|
@ -3210,8 +3210,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
|
|||||||
|
|
||||||
else if (t.cs() == "href") {
|
else if (t.cs() == "href") {
|
||||||
context.check_layout(os);
|
context.check_layout(os);
|
||||||
string target = p.getArg('{', '}');
|
string target = convert_command_inset_arg(p.verbatim_item());
|
||||||
string name = p.getArg('{', '}');
|
string name = convert_command_inset_arg(p.verbatim_item());
|
||||||
string type;
|
string type;
|
||||||
size_t i = target.find(':');
|
size_t i = target.find(':');
|
||||||
if (i != string::npos) {
|
if (i != string::npos) {
|
||||||
@ -3729,7 +3729,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
|
|||||||
else if (t.cs() == "verb") {
|
else if (t.cs() == "verb") {
|
||||||
context.check_layout(os);
|
context.check_layout(os);
|
||||||
char const delimiter = p.next_token().character();
|
char const delimiter = p.next_token().character();
|
||||||
string const arg = p.getArg(delimiter, delimiter);
|
// \verb is special: The usual escaping rules do not
|
||||||
|
// apply, e.g. "\verb+\+" is valid and denotes a single
|
||||||
|
// backslash (bug #4468). Therefore we do not allow
|
||||||
|
// escaping in getArg().
|
||||||
|
string const arg = p.getArg(delimiter, delimiter, false);
|
||||||
ostringstream oss;
|
ostringstream oss;
|
||||||
oss << "\\verb" << delimiter << arg << delimiter;
|
oss << "\\verb" << delimiter << arg << delimiter;
|
||||||
handle_ert(os, oss.str(), context);
|
handle_ert(os, oss.str(), context);
|
||||||
|
Loading…
Reference in New Issue
Block a user