apply: ignore the current namespace
[jimtcl.git] / linenoise-win32.c
blobdd15b949c69ac18a9cc9af9a6518aa1602e050f8
2 /* this code is not standalone
3 * it is included into linenoise.c
4 * for windows.
5 * It is deliberately kept separate so that
6 * applications that have no need for windows
7 * support can omit this
8 */
9 static DWORD orig_consolemode = 0;
11 static int flushOutput(struct current *current);
12 static void outputNewline(struct current *current);
14 static void refreshStart(struct current *current)
18 static void refreshEnd(struct current *current)
22 static void refreshStartChars(struct current *current)
24 assert(current->output == NULL);
25 /* We accumulate all output here */
26 current->output = sb_alloc();
27 #ifdef USE_UTF8
28 current->ubuflen = 0;
29 #endif
32 static void refreshNewline(struct current *current)
34 DRL("<nl>");
35 outputNewline(current);
38 static void refreshEndChars(struct current *current)
40 assert(current->output);
41 flushOutput(current);
42 sb_free(current->output);
43 current->output = NULL;
46 static int enableRawMode(struct current *current) {
47 DWORD n;
48 INPUT_RECORD irec;
50 current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
51 current->inh = GetStdHandle(STD_INPUT_HANDLE);
53 if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
54 return -1;
56 if (getWindowSize(current) != 0) {
57 return -1;
59 if (GetConsoleMode(current->inh, &orig_consolemode)) {
60 SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
62 #ifdef USE_UTF8
63 /* XXX is this the right thing to do? */
64 SetConsoleCP(65001);
65 #endif
66 return 0;
69 static void disableRawMode(struct current *current)
71 SetConsoleMode(current->inh, orig_consolemode);
74 void linenoiseClearScreen(void)
76 /* XXX: This is ugly. Should just have the caller pass a handle */
77 struct current current;
79 current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
81 if (getWindowSize(&current) == 0) {
82 COORD topleft = { 0, 0 };
83 DWORD n;
85 FillConsoleOutputCharacter(current.outh, ' ',
86 current.cols * current.rows, topleft, &n);
87 FillConsoleOutputAttribute(current.outh,
88 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
89 current.cols * current.rows, topleft, &n);
90 SetConsoleCursorPosition(current.outh, topleft);
94 static void cursorToLeft(struct current *current)
96 COORD pos;
97 DWORD n;
99 pos.X = 0;
100 pos.Y = (SHORT)current->y;
102 FillConsoleOutputAttribute(current->outh,
103 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
104 current->x = 0;
107 #ifdef USE_UTF8
108 static void flush_ubuf(struct current *current)
110 COORD pos;
111 DWORD nwritten;
112 pos.Y = (SHORT)current->y;
113 pos.X = (SHORT)current->x;
114 SetConsoleCursorPosition(current->outh, pos);
115 WriteConsoleW(current->outh, current->ubuf, current->ubuflen, &nwritten, 0);
116 current->x += current->ubufcols;
117 current->ubuflen = 0;
118 current->ubufcols = 0;
121 static void add_ubuf(struct current *current, int ch)
123 /* This code originally by: Author: Mark E. Davis, 1994. */
124 static const int halfShift = 10; /* used for shifting by 10 bits */
126 static const DWORD halfBase = 0x0010000UL;
127 static const DWORD halfMask = 0x3FFUL;
129 #define UNI_SUR_HIGH_START 0xD800
130 #define UNI_SUR_HIGH_END 0xDBFF
131 #define UNI_SUR_LOW_START 0xDC00
132 #define UNI_SUR_LOW_END 0xDFFF
134 #define UNI_MAX_BMP 0x0000FFFF
136 if (ch > UNI_MAX_BMP) {
137 /* convert from unicode to utf16 surrogate pairs
138 * There is always space for one extra word in ubuf
140 ch -= halfBase;
141 current->ubuf[current->ubuflen++] = (WORD)((ch >> halfShift) + UNI_SUR_HIGH_START);
142 current->ubuf[current->ubuflen++] = (WORD)((ch & halfMask) + UNI_SUR_LOW_START);
144 else {
145 current->ubuf[current->ubuflen++] = ch;
147 current->ubufcols += utf8_width(ch);
148 if (current->ubuflen >= UBUF_MAX_CHARS) {
149 flush_ubuf(current);
152 #endif
154 static int flushOutput(struct current *current)
156 const char *pt = sb_str(current->output);
157 int len = sb_len(current->output);
159 #ifdef USE_UTF8
160 /* convert utf8 in current->output into utf16 in current->ubuf
162 while (len) {
163 int ch;
164 int n = utf8_tounicode(pt, &ch);
166 pt += n;
167 len -= n;
169 add_ubuf(current, ch);
171 flush_ubuf(current);
172 #else
173 DWORD nwritten;
174 COORD pos;
176 pos.Y = (SHORT)current->y;
177 pos.X = (SHORT)current->x;
179 SetConsoleCursorPosition(current->outh, pos);
180 WriteConsoleA(current->outh, pt, len, &nwritten, 0);
182 current->x += len;
183 #endif
185 sb_clear(current->output);
187 return 0;
190 static int outputChars(struct current *current, const char *buf, int len)
192 if (len < 0) {
193 len = strlen(buf);
195 assert(current->output);
197 sb_append_len(current->output, buf, len);
199 return 0;
202 static void outputNewline(struct current *current)
204 /* On the last row output a newline to force a scroll */
205 if (current->y + 1 == current->rows) {
206 outputChars(current, "\n", 1);
208 flushOutput(current);
209 current->x = 0;
210 current->y++;
213 static void setOutputHighlight(struct current *current, const int *props, int nprops)
215 int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
216 int bold = 0;
217 int reverse = 0;
218 int i;
220 for (i = 0; i < nprops; i++) {
221 switch (props[i]) {
222 case 0:
223 colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
224 bold = 0;
225 reverse = 0;
226 break;
227 case 1:
228 bold = FOREGROUND_INTENSITY;
229 break;
230 case 7:
231 reverse = 1;
232 break;
233 case 30:
234 colour = 0;
235 break;
236 case 31:
237 colour = FOREGROUND_RED;
238 break;
239 case 32:
240 colour = FOREGROUND_GREEN;
241 break;
242 case 33:
243 colour = FOREGROUND_RED | FOREGROUND_GREEN;
244 break;
245 case 34:
246 colour = FOREGROUND_BLUE;
247 break;
248 case 35:
249 colour = FOREGROUND_RED | FOREGROUND_BLUE;
250 break;
251 case 36:
252 colour = FOREGROUND_BLUE | FOREGROUND_GREEN;
253 break;
254 case 37:
255 colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
256 break;
260 flushOutput(current);
262 if (reverse) {
263 SetConsoleTextAttribute(current->outh, BACKGROUND_INTENSITY);
265 else {
266 SetConsoleTextAttribute(current->outh, colour | bold);
270 static void eraseEol(struct current *current)
272 COORD pos;
273 DWORD n;
275 pos.X = (SHORT) current->x;
276 pos.Y = (SHORT) current->y;
278 FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
281 static void setCursorXY(struct current *current)
283 COORD pos;
285 pos.X = (SHORT) current->x;
286 pos.Y = (SHORT) current->y;
288 SetConsoleCursorPosition(current->outh, pos);
292 static void setCursorPos(struct current *current, int x)
294 current->x = x;
295 setCursorXY(current);
298 static void cursorUp(struct current *current, int n)
300 current->y -= n;
301 setCursorXY(current);
304 static void cursorDown(struct current *current, int n)
306 current->y += n;
307 setCursorXY(current);
310 static int fd_read(struct current *current)
312 while (1) {
313 INPUT_RECORD irec;
314 DWORD n;
315 if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
316 break;
318 if (!ReadConsoleInputW(current->inh, &irec, 1, &n)) {
319 break;
321 if (irec.EventType == KEY_EVENT) {
322 KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
323 if (k->bKeyDown || k->wVirtualKeyCode == VK_MENU) {
324 if (k->dwControlKeyState & ENHANCED_KEY) {
325 switch (k->wVirtualKeyCode) {
326 case VK_LEFT:
327 return SPECIAL_LEFT;
328 case VK_RIGHT:
329 return SPECIAL_RIGHT;
330 case VK_UP:
331 return SPECIAL_UP;
332 case VK_DOWN:
333 return SPECIAL_DOWN;
334 case VK_INSERT:
335 return SPECIAL_INSERT;
336 case VK_DELETE:
337 return SPECIAL_DELETE;
338 case VK_HOME:
339 return SPECIAL_HOME;
340 case VK_END:
341 return SPECIAL_END;
342 case VK_PRIOR:
343 return SPECIAL_PAGE_UP;
344 case VK_NEXT:
345 return SPECIAL_PAGE_DOWN;
348 /* Note that control characters are already translated in AsciiChar */
349 else if (k->wVirtualKeyCode == VK_CONTROL)
350 continue;
351 else {
352 return k->uChar.UnicodeChar;
357 return -1;
360 static int getWindowSize(struct current *current)
362 CONSOLE_SCREEN_BUFFER_INFO info;
363 if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
364 return -1;
366 current->cols = info.dwSize.X;
367 current->rows = info.dwSize.Y;
368 if (current->cols <= 0 || current->rows <= 0) {
369 current->cols = 80;
370 return -1;
372 current->y = info.dwCursorPosition.Y;
373 current->x = info.dwCursorPosition.X;
374 return 0;