Fossil SCM

fossil-scm / extsrc / linenoise-win32.c
Blame History Raw 380 lines
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
}
380

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button