2 /* this code is not standalone
3 * it is included into linenoise.c
5 * It is deliberately kept separate so that
6 * applications that have no need for windows
7 * support can omit this
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();
32 static void refreshNewline(struct current
*current
)
35 outputNewline(current
);
38 static void refreshEndChars(struct current
*current
)
40 assert(current
->output
);
42 sb_free(current
->output
);
43 current
->output
= NULL
;
46 static int enableRawMode(struct current
*current
) {
50 current
->outh
= GetStdHandle(STD_OUTPUT_HANDLE
);
51 current
->inh
= GetStdHandle(STD_INPUT_HANDLE
);
53 if (!PeekConsoleInput(current
->inh
, &irec
, 1, &n
)) {
56 if (getWindowSize(current
) != 0) {
59 if (GetConsoleMode(current
->inh
, &orig_consolemode
)) {
60 SetConsoleMode(current
->inh
, ENABLE_PROCESSED_INPUT
);
63 /* XXX is this the right thing to do? */
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(¤t
) == 0) {
82 COORD topleft
= { 0, 0 };
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
)
100 pos
.Y
= (SHORT
)current
->y
;
102 FillConsoleOutputAttribute(current
->outh
,
103 FOREGROUND_RED
| FOREGROUND_BLUE
| FOREGROUND_GREEN
, current
->cols
, pos
, &n
);
108 static void flush_ubuf(struct current
*current
)
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
141 current
->ubuf
[current
->ubuflen
++] = (WORD
)((ch
>> halfShift
) + UNI_SUR_HIGH_START
);
142 current
->ubuf
[current
->ubuflen
++] = (WORD
)((ch
& halfMask
) + UNI_SUR_LOW_START
);
145 current
->ubuf
[current
->ubuflen
++] = ch
;
147 current
->ubufcols
+= utf8_width(ch
);
148 if (current
->ubuflen
>= UBUF_MAX_CHARS
) {
154 static int flushOutput(struct current
*current
)
156 const char *pt
= sb_str(current
->output
);
157 int len
= sb_len(current
->output
);
160 /* convert utf8 in current->output into utf16 in current->ubuf
164 int n
= utf8_tounicode(pt
, &ch
);
169 add_ubuf(current
, ch
);
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);
185 sb_clear(current
->output
);
190 static int outputChars(struct current
*current
, const char *buf
, int len
)
195 assert(current
->output
);
197 sb_append_len(current
->output
, buf
, len
);
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
);
213 static void setOutputHighlight(struct current
*current
, const int *props
, int nprops
)
215 int colour
= FOREGROUND_RED
| FOREGROUND_BLUE
| FOREGROUND_GREEN
;
220 for (i
= 0; i
< nprops
; i
++) {
223 colour
= FOREGROUND_RED
| FOREGROUND_BLUE
| FOREGROUND_GREEN
;
228 bold
= FOREGROUND_INTENSITY
;
237 colour
= FOREGROUND_RED
;
240 colour
= FOREGROUND_GREEN
;
243 colour
= FOREGROUND_RED
| FOREGROUND_GREEN
;
246 colour
= FOREGROUND_BLUE
;
249 colour
= FOREGROUND_RED
| FOREGROUND_BLUE
;
252 colour
= FOREGROUND_BLUE
| FOREGROUND_GREEN
;
255 colour
= FOREGROUND_RED
| FOREGROUND_BLUE
| FOREGROUND_GREEN
;
260 flushOutput(current
);
263 SetConsoleTextAttribute(current
->outh
, BACKGROUND_INTENSITY
);
266 SetConsoleTextAttribute(current
->outh
, colour
| bold
);
270 static void eraseEol(struct current
*current
)
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
)
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
)
295 setCursorXY(current
);
298 static void cursorUp(struct current
*current
, int n
)
301 setCursorXY(current
);
304 static void cursorDown(struct current
*current
, int n
)
307 setCursorXY(current
);
310 static int fd_read(struct current
*current
)
315 if (WaitForSingleObject(current
->inh
, INFINITE
) != WAIT_OBJECT_0
) {
318 if (!ReadConsoleInputW(current
->inh
, &irec
, 1, &n
)) {
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
) {
329 return SPECIAL_RIGHT
;
335 return SPECIAL_INSERT
;
337 return SPECIAL_DELETE
;
343 return SPECIAL_PAGE_UP
;
345 return SPECIAL_PAGE_DOWN
;
348 /* Note that control characters are already translated in AsciiChar */
349 else if (k
->wVirtualKeyCode
== VK_CONTROL
)
352 return k
->uChar
.UnicodeChar
;
360 static int getWindowSize(struct current
*current
)
362 CONSOLE_SCREEN_BUFFER_INFO info
;
363 if (!GetConsoleScreenBufferInfo(current
->outh
, &info
)) {
366 current
->cols
= info
.dwSize
.X
;
367 current
->rows
= info
.dwSize
.Y
;
368 if (current
->cols
<= 0 || current
->rows
<= 0) {
372 current
->y
= info
.dwCursorPosition
.Y
;
373 current
->x
= info
.dwCursorPosition
.X
;