Skip to content

Commit 2a90a11

Browse files
feat: implement cursor position check for terminal input handling
1 parent 7651282 commit 2a90a11

File tree

4 files changed

+82
-46
lines changed

4 files changed

+82
-46
lines changed

modules/terminal/src/cpp/AdvancedTerminal.cpp

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -191,38 +191,6 @@ injectNewlineIntoInput()
191191
#endif
192192
}
193193
//=============================================================================
194-
static void
195-
writeStdoutUtf8(const std::string& msg)
196-
{
197-
#ifdef _WIN32
198-
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
199-
if (handle != nullptr && handle != INVALID_HANDLE_VALUE) {
200-
std::wstring wide = utf8_to_wstring(msg);
201-
DWORD written = 0;
202-
WriteConsoleW(handle, wide.c_str(), static_cast<DWORD>(wide.size()), &written, nullptr);
203-
return;
204-
}
205-
#endif
206-
std::cout << msg;
207-
std::cout.flush();
208-
}
209-
//=============================================================================
210-
static void
211-
writeStderrUtf8(const std::string& msg)
212-
{
213-
#ifdef _WIN32
214-
HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
215-
if (handle != nullptr && handle != INVALID_HANDLE_VALUE) {
216-
std::wstring wide = utf8_to_wstring(msg);
217-
DWORD written = 0;
218-
WriteConsoleW(handle, wide.c_str(), static_cast<DWORD>(wide.size()), &written, nullptr);
219-
return;
220-
}
221-
#endif
222-
std::cerr << msg;
223-
std::cerr.flush();
224-
}
225-
//=============================================================================
226194
} // namespace
227195
//=============================================================================
228196
std::wstring
@@ -239,7 +207,6 @@ AdvancedTerminal::getTextLine(const std::wstring& prompt, bool bIsInput)
239207
atPrompt = false;
240208
return L"\n";
241209
}
242-
243210
const char* line = repl->input(promptUtf8);
244211
if (line == nullptr || line[0] == 0) {
245212
atPrompt = false;
@@ -305,19 +272,19 @@ AdvancedTerminal::getTerminalHeight()
305272
void
306273
AdvancedTerminal::outputMessage(const std::wstring& msg)
307274
{
308-
std::string _msg = wstring_to_utf8(msg);
309-
if (atPrompt) {
310-
writeStdoutUtf8("\n");
311-
atPrompt = false;
312-
}
313-
314-
outputMessage(_msg);
275+
outputMessage(wstring_to_utf8(msg));
315276
}
316277
//=============================================================================
317278
void
318279
AdvancedTerminal::outputMessage(const std::string& msg)
319280
{
320-
writeStdoutUtf8(msg);
281+
if (atPrompt) {
282+
std::cout << "\n";
283+
284+
atPrompt = false;
285+
}
286+
std::cout << msg;
287+
std::cout.flush();
321288
this->diary.writeMessage(msg);
322289
}
323290
//=============================================================================
@@ -331,10 +298,11 @@ void
331298
AdvancedTerminal::errorMessage(const std::string& msg)
332299
{
333300
if (atPrompt) {
334-
writeStdoutUtf8("\n");
301+
std::cout << "\n";
335302
atPrompt = false;
336303
}
337-
writeStderrUtf8(msg);
304+
std::cerr << msg;
305+
std::cerr.flush();
338306
this->diary.writeMessage(msg);
339307
}
340308
//=============================================================================
@@ -348,11 +316,11 @@ void
348316
AdvancedTerminal::warningMessage(const std::string& msg)
349317
{
350318
if (atPrompt) {
351-
writeStdoutUtf8("\n");
319+
std::cout << "\n";
352320
atPrompt = false;
353321
}
354-
writeStdoutUtf8(msg);
355-
this->diary.writeMessage(msg);
322+
std::cout << msg;
323+
std::cout.flush();
356324
}
357325
//=============================================================================
358326
void

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,9 @@ Replxx::ReplxxImpl::input(std::string const& prompt)
856856

857857
/// Always render from beginning of current line. It's to prevent garbage inputs during
858858
/// starting up.
859+
if (!_terminal.is_at_beginning_of_the_line()) {
860+
dprintf(_out_fd, "\n");
861+
}
859862
_terminal.jump_cursor(0, 0);
860863
_asyncPrompt.clear();
861864
_updatePrompt = false;

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

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

modules/terminal/src/cpp/replxx/src/terminal.hxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ public:
8989
jump_cursor(int, int);
9090
void
9191
set_cursor_visible(bool);
92+
bool
93+
is_at_beginning_of_the_line(void);
9294
#ifndef _WIN32
9395
int
9496
read_verbatim(char32_t*, int);

0 commit comments

Comments
 (0)