mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 05:28:49 +00: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:
parent
6fc9e6f21e
commit
90495f3ac5
7 changed files with 56 additions and 40 deletions
|
@ -155,8 +155,7 @@ static void write_part(const wchar_t *begin,
|
|||
// fwprintf( stderr, L"Subshell: %ls, end char %lc\n", buff, *end );
|
||||
out.clear();
|
||||
tokenizer_t tok(buff, TOK_ACCEPT_UNFINISHED);
|
||||
for (; tok_has_next(&tok);
|
||||
tok_next(&tok))
|
||||
for (; tok_has_next(&tok); tok_next(&tok))
|
||||
{
|
||||
if ((cut_at_cursor) &&
|
||||
(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)
|
||||
{
|
||||
|
||||
int mode = 0;
|
||||
int out_pos;
|
||||
size_t in_pos;
|
||||
size_t len;
|
||||
|
@ -1097,8 +1095,8 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
int bracket_count=0;
|
||||
wchar_t prev=0;
|
||||
wchar_t *in;
|
||||
int unescape_special = flags & UNESCAPE_SPECIAL;
|
||||
int allow_incomplete = flags & UNESCAPE_INCOMPLETE;
|
||||
bool unescape_special = !! (flags & UNESCAPE_SPECIAL);
|
||||
bool allow_incomplete = !! (flags & UNESCAPE_INCOMPLETE);
|
||||
|
||||
CHECK(orig, 0);
|
||||
|
||||
|
@ -1107,6 +1105,12 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
|
||||
if (!in)
|
||||
DIE_MEM();
|
||||
|
||||
enum {
|
||||
mode_unquoted,
|
||||
mode_single_quotes,
|
||||
mode_double_quotes
|
||||
} mode = mode_unquoted;
|
||||
|
||||
for (in_pos=0, out_pos=0;
|
||||
in_pos<len;
|
||||
|
@ -1116,20 +1120,20 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
switch (mode)
|
||||
{
|
||||
|
||||
/*
|
||||
Mode 0 means unquoted string
|
||||
*/
|
||||
case 0:
|
||||
/*
|
||||
Mode 0 means unquoted string
|
||||
*/
|
||||
case mode_unquoted:
|
||||
{
|
||||
if (c == L'\\')
|
||||
{
|
||||
switch (in[++in_pos])
|
||||
{
|
||||
|
||||
/*
|
||||
A null character after a backslash is an
|
||||
error, return null
|
||||
*/
|
||||
/*
|
||||
A null character after a backslash is an
|
||||
error, return null
|
||||
*/
|
||||
case L'\0':
|
||||
{
|
||||
if (!allow_incomplete)
|
||||
|
@ -1317,7 +1321,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
in[out_pos]=L'\t';
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
\v means vertical tab
|
||||
*/
|
||||
|
@ -1326,6 +1330,11 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
in[out_pos]=L'\v';
|
||||
break;
|
||||
}
|
||||
|
||||
/* If a backslash is followed by an actual newline, swallow them both */
|
||||
case L'\n':
|
||||
out_pos--;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
|
@ -1454,7 +1463,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
|
||||
case L'\'':
|
||||
{
|
||||
mode = 1;
|
||||
mode = mode_single_quotes;
|
||||
if (unescape_special)
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
else
|
||||
|
@ -1464,7 +1473,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
|
||||
case L'\"':
|
||||
{
|
||||
mode = 2;
|
||||
mode = mode_double_quotes;
|
||||
if (unescape_special)
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
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'\\')
|
||||
{
|
||||
|
@ -1493,13 +1503,12 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
{
|
||||
case '\\':
|
||||
case L'\'':
|
||||
case L'\n':
|
||||
{
|
||||
in[out_pos]=in[in_pos];
|
||||
break;
|
||||
}
|
||||
|
||||
case 0:
|
||||
case L'\0':
|
||||
{
|
||||
if (!allow_incomplete)
|
||||
{
|
||||
|
@ -1513,6 +1522,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
in[out_pos++] = L'\\';
|
||||
|
@ -1527,7 +1537,7 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
else
|
||||
out_pos--;
|
||||
mode = 0;
|
||||
mode = mode_unquoted;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1540,13 +1550,13 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
/*
|
||||
Mode 2 means double quoted string, i.e. "foo"
|
||||
*/
|
||||
case 2:
|
||||
case mode_double_quotes:
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
{
|
||||
mode = 0;
|
||||
mode = mode_unquoted;
|
||||
if (unescape_special)
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
else
|
||||
|
@ -1575,11 +1585,16 @@ wchar_t *unescape(const wchar_t * orig, int flags)
|
|||
case '\\':
|
||||
case L'$':
|
||||
case '"':
|
||||
case '\n':
|
||||
{
|
||||
in[out_pos]=in[in_pos];
|
||||
break;
|
||||
}
|
||||
|
||||
case '\n':
|
||||
{
|
||||
out_pos--;
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
while (tok_has_next(&tok) && !end_loop)
|
||||
{
|
||||
|
||||
switch (tok_last_type(&tok))
|
||||
{
|
||||
|
||||
|
@ -1881,7 +1880,6 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, complete_ty
|
|||
end_loop=1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
symbol. The only backslash escapes accepted within double quotes are
|
||||
\\", which escapes a double quote, \\$, which escapes a dollar
|
||||
character, and \\\\, which escapes the backslash symbol. Single quotes
|
||||
have no special meaning withing double quotes and vice versa.
|
||||
character, \\ followed by a newline, which deletes the backslash
|
||||
and the newline, and lastly \\\\, which escapes the backslash symbol.
|
||||
Single quotes have no special meaning withing double quotes and vice versa.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -1454,7 +1455,6 @@ g++, javac, java, gcj, lpr, doxygen, whois)
|
|||
- Descriptions for variables using 'set -d'.
|
||||
- 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
|
||||
- Right-side prompt
|
||||
- Selectable completions in the pager
|
||||
- Per process output redirection
|
||||
- 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.
|
||||
- bindings in config.fish are overwritten by default key bindings.
|
||||
- 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.
|
||||
|
||||
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 foo-{1,2{3,4}}
|
||||
|
||||
# Escpaed newlines
|
||||
echo foo\ bar
|
||||
echo foo\
|
||||
bar
|
||||
echo "foo\
|
||||
bar"
|
||||
echo 'foo\
|
||||
bar'
|
||||
|
||||
# Simple alias tests
|
||||
|
||||
function foo
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
x-1
|
||||
x-1 x-2
|
||||
foo-1 foo-23 foo-24
|
||||
foo bar
|
||||
foobar
|
||||
foobar
|
||||
foo\
|
||||
bar
|
||||
Test 2 pass
|
||||
Test pass
|
||||
Test 3 pass
|
||||
|
|
|
@ -255,14 +255,6 @@ static void read_string(tokenizer_t *tok)
|
|||
tok->buff--;
|
||||
do_loop = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (*tok->buff == L'\n' && mode == mode_regular_text)
|
||||
{
|
||||
tok->buff--;
|
||||
do_loop = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
tok->buff++;
|
||||
|
|
Loading…
Reference in a new issue