Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/windows fixes #32

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 136 additions & 40 deletions linenoise.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,13 +320,67 @@ inline void FlushBuffer(void)
// Adds a character in the buffer.
//-----------------------------------------------------------------------------

inline void PushBuffer(WCHAR c)
inline DWORD PushBuffer(LPCSTR buf, DWORD size)
{
if (shifted && c >= FIRST_G1 && c <= LAST_G1)
c = G1[c - FIRST_G1];
ChBuffer[nCharInBuffer] = c;
if (++nCharInBuffer == BUFFER_SIZE)
FlushBuffer();
if (size < 1)
{
return 0;
}

WCHAR wideChars[2];
int wideCharCount;
if (shifted && *buf >= FIRST_G1 && *buf <= LAST_G1)
{
wideChars[0] = G1[*buf - FIRST_G1];
wideCharCount = 1;
}
else
{
// Find the complete UTF-8 character
unsigned char byte = buf[0];
DWORD utf8Size;

if ((byte & 0x80) == 0)
{
utf8Size = 1;
}
else if ((byte & 0xE0) == 0xC0)
{
utf8Size = 2;
}
else if ((byte & 0xF0) == 0xE0)
{
utf8Size = 3;
}
else if ((byte & 0xF8) == 0xF0)
{
utf8Size = 4;
}
else
{
return 0;
}

if (size < utf8Size)
{
return 0;
}

wideCharCount = MultiByteToWideChar(CP_UTF8, 0, buf, utf8Size, wideChars, 2);
if (wideCharCount == 0)
{
return 0;
}
}

for (int i = 0; i < wideCharCount; ++i)
{
ChBuffer[nCharInBuffer] = wideChars[i];
if (++nCharInBuffer == BUFFER_SIZE)
FlushBuffer();
}

return wideCharCount;
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -369,12 +423,11 @@ inline void SendSequence(LPCWSTR seq)
// suffix = 'm'
//-----------------------------------------------------------------------------

inline void InterpretEscSeq(void)
inline void InterpretEscSeq(PCONSOLE_CURSOR_INFO lpConsoleCursorInfo)
{
int i;
WORD attribute;
CONSOLE_SCREEN_BUFFER_INFO Info;
CONSOLE_CURSOR_INFO CursInfo;
DWORD len, NumberOfCharsWritten;
COORD Pos;
SMALL_RECT Rect;
Expand All @@ -386,9 +439,7 @@ inline void InterpretEscSeq(void)
{
if (es_argc == 1 && es_argv[0] == 25)
{
GetConsoleCursorInfo(hConOut, &CursInfo);
CursInfo.bVisible = (suffix == 'h');
SetConsoleCursorInfo(hConOut, &CursInfo);
lpConsoleCursorInfo->bVisible = (suffix == 'h');
return;
}
}
Expand Down Expand Up @@ -826,14 +877,30 @@ inline BOOL ParseAndPrintANSIString(HANDLE hDev, LPCVOID lpBuffer, DWORD nNumber
state = 1;
shifted = FALSE;
}

CONSOLE_CURSOR_INFO oldConsoleCursorInfo;
GetConsoleCursorInfo(hConOut, & oldConsoleCursorInfo);

CONSOLE_CURSOR_INFO invisibleCursor { .dwSize = oldConsoleCursorInfo.dwSize, .bVisible = 0 };
SetConsoleCursorInfo(hConOut, &invisibleCursor);

for (i = nNumberOfBytesToWrite, s = (LPCSTR)lpBuffer; i > 0; i--, s++)
{
if (state == 1)
{
if (*s == ESC) state = 2;
else if (*s == SO) shifted = TRUE;
else if (*s == SI) shifted = FALSE;
else PushBuffer(*s);
else
{
DWORD written = PushBuffer(s, nNumberOfBytesToWrite);
if (written > 0)
{
DWORD extraWritten = written - 1;
i -= extraWritten;
s += extraWritten;
}
}
}
else if (state == 2)
{
Expand Down Expand Up @@ -873,7 +940,7 @@ inline BOOL ParseAndPrintANSIString(HANDLE hDev, LPCVOID lpBuffer, DWORD nNumber
{
es_argc = 0;
suffix = *s;
InterpretEscSeq();
InterpretEscSeq(&oldConsoleCursorInfo);
state = 1;
}
}
Expand All @@ -894,7 +961,7 @@ inline BOOL ParseAndPrintANSIString(HANDLE hDev, LPCVOID lpBuffer, DWORD nNumber
{
es_argc++;
suffix = *s;
InterpretEscSeq();
InterpretEscSeq(&oldConsoleCursorInfo);
state = 1;
}
}
Expand All @@ -903,13 +970,13 @@ inline BOOL ParseAndPrintANSIString(HANDLE hDev, LPCVOID lpBuffer, DWORD nNumber
if (*s == BEL)
{
Pt_arg[Pt_len] = '\0';
InterpretEscSeq();
InterpretEscSeq(&oldConsoleCursorInfo);
state = 1;
}
else if (*s == '\\' && Pt_len > 0 && Pt_arg[Pt_len - 1] == ESC)
{
Pt_arg[--Pt_len] = '\0';
InterpretEscSeq();
InterpretEscSeq(&oldConsoleCursorInfo);
state = 1;
}
else if (Pt_len < lenof(Pt_arg) - 1)
Expand All @@ -922,6 +989,9 @@ inline BOOL ParseAndPrintANSIString(HANDLE hDev, LPCVOID lpBuffer, DWORD nNumber
}
}
FlushBuffer();

SetConsoleCursorInfo(hConOut, &oldConsoleCursorInfo);

if (lpNumberOfBytesWritten != NULL)
*lpNumberOfBytesWritten = nNumberOfBytesToWrite - i;
return (i == 0);
Expand All @@ -933,61 +1003,61 @@ HANDLE hOut;
HANDLE hIn;
DWORD consolemodeIn = 0;

inline int win32read(int *c) {
inline int win32readW(WCHAR *c) {
DWORD foo;
INPUT_RECORD b;
KEY_EVENT_RECORD e;
BOOL altgr;

while (1) {
if (!ReadConsoleInput(hIn, &b, 1, &foo)) return 0;
if (!ReadConsoleInputW(hIn, &b, 1, &foo)) return 0;
if (!foo) return 0;

if (b.EventType == KEY_EVENT && b.Event.KeyEvent.bKeyDown) {

e = b.Event.KeyEvent;
*c = b.Event.KeyEvent.uChar.AsciiChar;
*c = b.Event.KeyEvent.uChar.UnicodeChar;

altgr = e.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);

if (e.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) && !altgr) {

/* Ctrl+Key */
switch (*c) {
case 'D':
case L'D':
*c = 4;
return 1;
case 'C':
case L'C':
*c = 3;
return 1;
case 'H':
case L'H':
*c = 8;
return 1;
case 'T':
case L'T':
*c = 20;
return 1;
case 'B': /* ctrl-b, left_arrow */
case L'B': /* ctrl-b, left_arrow */
*c = 2;
return 1;
case 'F': /* ctrl-f right_arrow*/
case L'F': /* ctrl-f right_arrow*/
*c = 6;
return 1;
case 'P': /* ctrl-p up_arrow*/
case L'P': /* ctrl-p up_arrow*/
*c = 16;
return 1;
case 'N': /* ctrl-n down_arrow*/
case L'N': /* ctrl-n down_arrow*/
*c = 14;
return 1;
case 'U': /* Ctrl+u, delete the whole line. */
case L'U': /* Ctrl+u, delete the whole line. */
*c = 21;
return 1;
case 'K': /* Ctrl+k, delete from current to end of line. */
case L'K': /* Ctrl+k, delete from current to end of line. */
*c = 11;
return 1;
case 'A': /* Ctrl+a, go to the start of the line */
case L'A': /* Ctrl+a, go to the start of the line */
*c = 1;
return 1;
case 'E': /* ctrl+e, go to the end of the line */
case L'E': /* ctrl+e, go to the end of the line */
*c = 5;
return 1;
}
Expand Down Expand Up @@ -1037,6 +1107,38 @@ inline int win32read(int *c) {
return -1; /* Makes compiler happy */
}

inline int win32read(char *buf, int *c)
{
WCHAR wideChars[2];
int wideCharCount;
if (win32readW(wideChars) != 1)
{
return 0;
}

// check for high surrogate
if (!IS_HIGH_SURROGATE(wideChars[0]))
{
*c = wideChars[0];
wideCharCount = 1;
}
else
{
if (win32readW(wideChars + 1) != 1)
{
return 0;
}

// combine the surrogates
*c = 0x10000 + (((wideChars[0] & 0x3ff) << 10) | (wideChars[1] & 0x3ff));
wideCharCount = 2;
}

auto count = WideCharToMultiByte(CP_UTF8, 0, wideChars, wideCharCount, buf, 4, nullptr, nullptr);

return count;
}

inline int win32_write(int fd, const void *buffer, unsigned int count) {
if (fd == _fileno(stdout)) {
DWORD bytesWritten = 0;
Expand Down Expand Up @@ -1706,7 +1808,7 @@ inline int getColumns(int ifd, int ofd) {
CONSOLE_SCREEN_BUFFER_INFO b;

if (!GetConsoleScreenBufferInfo(hOut, &b)) return 80;
return b.srWindow.Right - b.srWindow.Left;
return (b.srWindow.Right - b.srWindow.Left) + 1;
#else
struct winsize ws;

Expand Down Expand Up @@ -1791,10 +1893,7 @@ inline int completeLine(struct linenoiseState *ls, char *cbuf, int *c) {

//nread = read(ls->ifd,&c,1);
#ifdef _WIN32
nread = win32read(c);
if (nread == 1) {
cbuf[0] = *c;
}
nread = win32read(cbuf, c);
#else
nread = unicodeReadUTF8Char(ls->ifd,cbuf,c);
#endif
Expand Down Expand Up @@ -2128,10 +2227,7 @@ inline int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, int buflen, con
char seq[3];

#ifdef _WIN32
nread = win32read(&c);
if (nread == 1) {
cbuf[0] = c;
}
nread = win32read(cbuf, &c);
#else
nread = unicodeReadUTF8Char(l.ifd,cbuf,&c);
#endif
Expand Down