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
+ (void )current ;
17
+ }
18
+
19
+ static void refreshEnd (struct current * current )
20
+ {
21
+ (void )current ;
22
+ }
23
+
24
+ static void refreshStartChars (struct current * current )
25
+ {
26
+ assert (current -> output == NULL );
27
+ /* We accumulate all output here */
28
+ current -> output = sb_alloc ();
29
+ #ifdef USE_UTF8
30
+ current -> ubuflen = 0 ;
31
+ #endif
32
+ }
33
+
34
+ static void refreshNewline (struct current * current )
35
+ {
36
+ DRL ("<nl>" );
37
+ outputNewline (current );
38
+ }
39
+
40
+ static void refreshEndChars (struct current * current )
41
+ {
42
+ assert (current -> output );
43
+ flushOutput (current );
44
+ sb_free (current -> output );
45
+ current -> output = NULL ;
46
+ }
47
+
48
+ static int enableRawMode (struct current * current ) {
49
+ DWORD n ;
50
+ INPUT_RECORD irec ;
51
+
52
+ current -> outh = GetStdHandle (STD_OUTPUT_HANDLE );
53
+ current -> inh = GetStdHandle (STD_INPUT_HANDLE );
54
+
55
+ if (!PeekConsoleInput (current -> inh , & irec , 1 , & n )) {
56
+ return -1 ;
57
+ }
58
+ if (getWindowSize (current ) != 0 ) {
59
+ return -1 ;
60
+ }
61
+ if (GetConsoleMode (current -> inh , & orig_consolemode )) {
62
+ SetConsoleMode (current -> inh , ENABLE_PROCESSED_INPUT );
63
+ }
64
+ #ifdef USE_UTF8
65
+ /* XXX is this the right thing to do? */
66
+ SetConsoleCP (65001 );
67
+ #endif
68
+ return 0 ;
69
+ }
70
+
71
+ static void disableRawMode (struct current * current )
72
+ {
73
+ SetConsoleMode (current -> inh , orig_consolemode );
74
+ }
75
+
76
+ void linenoiseClearScreen (void )
77
+ {
78
+ /* XXX: This is ugly. Should just have the caller pass a handle */
79
+ struct current current ;
80
+
81
+ current .outh = GetStdHandle (STD_OUTPUT_HANDLE );
82
+
83
+ if (getWindowSize (& current ) == 0 ) {
84
+ COORD topleft = { 0 , 0 };
85
+ DWORD n ;
86
+
87
+ FillConsoleOutputCharacter (current .outh , ' ' ,
88
+ current .cols * current .rows , topleft , & n );
89
+ FillConsoleOutputAttribute (current .outh ,
90
+ FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN ,
91
+ current .cols * current .rows , topleft , & n );
92
+ SetConsoleCursorPosition (current .outh , topleft );
93
+ }
94
+ }
95
+
96
+ static void cursorToLeft (struct current * current )
97
+ {
98
+ COORD pos ;
99
+ DWORD n ;
100
+
101
+ pos .X = 0 ;
102
+ pos .Y = (SHORT )current -> y ;
103
+
104
+ FillConsoleOutputAttribute (current -> outh ,
105
+ FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN , current -> cols , pos , & n );
106
+ current -> x = 0 ;
107
+ }
108
+
109
+ #ifdef USE_UTF8
110
+ static void flush_ubuf (struct current * current )
111
+ {
112
+ COORD pos ;
113
+ DWORD nwritten ;
114
+ pos .Y = (SHORT )current -> y ;
115
+ pos .X = (SHORT )current -> x ;
116
+ SetConsoleCursorPosition (current -> outh , pos );
117
+ WriteConsoleW (current -> outh , current -> ubuf , current -> ubuflen , & nwritten , 0 );
118
+ current -> x += current -> ubufcols ;
119
+ current -> ubuflen = 0 ;
120
+ current -> ubufcols = 0 ;
121
+ }
122
+
123
+ static void add_ubuf (struct current * current , int ch )
124
+ {
125
+ /* This code originally by: Author: Mark E. Davis, 1994. */
126
+ static const int halfShift = 10 ; /* used for shifting by 10 bits */
127
+
128
+ static const DWORD halfBase = 0x0010000UL ;
129
+ static const DWORD halfMask = 0x3FFUL ;
130
+
131
+ #define UNI_SUR_HIGH_START 0xD800
132
+ #define UNI_SUR_HIGH_END 0xDBFF
133
+ #define UNI_SUR_LOW_START 0xDC00
134
+ #define UNI_SUR_LOW_END 0xDFFF
135
+
136
+ #define UNI_MAX_BMP 0x0000FFFF
137
+
138
+ if (ch > UNI_MAX_BMP ) {
139
+ /* convert from unicode to utf16 surrogate pairs
140
+ * There is always space for one extra word in ubuf
141
+ */
142
+ ch -= halfBase ;
143
+ current -> ubuf [current -> ubuflen ++ ] = (WORD )((ch >> halfShift ) + UNI_SUR_HIGH_START );
144
+ current -> ubuf [current -> ubuflen ++ ] = (WORD )((ch & halfMask ) + UNI_SUR_LOW_START );
145
+ }
146
+ else {
147
+ current -> ubuf [current -> ubuflen ++ ] = ch ;
148
+ }
149
+ current -> ubufcols += utf8_width (ch );
150
+ if (current -> ubuflen >= UBUF_MAX_CHARS ) {
151
+ flush_ubuf (current );
152
+ }
153
+ }
154
+ #endif
155
+
156
+ static int flushOutput (struct current * current )
157
+ {
158
+ const char * pt = sb_str (current -> output );
159
+ int len = sb_len (current -> output );
160
+
161
+ #ifdef USE_UTF8
162
+ /* convert utf8 in current->output into utf16 in current->ubuf
163
+ */
164
+ while (len ) {
165
+ int ch ;
166
+ int n = utf8_tounicode (pt , & ch );
167
+
168
+ pt += n ;
169
+ len -= n ;
170
+
171
+ add_ubuf (current , ch );
172
+ }
173
+ flush_ubuf (current );
174
+ #else
175
+ DWORD nwritten ;
176
+ COORD pos ;
177
+
178
+ pos .Y = (SHORT )current -> y ;
179
+ pos .X = (SHORT )current -> x ;
180
+
181
+ SetConsoleCursorPosition (current -> outh , pos );
182
+ WriteConsoleA (current -> outh , pt , len , & nwritten , 0 );
183
+
184
+ current -> x += len ;
185
+ #endif
186
+
187
+ sb_clear (current -> output );
188
+
189
+ return 0 ;
190
+ }
191
+
192
+ static int outputChars (struct current * current , const char * buf , int len )
193
+ {
194
+ if (len < 0 ) {
195
+ len = strlen (buf );
196
+ }
197
+ assert (current -> output );
198
+
199
+ sb_append_len (current -> output , buf , len );
200
+
201
+ return 0 ;
202
+ }
203
+
204
+ static void outputNewline (struct current * current )
205
+ {
206
+ /* On the last row output a newline to force a scroll */
207
+ if (current -> y + 1 == current -> rows ) {
208
+ outputChars (current , "\n" , 1 );
209
+ }
210
+ flushOutput (current );
211
+ current -> x = 0 ;
212
+ current -> y ++ ;
213
+ }
214
+
215
+ static void setOutputHighlight (struct current * current , const int * props , int nprops )
216
+ {
217
+ int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN ;
218
+ int bold = 0 ;
219
+ int reverse = 0 ;
220
+ int i ;
221
+
222
+ for (i = 0 ; i < nprops ; i ++ ) {
223
+ switch (props [i ]) {
224
+ case 0 :
225
+ colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN ;
226
+ bold = 0 ;
227
+ reverse = 0 ;
228
+ break ;
229
+ case 1 :
230
+ bold = FOREGROUND_INTENSITY ;
231
+ break ;
232
+ case 7 :
233
+ reverse = 1 ;
234
+ break ;
235
+ case 30 :
236
+ colour = 0 ;
237
+ break ;
238
+ case 31 :
239
+ colour = FOREGROUND_RED ;
240
+ break ;
241
+ case 32 :
242
+ colour = FOREGROUND_GREEN ;
243
+ break ;
244
+ case 33 :
245
+ colour = FOREGROUND_RED | FOREGROUND_GREEN ;
246
+ break ;
247
+ case 34 :
248
+ colour = FOREGROUND_BLUE ;
249
+ break ;
250
+ case 35 :
251
+ colour = FOREGROUND_RED | FOREGROUND_BLUE ;
252
+ break ;
253
+ case 36 :
254
+ colour = FOREGROUND_BLUE | FOREGROUND_GREEN ;
255
+ break ;
256
+ case 37 :
257
+ colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN ;
258
+ break ;
259
+ }
260
+ }
261
+
262
+ flushOutput (current );
263
+
264
+ if (reverse ) {
265
+ SetConsoleTextAttribute (current -> outh , BACKGROUND_INTENSITY );
266
+ }
267
+ else {
268
+ SetConsoleTextAttribute (current -> outh , colour | bold );
269
+ }
270
+ }
271
+
272
+ static void eraseEol (struct current * current )
273
+ {
274
+ COORD pos ;
275
+ DWORD n ;
276
+
277
+ pos .X = (SHORT ) current -> x ;
278
+ pos .Y = (SHORT ) current -> y ;
279
+
280
+ FillConsoleOutputCharacter (current -> outh , ' ' , current -> cols - current -> x , pos , & n );
281
+ }
282
+
283
+ static void setCursorXY (struct current * current )
284
+ {
285
+ COORD pos ;
286
+
287
+ pos .X = (SHORT ) current -> x ;
288
+ pos .Y = (SHORT ) current -> y ;
289
+
290
+ SetConsoleCursorPosition (current -> outh , pos );
291
+ }
292
+
293
+
294
+ static void setCursorPos (struct current * current , int x )
295
+ {
296
+ current -> x = x ;
297
+ setCursorXY (current );
298
+ }
299
+
300
+ static void cursorUp (struct current * current , int n )
301
+ {
302
+ current -> y -= n ;
303
+ setCursorXY (current );
304
+ }
305
+
306
+ static void cursorDown (struct current * current , int n )
307
+ {
308
+ current -> y += n ;
309
+ setCursorXY (current );
310
+ }
311
+
312
+ static int fd_read (struct current * current )
313
+ {
314
+ while (1 ) {
315
+ INPUT_RECORD irec ;
316
+ DWORD n ;
317
+ if (WaitForSingleObject (current -> inh , INFINITE ) != WAIT_OBJECT_0 ) {
318
+ break ;
319
+ }
320
+ if (!ReadConsoleInputW (current -> inh , & irec , 1 , & n )) {
321
+ break ;
322
+ }
323
+ if (irec .EventType == KEY_EVENT ) {
324
+ KEY_EVENT_RECORD * k = & irec .Event .KeyEvent ;
325
+ if (k -> bKeyDown || k -> wVirtualKeyCode == VK_MENU ) {
326
+ if (k -> dwControlKeyState & ENHANCED_KEY ) {
327
+ switch (k -> wVirtualKeyCode ) {
328
+ case VK_LEFT :
329
+ return SPECIAL_LEFT ;
330
+ case VK_RIGHT :
331
+ return SPECIAL_RIGHT ;
332
+ case VK_UP :
333
+ return SPECIAL_UP ;
334
+ case VK_DOWN :
335
+ return SPECIAL_DOWN ;
336
+ case VK_INSERT :
337
+ return SPECIAL_INSERT ;
338
+ case VK_DELETE :
339
+ return SPECIAL_DELETE ;
340
+ case VK_HOME :
341
+ return SPECIAL_HOME ;
342
+ case VK_END :
343
+ return SPECIAL_END ;
344
+ case VK_PRIOR :
345
+ return SPECIAL_PAGE_UP ;
346
+ case VK_NEXT :
347
+ return SPECIAL_PAGE_DOWN ;
348
+ case VK_RETURN :
349
+ return k -> uChar .UnicodeChar ;
350
+ }
351
+ }
352
+ /* Note that control characters are already translated in AsciiChar */
353
+ else if (k -> wVirtualKeyCode == VK_CONTROL )
354
+ continue ;
355
+ else {
356
+ return k -> uChar .UnicodeChar ;
357
+ }
358
+ }
359
+ }
360
+ }
361
+ return -1 ;
362
+ }
363
+
364
+ static int getWindowSize (struct current * current )
365
+ {
366
+ CONSOLE_SCREEN_BUFFER_INFO info ;
367
+ if (!GetConsoleScreenBufferInfo (current -> outh , & info )) {
368
+ return -1 ;
369
+ }
370
+ current -> cols = info .dwSize .X ;
371
+ current -> rows = info .dwSize .Y ;
372
+ if (current -> cols <= 0 || current -> rows <= 0 ) {
373
+ current -> cols = 80 ;
374
+ return -1 ;
375
+ }
376
+ current -> y = info .dwCursorPosition .Y ;
377
+ current -> x = info .dwCursorPosition .X ;
378
+ return 0 ;
379
+ }
0 commit comments