mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:37:46 +00:00
LibLine: Make the DSR response parser a bit more robust
At the cost of using more read() syscalls, process the DSR response character-by-character. This avoids blocking forever waiting for an 'R' that will never come :P
This commit is contained in:
parent
fe97aec8c3
commit
80d21f120f
1 changed files with 90 additions and 19 deletions
|
@ -1678,7 +1678,6 @@ Editor::VTState Editor::actual_rendered_string_length_step(StringMetrics& metric
|
||||||
Vector<size_t, 2> Editor::vt_dsr()
|
Vector<size_t, 2> Editor::vt_dsr()
|
||||||
{
|
{
|
||||||
char buf[16];
|
char buf[16];
|
||||||
u32 length { 0 };
|
|
||||||
|
|
||||||
// Read whatever junk there is before talking to the terminal
|
// Read whatever junk there is before talking to the terminal
|
||||||
// and insert them later when we're reading user input.
|
// and insert them later when we're reading user input.
|
||||||
|
@ -1713,8 +1712,25 @@ Vector<size_t, 2> Editor::vt_dsr()
|
||||||
fputs("\033[6n", stderr);
|
fputs("\033[6n", stderr);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
|
// Parse the DSR response
|
||||||
|
// it should be of the form .*\e[\d+;\d+R.*
|
||||||
|
// Anything not part of the response is just added to the incomplete data.
|
||||||
|
enum {
|
||||||
|
Free,
|
||||||
|
SawEsc,
|
||||||
|
SawBracket,
|
||||||
|
InFirstCoordinate,
|
||||||
|
SawSemicolon,
|
||||||
|
InSecondCoordinate,
|
||||||
|
SawR,
|
||||||
|
} state { Free };
|
||||||
|
auto has_error = false;
|
||||||
|
Vector<char, 4> coordinate_buffer;
|
||||||
|
size_t row { 1 }, col { 1 };
|
||||||
|
|
||||||
do {
|
do {
|
||||||
auto nread = read(0, buf + length, 16 - length);
|
char c;
|
||||||
|
auto nread = read(0, &c, 1);
|
||||||
if (nread < 0) {
|
if (nread < 0) {
|
||||||
if (errno == 0 || errno == EINTR) {
|
if (errno == 0 || errno == EINTR) {
|
||||||
// ????
|
// ????
|
||||||
|
@ -1731,25 +1747,80 @@ Vector<size_t, 2> Editor::vt_dsr()
|
||||||
dbgln("Terminal DSR issue; received no response");
|
dbgln("Terminal DSR issue; received no response");
|
||||||
return { 1, 1 };
|
return { 1, 1 };
|
||||||
}
|
}
|
||||||
length += nread;
|
|
||||||
} while (buf[length - 1] != 'R' && length < 16);
|
|
||||||
size_t row { 1 }, col { 1 };
|
|
||||||
|
|
||||||
if (buf[0] == '\033' && buf[1] == '[') {
|
switch (state) {
|
||||||
auto parts = StringView(buf + 2, length - 3).split_view(';');
|
case Free:
|
||||||
auto row_opt = parts[0].to_int();
|
if (c == '\x1b') {
|
||||||
if (!row_opt.has_value()) {
|
state = SawEsc;
|
||||||
dbgln("Terminal DSR issue; received garbage row");
|
continue;
|
||||||
} else {
|
}
|
||||||
row = row_opt.value();
|
m_incomplete_data.append(c);
|
||||||
|
continue;
|
||||||
|
case SawEsc:
|
||||||
|
if (c == '[') {
|
||||||
|
state = SawBracket;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_incomplete_data.append(c);
|
||||||
|
continue;
|
||||||
|
case SawBracket:
|
||||||
|
if (isdigit(c)) {
|
||||||
|
state = InFirstCoordinate;
|
||||||
|
coordinate_buffer.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_incomplete_data.append(c);
|
||||||
|
continue;
|
||||||
|
case InFirstCoordinate:
|
||||||
|
if (isdigit(c)) {
|
||||||
|
coordinate_buffer.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == ';') {
|
||||||
|
auto maybe_row = StringView { coordinate_buffer.data(), coordinate_buffer.size() }.to_uint();
|
||||||
|
if (!maybe_row.has_value())
|
||||||
|
has_error = true;
|
||||||
|
row = maybe_row.value_or(1u);
|
||||||
|
coordinate_buffer.clear_with_capacity();
|
||||||
|
state = SawSemicolon;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_incomplete_data.append(c);
|
||||||
|
continue;
|
||||||
|
case SawSemicolon:
|
||||||
|
if (isdigit(c)) {
|
||||||
|
state = InSecondCoordinate;
|
||||||
|
coordinate_buffer.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_incomplete_data.append(c);
|
||||||
|
continue;
|
||||||
|
case InSecondCoordinate:
|
||||||
|
if (isdigit(c)) {
|
||||||
|
coordinate_buffer.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == 'R') {
|
||||||
|
auto maybe_column = StringView { coordinate_buffer.data(), coordinate_buffer.size() }.to_uint();
|
||||||
|
if (!maybe_column.has_value())
|
||||||
|
has_error = true;
|
||||||
|
col = maybe_column.value_or(1u);
|
||||||
|
coordinate_buffer.clear_with_capacity();
|
||||||
|
state = SawR;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_incomplete_data.append(c);
|
||||||
|
continue;
|
||||||
|
case SawR:
|
||||||
|
m_incomplete_data.append(c);
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
auto col_opt = parts[1].to_int();
|
} while (state != SawR);
|
||||||
if (!col_opt.has_value()) {
|
|
||||||
dbgln("Terminal DSR issue; received garbage col");
|
if (has_error)
|
||||||
} else {
|
dbgln("Terminal DSR issue, couldn't parse DSR response");
|
||||||
col = col_opt.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { row, col };
|
return { row, col };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue