Skip to content

Commit 9a1a069

Browse files
feat: implement cursor position check for terminal input handling (#1542)
1 parent 2a90a11 commit 9a1a069

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

modules/terminal/src/cpp/replxx/src/terminal.cxx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,70 @@ Terminal::jump_cursor(int xPos_, int yOffset_)
891891
#endif
892892
}
893893

894+
#if defined(_WIN32)
895+
bool
896+
Terminal::is_at_beginning_of_the_line(void)
897+
{
898+
CONSOLE_SCREEN_BUFFER_INFO inf;
899+
HANDLE consoleOut(
900+
_consoleOut != INVALID_HANDLE_VALUE ? _consoleOut : GetStdHandle(STD_OUTPUT_HANDLE));
901+
if (!GetConsoleScreenBufferInfo(consoleOut, &inf)) {
902+
return false;
903+
}
904+
return (inf.dwCursorPosition.X == 0);
905+
}
906+
#else
907+
bool
908+
Terminal::is_at_beginning_of_the_line(void)
909+
{
910+
// Request cursor position report (DSR) and parse response: ESC [ row ; col R
911+
const char request[] = "\033[6n";
912+
write8(request, sizeof(request) - 1);
913+
914+
fd_set rfds;
915+
struct timeval tv;
916+
tv.tv_sec = 0;
917+
tv.tv_usec = 200000; // 200 ms
918+
919+
std::string resp;
920+
int fd = _in_fd;
921+
char buf[32];
922+
923+
while (true) {
924+
FD_ZERO(&rfds);
925+
FD_SET(fd, &rfds);
926+
int ret = select(fd + 1, &rfds, nullptr, nullptr, &tv);
927+
if (ret <= 0) {
928+
break; // timeout or error
929+
}
930+
ssize_t n = read(fd, buf, sizeof(buf));
931+
if (n <= 0) {
932+
break;
933+
}
934+
resp.append(buf, buf + n);
935+
if (resp.find('R') != std::string::npos) {
936+
break;
937+
}
938+
// small additional delay for more data
939+
tv.tv_sec = 0;
940+
tv.tv_usec = 50000; // 50ms
941+
}
942+
943+
size_t p1 = resp.find('[');
944+
size_t p2 = resp.find('R');
945+
if (p1 == std::string::npos || p2 == std::string::npos || p2 <= p1) {
946+
return false;
947+
}
948+
std::string inside = resp.substr(p1 + 1, p2 - p1 - 1);
949+
size_t sep = inside.find(';');
950+
if (sep == std::string::npos) {
951+
return false;
952+
}
953+
int col = atoi(inside.c_str() + sep + 1);
954+
return (col == 1); // DSR is 1-based
955+
}
956+
#endif
957+
894958
#ifdef _WIN32
895959
void
896960
Terminal::set_cursor_visible(bool visible_)

0 commit comments

Comments
 (0)