mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
lineedit: make both ^M and ^J terminate a line.
In protocols other than PROT_RAW, the new line editing system differed from the old one in not considering ^M or ^J (typed using the actual Ctrl key, so distinct from pressing Return) to mean "I've finished editing this line, please send it". This commit reinstates that behaviour. It turned out that a third-party tool (namely PuTTY Connection Manager), which automatically answers prompts for the user, was terminating them by sending ^J in place of the Return key. We don't know why (and it's now unmaintained), but it was. So this change should make that tool start working again. I exclude PROT_RAW above because in that protocol the line editing has much weirder handling for ^M and ^J, which lineedit replicated faithfully from the old code: either control character by itself is treated literally (displaying as "^M" or "^J" in the terminal), but if you type the two in sequence in that order, then the ^J deletes the ^M from the edit buffer and enters the line, so that the sequence CR LF acts as a newline overall. I haven't changed that behaviour here, but I have added a regression test of it to test_lineedit.
This commit is contained in:
parent
1fc5f4afd1
commit
363debc7f0
@ -454,6 +454,24 @@ void lineedit_input(TermLineEditor *le, char ch, bool dedicated)
|
|||||||
lineedit_complete_line(le);
|
lineedit_complete_line(le);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
/* If we're not in LE_CRLF_NEWLINE mode, then ^J by
|
||||||
|
* itself acts as a full newline character */
|
||||||
|
lineedit_complete_line(le);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case CTRL('M'):
|
||||||
|
if (le->flags & LE_CRLF_NEWLINE) {
|
||||||
|
/* In this mode, ^M is literal, and can combine with
|
||||||
|
* ^J (see case above). So do nothing, and fall
|
||||||
|
* through into the 'treat it literally' code, */
|
||||||
|
} else {
|
||||||
|
/* If we're not in LE_CRLF_NEWLINE mode, then ^M by
|
||||||
|
* itself acts as a full newline character */
|
||||||
|
lineedit_complete_line(le);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,6 +527,65 @@ static void test_edit(Mock *mk, bool echo)
|
|||||||
EXPECT(mk, specials, 1, SS_EOF, 0);
|
EXPECT(mk, specials, 1, SS_EOF, 0);
|
||||||
reset(mk);
|
reset(mk);
|
||||||
|
|
||||||
|
/* ^M with the special flag is the Return key, and sends the line */
|
||||||
|
ldisc_send(mk->ldisc, "abc", 3, false);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL(""));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
|
||||||
|
ldisc_send(mk->ldisc, "\x0D", -1, true);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D\x0A"));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x0D\x0A"));
|
||||||
|
reset(mk);
|
||||||
|
|
||||||
|
/* In non-LE_CRLF_NEWLINE mode, either of ^M or ^J without the
|
||||||
|
* special flag also sends the line */
|
||||||
|
conf_set_int(mk->conf, CONF_protocol, PROT_SSH);
|
||||||
|
ldisc_configure(mk->ldisc, mk->conf);
|
||||||
|
ldisc_send(mk->ldisc, "abc", 3, false);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL(""));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
|
||||||
|
ldisc_send(mk->ldisc, "\x0D", 1, true);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D"));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x0D\x0A"));
|
||||||
|
reset(mk);
|
||||||
|
ldisc_send(mk->ldisc, "abc", 3, false);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL(""));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
|
||||||
|
ldisc_send(mk->ldisc, "\x0A", 1, true);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D"));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x0D\x0A"));
|
||||||
|
reset(mk);
|
||||||
|
|
||||||
|
/* In LE_CRLF_NEWLINE mode, non-special ^J is just literal */
|
||||||
|
conf_set_int(mk->conf, CONF_protocol, PROT_RAW);
|
||||||
|
ldisc_configure(mk->ldisc, mk->conf);
|
||||||
|
ldisc_send(mk->ldisc, "abc", 3, false);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL(""));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
|
||||||
|
ldisc_send(mk->ldisc, "\x0A", 1, true);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL(""));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc^J"));
|
||||||
|
/* So when we press Return it's sent */
|
||||||
|
ldisc_send(mk->ldisc, "\x0D", -1, true);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0A\x0D\x0A"));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc^J\x0D\x0A"));
|
||||||
|
reset(mk);
|
||||||
|
|
||||||
|
/* In LE_CRLF_NEWLINE mode, non-special ^M is literal, but if
|
||||||
|
* followed with ^J, they combine into a Return */
|
||||||
|
conf_set_int(mk->conf, CONF_protocol, PROT_RAW);
|
||||||
|
ldisc_configure(mk->ldisc, mk->conf);
|
||||||
|
ldisc_send(mk->ldisc, "abc", 3, false);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL(""));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
|
||||||
|
ldisc_send(mk->ldisc, "\x0D", 1, true);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL(""));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc^M"));
|
||||||
|
/* So when we press Return it's sent */
|
||||||
|
ldisc_send(mk->ldisc, "\x0A", 1, true);
|
||||||
|
EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D\x0A"));
|
||||||
|
EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc^M\x08 \x08\x08 \x08\x0D\x0A"));
|
||||||
|
reset(mk);
|
||||||
|
|
||||||
/* ^R redraws the current line, after printing "^R" at the end of
|
/* ^R redraws the current line, after printing "^R" at the end of
|
||||||
* the previous attempt to make it clear that that's what
|
* the previous attempt to make it clear that that's what
|
||||||
* happened */
|
* happened */
|
||||||
|
Loading…
Reference in New Issue
Block a user