mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-02 14:01:20 -03:00
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:
@@ -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))
|
||||||
|
|||||||
61
common.cpp
61
common.cpp
@@ -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:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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++;
|
||||||
|
|||||||
Reference in New Issue
Block a user