mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-23 02:12:08 +08:00
Enable multi-line edit when the line ends with a pipe (#1285)
This commit is contained in:
parent
cefb9e6d03
commit
38418d6356
|
@ -302,6 +302,7 @@ static volatile sig_atomic_t interrupted = 0;
|
|||
// Prototypes for a bunch of functions defined later on.
|
||||
static bool is_backslashed(const wcstring &str, size_t pos);
|
||||
static wchar_t unescaped_quote(const wcstring &str, size_t pos);
|
||||
static bool ends_with_pipe(const wcstring &str, size_t pos);
|
||||
|
||||
/// Mode on startup, which we restore on exit.
|
||||
static struct termios terminal_mode_on_startup;
|
||||
|
@ -2302,6 +2303,19 @@ static bool is_backslashed(const wcstring &str, size_t pos) {
|
|||
return (count % 2) == 1;
|
||||
}
|
||||
|
||||
/// Test if the specified string ends with pipe. Whitespaces at the end are ignored. It returns
|
||||
/// false if backslashed before the pipe because it should be treated as an escaped character.
|
||||
static bool ends_with_pipe(const wcstring &str, size_t pos) {
|
||||
if (pos > str.size()) return false;
|
||||
|
||||
while (pos--) {
|
||||
wchar_t c = str.at(pos);
|
||||
if (c == L'|') return !is_backslashed(str, pos);
|
||||
if (!iswspace(c)) break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static wchar_t unescaped_quote(const wcstring &str, size_t pos) {
|
||||
wchar_t result = L'\0';
|
||||
if (pos < str.size()) {
|
||||
|
@ -2751,6 +2765,12 @@ const wchar_t *reader_readline(int nchars) {
|
|||
insert_char(el, '\n');
|
||||
break;
|
||||
}
|
||||
// A newline is inserted if the line ends with a pipe (issue #1285).
|
||||
if (ends_with_pipe(el->text, el->size())) {
|
||||
el->position = el->size();
|
||||
insert_char(el, '\n');
|
||||
break;
|
||||
}
|
||||
|
||||
// See if this command is valid.
|
||||
int command_test_result = data->test_func(el->text.c_str());
|
||||
|
|
|
@ -102,7 +102,16 @@ bool tokenizer_t::next(struct tok_t *result) {
|
|||
}
|
||||
|
||||
assert(this->buff >= this->orig_buff);
|
||||
result->length = current_pos >= this->last_pos ? current_pos - this->last_pos : 0;
|
||||
if (this->last_type == TOK_PIPE) {
|
||||
// Ignore subsequent whitespaces or a newline after a pipe (#1285).
|
||||
int pipe_pos = current_pos - 1;
|
||||
while (this->orig_buff[pipe_pos] != L'|') {
|
||||
pipe_pos--;
|
||||
}
|
||||
result->length = pipe_pos - this->last_pos + 1;
|
||||
} else {
|
||||
result->length = current_pos >= this->last_pos ? current_pos - this->last_pos : 0;
|
||||
}
|
||||
|
||||
this->tok_next();
|
||||
return true;
|
||||
|
@ -556,6 +565,7 @@ void tokenizer_t::tok_next() {
|
|||
this->last_token = L"1";
|
||||
this->last_type = TOK_PIPE;
|
||||
this->buff++;
|
||||
skip_newline_after_pipe();
|
||||
break;
|
||||
}
|
||||
case L'>':
|
||||
|
@ -570,6 +580,9 @@ void tokenizer_t::tok_next() {
|
|||
TOK_CALL_ERROR(this, TOK_OTHER, REDIRECT_ERROR, this->buff);
|
||||
} else {
|
||||
this->buff += consumed;
|
||||
if (mode == TOK_PIPE) {
|
||||
skip_newline_after_pipe();
|
||||
}
|
||||
this->last_type = mode;
|
||||
this->last_token = to_string(fd);
|
||||
}
|
||||
|
@ -593,6 +606,9 @@ void tokenizer_t::tok_next() {
|
|||
TOK_CALL_ERROR(this, TOK_OTHER, PIPE_ERROR, error_location);
|
||||
} else {
|
||||
this->buff += consumed;
|
||||
if (mode == TOK_PIPE) {
|
||||
skip_newline_after_pipe();
|
||||
}
|
||||
this->last_type = mode;
|
||||
this->last_token = to_string(fd);
|
||||
}
|
||||
|
@ -605,6 +621,20 @@ void tokenizer_t::tok_next() {
|
|||
}
|
||||
}
|
||||
|
||||
/// If the line ends with pipe, continue to the next line (#1285).
|
||||
void tokenizer_t::skip_newline_after_pipe() {
|
||||
while (1) {
|
||||
if (this->buff[0] == L'\n') {
|
||||
this->buff++;
|
||||
break;
|
||||
} else if (my_iswspace(this->buff[0])) {
|
||||
this->buff++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wcstring tok_first(const wcstring &str) {
|
||||
wcstring result;
|
||||
tokenizer_t t(str.c_str(), TOK_SQUASH_ERRORS);
|
||||
|
|
|
@ -107,6 +107,9 @@ class tokenizer_t {
|
|||
void read_comment();
|
||||
void tok_next();
|
||||
|
||||
/// Skip whitespaces and a newline after a pipe at the end of the line.
|
||||
void skip_newline_after_pipe();
|
||||
|
||||
public:
|
||||
/// Constructor for a tokenizer. b is the string that is to be tokenized. It is not copied, and
|
||||
/// should not be freed by the caller until after the tokenizer is destroyed.
|
||||
|
|
Loading…
Reference in New Issue
Block a user