]> git.lizzy.rs Git - linenoise.git/blob - linenoise-win32.c
Use CMake
[linenoise.git] / linenoise-win32.c
1
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;
10
11 static int flushOutput(struct current *current);
12 static void outputNewline(struct current *current);
13
14 static void refreshStart(struct current *current)
15 {
16 }
17
18 static void refreshEnd(struct current *current)
19 {
20 }
21
22 static void refreshStartChars(struct current *current)
23 {
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
30 }
31
32 static void refreshNewline(struct current *current)
33 {
34     DRL("<nl>");
35     outputNewline(current);
36 }
37
38 static void refreshEndChars(struct current *current)
39 {
40     assert(current->output);
41     flushOutput(current);
42     sb_free(current->output);
43     current->output = NULL;
44 }
45
46 static int enableRawMode(struct current *current) {
47     DWORD n;
48     INPUT_RECORD irec;
49
50     current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
51     current->inh = GetStdHandle(STD_INPUT_HANDLE);
52
53     if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
54         return -1;
55     }
56     if (getWindowSize(current) != 0) {
57         return -1;
58     }
59     if (GetConsoleMode(current->inh, &orig_consolemode)) {
60         SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
61     }
62 #ifdef USE_UTF8
63     /* XXX is this the right thing to do? */
64     SetConsoleCP(65001);
65 #endif
66     return 0;
67 }
68
69 static void disableRawMode(struct current *current)
70 {
71     SetConsoleMode(current->inh, orig_consolemode);
72 }
73
74 void linenoiseClearScreen(void)
75 {
76     /* XXX: This is ugly. Should just have the caller pass a handle */
77     struct current current;
78
79     current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
80
81     if (getWindowSize(&current) == 0) {
82         COORD topleft = { 0, 0 };
83         DWORD n;
84
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);
91     }
92 }
93
94 static void cursorToLeft(struct current *current)
95 {
96     COORD pos;
97     DWORD n;
98
99     pos.X = 0;
100     pos.Y = (SHORT)current->y;
101
102     FillConsoleOutputAttribute(current->outh,
103         FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
104     current->x = 0;
105 }
106
107 #ifdef USE_UTF8
108 static void flush_ubuf(struct current *current)
109 {
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;
119 }
120
121 static void add_ubuf(struct current *current, int ch)
122 {
123     /* This code originally by: Author: Mark E. Davis, 1994. */
124     static const int halfShift  = 10; /* used for shifting by 10 bits */
125
126     static const DWORD halfBase = 0x0010000UL;
127     static const DWORD halfMask = 0x3FFUL;
128
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
133
134     #define UNI_MAX_BMP 0x0000FFFF
135
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
139          */
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);
143     }
144     else {
145         current->ubuf[current->ubuflen++] = ch;
146     }
147     current->ubufcols += utf8_width(ch);
148     if (current->ubuflen >= UBUF_MAX_CHARS) {
149         flush_ubuf(current);
150     }
151 }
152 #endif
153
154 static int flushOutput(struct current *current)
155 {
156     const char *pt = sb_str(current->output);
157     int len = sb_len(current->output);
158
159 #ifdef USE_UTF8
160     /* convert utf8 in current->output into utf16 in current->ubuf
161      */
162     while (len) {
163         int ch;
164         int n = utf8_tounicode(pt, &ch);
165
166         pt += n;
167         len -= n;
168
169         add_ubuf(current, ch);
170     }
171     flush_ubuf(current);
172 #else
173     DWORD nwritten;
174     COORD pos;
175
176     pos.Y = (SHORT)current->y;
177     pos.X = (SHORT)current->x;
178
179     SetConsoleCursorPosition(current->outh, pos);
180     WriteConsoleA(current->outh, pt, len, &nwritten, 0);
181
182     current->x += len;
183 #endif
184
185     sb_clear(current->output);
186
187     return 0;
188 }
189
190 static int outputChars(struct current *current, const char *buf, int len)
191 {
192     if (len < 0) {
193         len = strlen(buf);
194     }
195     assert(current->output);
196
197     sb_append_len(current->output, buf, len);
198
199     return 0;
200 }
201
202 static void outputNewline(struct current *current)
203 {
204     /* On the last row output a newline to force a scroll */
205     if (current->y + 1 == current->rows) {
206         outputChars(current, "\n", 1);
207     }
208     flushOutput(current);
209     current->x = 0;
210     current->y++;
211 }
212
213 static void setOutputHighlight(struct current *current, const int *props, int nprops)
214 {
215     int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
216     int bold = 0;
217     int reverse = 0;
218     int i;
219
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;
257         }
258     }
259
260     flushOutput(current);
261
262     if (reverse) {
263         SetConsoleTextAttribute(current->outh, BACKGROUND_INTENSITY);
264     }
265     else {
266         SetConsoleTextAttribute(current->outh, colour | bold);
267     }
268 }
269
270 static void eraseEol(struct current *current)
271 {
272     COORD pos;
273     DWORD n;
274
275     pos.X = (SHORT) current->x;
276     pos.Y = (SHORT) current->y;
277
278     FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
279 }
280
281 static void setCursorXY(struct current *current)
282 {
283     COORD pos;
284
285     pos.X = (SHORT) current->x;
286     pos.Y = (SHORT) current->y;
287
288     SetConsoleCursorPosition(current->outh, pos);
289 }
290
291
292 static void setCursorPos(struct current *current, int x)
293 {
294     current->x = x;
295     setCursorXY(current);
296 }
297
298 static void cursorUp(struct current *current, int n)
299 {
300     current->y -= n;
301     setCursorXY(current);
302 }
303
304 static void cursorDown(struct current *current, int n)
305 {
306     current->y += n;
307     setCursorXY(current);
308 }
309
310 static int fd_read(struct current *current)
311 {
312     while (1) {
313         INPUT_RECORD irec;
314         DWORD n;
315         if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
316             break;
317         }
318         if (!ReadConsoleInputW(current->inh, &irec, 1, &n)) {
319             break;
320         }
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;
346                     }
347                 }
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;
353                 }
354             }
355         }
356     }
357     return -1;
358 }
359
360 static int getWindowSize(struct current *current)
361 {
362     CONSOLE_SCREEN_BUFFER_INFO info;
363     if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
364         return -1;
365     }
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;
371     }
372     current->y = info.dwCursorPosition.Y;
373     current->x = info.dwCursorPosition.X;
374     return 0;
375 }