Implement new newline-escaping behavior. Backslashes at the end of lines now essentially delete the newline, within normal text or double quotes. Backslashes are retained within single quotes.

Fixes https://github.com/fish-shell/fish-shell/issues/347
Fixes https://github.com/fish-shell/fish-shell/issues/52
This commit is contained in:
ridiculousfish
2012-11-22 01:09:07 -08:00
parent 6fc9e6f21e
commit 90495f3ac5
7 changed files with 56 additions and 40 deletions

View File

@@ -155,8 +155,7 @@ static void write_part(const wchar_t *begin,
// fwprintf( stderr, L"Subshell: %ls, end char %lc\n", buff, *end ); // fwprintf( stderr, L"Subshell: %ls, end char %lc\n", buff, *end );
out.clear(); out.clear();
tokenizer_t tok(buff, TOK_ACCEPT_UNFINISHED); tokenizer_t tok(buff, TOK_ACCEPT_UNFINISHED);
for (; tok_has_next(&tok); for (; tok_has_next(&tok); tok_next(&tok))
tok_next(&tok))
{ {
if ((cut_at_cursor) && if ((cut_at_cursor) &&
(tok_get_pos(&tok)+wcslen(tok_last(&tok)) >= pos)) (tok_get_pos(&tok)+wcslen(tok_last(&tok)) >= pos))

View File

@@ -1088,8 +1088,6 @@ wcstring escape_string(const wcstring &in, escape_flags_t flags)
wchar_t *unescape(const wchar_t * orig, int flags) wchar_t *unescape(const wchar_t * orig, int flags)
{ {
int mode = 0;
int out_pos; int out_pos;
size_t in_pos; size_t in_pos;
size_t len; size_t len;
@@ -1097,8 +1095,8 @@ wchar_t *unescape(const wchar_t * orig, int flags)
int bracket_count=0; int bracket_count=0;
wchar_t prev=0; wchar_t prev=0;
wchar_t *in; wchar_t *in;
int unescape_special = flags & UNESCAPE_SPECIAL; bool unescape_special = !! (flags & UNESCAPE_SPECIAL);
int allow_incomplete = flags & UNESCAPE_INCOMPLETE; bool allow_incomplete = !! (flags & UNESCAPE_INCOMPLETE);
CHECK(orig, 0); CHECK(orig, 0);
@@ -1107,6 +1105,12 @@ wchar_t *unescape(const wchar_t * orig, int flags)
if (!in) if (!in)
DIE_MEM(); DIE_MEM();
enum {
mode_unquoted,
mode_single_quotes,
mode_double_quotes
} mode = mode_unquoted;
for (in_pos=0, out_pos=0; for (in_pos=0, out_pos=0;
in_pos<len; in_pos<len;
@@ -1116,20 +1120,20 @@ wchar_t *unescape(const wchar_t * orig, int flags)
switch (mode) switch (mode)
{ {
/* /*
Mode 0 means unquoted string Mode 0 means unquoted string
*/ */
case 0: case mode_unquoted:
{ {
if (c == L'\\') if (c == L'\\')
{ {
switch (in[++in_pos]) switch (in[++in_pos])
{ {
/* /*
A null character after a backslash is an A null character after a backslash is an
error, return null error, return null
*/ */
case L'\0': case L'\0':
{ {
if (!allow_incomplete) if (!allow_incomplete)
@@ -1317,7 +1321,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
in[out_pos]=L'\t'; in[out_pos]=L'\t';
break; break;
} }
/* /*
\v means vertical tab \v means vertical tab
*/ */
@@ -1326,6 +1330,11 @@ wchar_t *unescape(const wchar_t * orig, int flags)
in[out_pos]=L'\v'; in[out_pos]=L'\v';
break; break;
} }
/* If a backslash is followed by an actual newline, swallow them both */
case L'\n':
out_pos--;
break;
default: default:
{ {
@@ -1454,7 +1463,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
case L'\'': case L'\'':
{ {
mode = 1; mode = mode_single_quotes;
if (unescape_special) if (unescape_special)
in[out_pos] = INTERNAL_SEPARATOR; in[out_pos] = INTERNAL_SEPARATOR;
else else
@@ -1464,7 +1473,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
case L'\"': case L'\"':
{ {
mode = 2; mode = mode_double_quotes;
if (unescape_special) if (unescape_special)
in[out_pos] = INTERNAL_SEPARATOR; in[out_pos] = INTERNAL_SEPARATOR;
else else
@@ -1483,9 +1492,10 @@ wchar_t *unescape(const wchar_t * orig, int flags)
} }
/* /*
Mode 1 means single quoted string, i.e 'foo' Mode 1 means single quoted string, i.e 'foo'.
A backslash at the end of a line in a single quoted string does not swallow the backslash or newline.
*/ */
case 1: case mode_single_quotes:
{ {
if (c == L'\\') if (c == L'\\')
{ {
@@ -1493,13 +1503,12 @@ wchar_t *unescape(const wchar_t * orig, int flags)
{ {
case '\\': case '\\':
case L'\'': case L'\'':
case L'\n':
{ {
in[out_pos]=in[in_pos]; in[out_pos]=in[in_pos];
break; break;
} }
case 0: case L'\0':
{ {
if (!allow_incomplete) if (!allow_incomplete)
{ {
@@ -1513,6 +1522,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
} }
} }
break; break;
default: default:
{ {
in[out_pos++] = L'\\'; in[out_pos++] = L'\\';
@@ -1527,7 +1537,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
in[out_pos] = INTERNAL_SEPARATOR; in[out_pos] = INTERNAL_SEPARATOR;
else else
out_pos--; out_pos--;
mode = 0; mode = mode_unquoted;
} }
else else
{ {
@@ -1540,13 +1550,13 @@ wchar_t *unescape(const wchar_t * orig, int flags)
/* /*
Mode 2 means double quoted string, i.e. "foo" Mode 2 means double quoted string, i.e. "foo"
*/ */
case 2: case mode_double_quotes:
{ {
switch (c) switch (c)
{ {
case '"': case '"':
{ {
mode = 0; mode = mode_unquoted;
if (unescape_special) if (unescape_special)
in[out_pos] = INTERNAL_SEPARATOR; in[out_pos] = INTERNAL_SEPARATOR;
else else
@@ -1575,11 +1585,16 @@ wchar_t *unescape(const wchar_t * orig, int flags)
case '\\': case '\\':
case L'$': case L'$':
case '"': case '"':
case '\n':
{ {
in[out_pos]=in[in_pos]; in[out_pos]=in[in_pos];
break; break;
} }
case '\n':
{
out_pos--;
break;
}
default: default:
{ {

View File

@@ -1810,7 +1810,6 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, complete_ty
tokenizer_t tok(buff.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS); tokenizer_t tok(buff.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
while (tok_has_next(&tok) && !end_loop) while (tok_has_next(&tok) && !end_loop)
{ {
switch (tok_last_type(&tok)) switch (tok_last_type(&tok))
{ {
@@ -1881,7 +1880,6 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, complete_ty
end_loop=1; end_loop=1;
break; break;
} }
} }
if (tok_get_pos(&tok) >= (long)pos) if (tok_get_pos(&tok) >= (long)pos)

View File

@@ -92,8 +92,9 @@ only backslash escape accepted within single quotes is \\', which
escapes a single quote and \\\\, which escapes the backslash escapes a single quote and \\\\, which escapes the backslash
symbol. The only backslash escapes accepted within double quotes are symbol. The only backslash escapes accepted within double quotes are
\\", which escapes a double quote, \\$, which escapes a dollar \\", which escapes a double quote, \\$, which escapes a dollar
character, and \\\\, which escapes the backslash symbol. Single quotes character, \\ followed by a newline, which deletes the backslash
have no special meaning withing double quotes and vice versa. and the newline, and lastly \\\\, which escapes the backslash symbol.
Single quotes have no special meaning withing double quotes and vice versa.
Example: Example:
@@ -1454,7 +1455,6 @@ g++, javac, java, gcj, lpr, doxygen, whois)
- Descriptions for variables using 'set -d'. - Descriptions for variables using 'set -d'.
- Parse errors should when possible honor IO redirections - Parse errors should when possible honor IO redirections
- Support for writing strings like /u/l/b/foo and have them expand to /usr/local/bin/foo - perhaps through tab expansion - Support for writing strings like /u/l/b/foo and have them expand to /usr/local/bin/foo - perhaps through tab expansion
- Right-side prompt
- Selectable completions in the pager - Selectable completions in the pager
- Per process output redirection - Per process output redirection
- Reduce the space of the pager by one line to allow the commandline to remain visible. - Reduce the space of the pager by one line to allow the commandline to remain visible.
@@ -1484,8 +1484,6 @@ g++, javac, java, gcj, lpr, doxygen, whois)
- There have been stray reports of issues with strange values of the PATH variable during startup. - There have been stray reports of issues with strange values of the PATH variable during startup.
- bindings in config.fish are overwritten by default key bindings. - bindings in config.fish are overwritten by default key bindings.
- Adding 'bind -k ...' doesn't overwrite non-keybinding binds of the same sequence. - Adding 'bind -k ...' doesn't overwrite non-keybinding binds of the same sequence.
- History file does not remove duplicates.
- History file should apply some kind of maximum history length.
- Older versions of Doxygen has bugs in the man-page generation which cause the builtin help to render incorrectly. Version 1.2.14 is known to have this problem. - Older versions of Doxygen has bugs in the man-page generation which cause the builtin help to render incorrectly. Version 1.2.14 is known to have this problem.
If you think you have found a bug not described here, please send a If you think you have found a bug not described here, please send a

View File

@@ -15,6 +15,15 @@ echo x-{1}
echo x-{1,2} echo x-{1,2}
echo foo-{1,2{3,4}} echo foo-{1,2{3,4}}
# Escpaed newlines
echo foo\ bar
echo foo\
bar
echo "foo\
bar"
echo 'foo\
bar'
# Simple alias tests # Simple alias tests
function foo function foo

View File

@@ -5,6 +5,11 @@
x-1 x-1
x-1 x-2 x-1 x-2
foo-1 foo-23 foo-24 foo-1 foo-23 foo-24
foo bar
foobar
foobar
foo\
bar
Test 2 pass Test 2 pass
Test pass Test pass
Test 3 pass Test 3 pass

View File

@@ -255,14 +255,6 @@ static void read_string(tokenizer_t *tok)
tok->buff--; tok->buff--;
do_loop = 0; do_loop = 0;
} }
}
else if (*tok->buff == L'\n' && mode == mode_regular_text)
{
tok->buff--;
do_loop = 0;
break;
} }
tok->buff++; tok->buff++;