blob: cd1c91009cb3544a1843b70ebaa270b992dca016 [file] [log] [blame]
Bram Moolenaare4f25e42017-07-07 11:54:15 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * Terminal window support, see ":help :terminal".
12 *
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020013 * There are three parts:
14 * 1. Generic code for all systems.
15 * 2. The MS-Windows implementation.
16 * Uses a hidden console for the terminal emulator.
17 * 3. The Unix-like implementation.
18 * Uses libvterm for the terminal emulator.
Bram Moolenaare4f25e42017-07-07 11:54:15 +020019 *
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020020 * When a terminal window is opened, a job is started that will be connected to
21 * the terminal emulator.
Bram Moolenaare4f25e42017-07-07 11:54:15 +020022 *
23 * If the terminal window has keyboard focus, typed keys are converted to the
24 * terminal encoding and writting to the job over a channel.
25 *
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020026 * If the job produces output, it is written to the terminal emulator. The
27 * terminal emulator invokes callbacks when its screen content changes. The
28 * line range is stored in tl_dirty_row_start and tl_dirty_row_end. Once in a
29 * while, if the terminal window is visible, the screen contents is drawn.
Bram Moolenaare4f25e42017-07-07 11:54:15 +020030 *
31 * TODO:
Bram Moolenaar938783d2017-07-16 20:13:26 +020032 * - pressing Enter sends two CR and/or NL characters to "bash -i"?
Bram Moolenaar96ca27a2017-07-17 23:20:24 +020033 * Passing Enter as NL seems to work.
Bram Moolenaare4f25e42017-07-07 11:54:15 +020034 * - set buffer options to be scratch, hidden, nomodifiable, etc.
35 * - set buffer name to command, add (1) to avoid duplicates.
Bram Moolenaar96ca27a2017-07-17 23:20:24 +020036 * - If [command] is not given the 'shell' option is used.
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020037 * - Add a scrollback buffer (contains lines to scroll off the top).
38 * Can use the buf_T lines, store attributes somewhere else?
39 * - When the job ends:
40 * - Write "-- JOB ENDED --" in the terminal.
41 * - Put the terminal contents in the scrollback buffer.
42 * - Free the terminal emulator.
43 * - Display the scrollback buffer (but with attributes).
44 * Make the buffer not modifiable, drop attributes when making changes.
Bram Moolenaar938783d2017-07-16 20:13:26 +020045 * - when closing window and job has not ended, make terminal hidden?
46 * - Use a pty for I/O with the job.
47 * - Windows implementation:
48 * (WiP): https://github.com/mattn/vim/tree/terminal
49 * src/os_win32.c mch_open_terminal()
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020050 * Using winpty ?
51 * - use win_del_lines() to make scroll-up efficient.
Bram Moolenaar938783d2017-07-16 20:13:26 +020052 * - command line completion for :terminal
Bram Moolenaare4f25e42017-07-07 11:54:15 +020053 * - support fixed size when 'termsize' is "rowsXcols".
54 * - support minimal size when 'termsize' is "rows*cols".
55 * - support minimal size when 'termsize' is empty.
56 * - implement ":buf {term-buf-name}"
Bram Moolenaar96ca27a2017-07-17 23:20:24 +020057 * - implement term_list() list of buffers with a terminal
58 * - implement term_getsize(buf)
59 * - implement term_setsize(buf)
60 * - implement term_sendkeys(buf, keys) send keystrokes to a terminal
61 * - implement term_wait(buf) wait for screen to be updated
62 * - implement term_scrape(buf, row) inspect terminal screen
63 * - implement term_open(command, options) open terminal window
64 * - implement term_getjob(buf)
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +020065 * - implement 'termkey'
Bram Moolenaare4f25e42017-07-07 11:54:15 +020066 */
67
68#include "vim.h"
69
70#ifdef FEAT_TERMINAL
71
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020072#ifdef WIN3264
73/* MS-Windows: use a native console. */
74#else
75/* Unix-like: use libvterm. */
76# include "libvterm/include/vterm.h"
77#endif
Bram Moolenaare4f25e42017-07-07 11:54:15 +020078
79/* typedef term_T in structs.h */
80struct terminal_S {
81 term_T *tl_next;
82
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020083#ifdef WIN3264
84 /* console handle? */
85#else
Bram Moolenaare4f25e42017-07-07 11:54:15 +020086 VTerm *tl_vterm;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020087#endif
Bram Moolenaare4f25e42017-07-07 11:54:15 +020088 job_T *tl_job;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +020089 buf_T *tl_buffer;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020090
91 /* Range of screen rows to update. Zero based. */
92 int tl_dirty_row_start; /* -1 if nothing dirty */
93 int tl_dirty_row_end; /* row below last one to update */
94
95 pos_T tl_cursor;
96};
97
98#define MAX_ROW 999999 /* used for tl_dirty_row_end to update all rows */
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020099#define KEY_BUF_LEN 200
100
101/* Functions implemented for MS-Windows and Unix-like systems. */
102static int term_init(term_T *term, int rows, int cols);
103static void term_free(term_T *term);
104static void term_write_job_output(term_T *term, char_u *msg, size_t len);
105static int term_convert_key(int c, char *buf);
106static void term_update_lines(win_T *wp);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200107
108/*
109 * List of all active terminals.
110 */
111static term_T *first_term = NULL;
112
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200113/**************************************
114 * 1. Generic code for all systems.
115 */
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200116
117/*
118 * ":terminal": open a terminal window and execute a job in it.
119 */
120 void
121ex_terminal(exarg_T *eap)
122{
123 int rows;
124 int cols;
125 exarg_T split_ea;
126 win_T *old_curwin = curwin;
127 typval_T argvars[2];
128 term_T *term;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200129 jobopt_T opt;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200130
131 if (check_restricted() || check_secure())
132 return;
133
134 term = (term_T *)alloc_clear(sizeof(term_T));
135 if (term == NULL)
136 return;
137 term->tl_dirty_row_end = MAX_ROW;
138
139 /* Open a new window or tab. */
140 vim_memset(&split_ea, 0, sizeof(split_ea));
141 split_ea.cmdidx = CMD_new;
142 split_ea.cmd = (char_u *)"new";
143 split_ea.arg = (char_u *)"";
144 ex_splitview(&split_ea);
145 if (curwin == old_curwin)
146 {
147 /* split failed */
148 vim_free(term);
149 return;
150 }
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200151 term->tl_buffer = curbuf;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200152
153 curbuf->b_term = term;
154 term->tl_next = first_term;
155 first_term = term;
156
157 /* TODO: set buffer type, hidden, etc. */
158
159 if (*curwin->w_p_tms != NUL)
160 {
161 char_u *p = vim_strchr(curwin->w_p_tms, 'x') + 1;
162
163 rows = atoi((char *)curwin->w_p_tms);
164 cols = atoi((char *)p);
165 /* TODO: resize window if possible. */
166 }
167 else
168 {
169 rows = curwin->w_height;
170 cols = curwin->w_width;
171 }
172
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200173 if (term_init(term, rows, cols) == OK)
174 {
175 argvars[0].v_type = VAR_STRING;
176 argvars[0].vval.v_string = eap->arg;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200177
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200178 clear_job_options(&opt);
179 opt.jo_mode = MODE_RAW;
180 opt.jo_out_mode = MODE_RAW;
181 opt.jo_err_mode = MODE_RAW;
182 opt.jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE;
183 opt.jo_io[PART_OUT] = JIO_BUFFER;
184 opt.jo_io[PART_ERR] = JIO_BUFFER;
185 opt.jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT));
186 opt.jo_io_buf[PART_OUT] = curbuf->b_fnum;
187 opt.jo_io_buf[PART_ERR] = curbuf->b_fnum;
188 opt.jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT));
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200189
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200190 term->tl_job = job_start(argvars, &opt);
191 }
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200192
Bram Moolenaar96ca27a2017-07-17 23:20:24 +0200193 if (term->tl_job == NULL)
194 /* Wiping out the buffer will also close the window. */
195 do_buffer(DOBUF_WIPE, DOBUF_CURRENT, FORWARD, 0, TRUE);
196
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200197 /* TODO: Setup pty, see mch_call_shell(). */
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200198}
199
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200200/*
Bram Moolenaar96ca27a2017-07-17 23:20:24 +0200201 * Free a terminal and everything it refers to.
202 * Kills the job if there is one.
203 * Called when wiping out a buffer.
204 */
205 void
206free_terminal(term_T *term)
207{
208 term_T *tp;
209
210 if (term == NULL)
211 return;
212 if (first_term == term)
213 first_term = term->tl_next;
214 else
215 for (tp = first_term; tp->tl_next != NULL; tp = tp->tl_next)
216 if (tp->tl_next == term)
217 {
218 tp->tl_next = term->tl_next;
219 break;
220 }
221
222 if (term->tl_job != NULL)
223 {
224 if (term->tl_job->jv_status != JOB_ENDED)
225 job_stop(term->tl_job, NULL, "kill");
226 job_unref(term->tl_job);
227 }
228
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200229 term_free(term);
Bram Moolenaar96ca27a2017-07-17 23:20:24 +0200230 vim_free(term);
231}
232
233/*
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200234 * Invoked when "msg" output from a job was received. Write it to the terminal
235 * of "buffer".
236 */
237 void
238write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
239{
240 size_t len = STRLEN(msg);
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200241 term_T *term = buffer->b_term;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200242
243 ch_logn(channel, "writing %d bytes to terminal", (int)len);
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200244 term_write_job_output(term, msg, len);
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200245
246 /* TODO: only update once in a while. */
247 update_screen(0);
248 setcursor();
249 out_flush();
250}
251
252/*
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200253 * Wait for input and send it to the job.
254 * Return when a CTRL-W command is typed that moves to another window.
255 */
256 void
257terminal_loop(void)
258{
259 char buf[KEY_BUF_LEN];
260 int c;
261 size_t len;
262
263 for (;;)
264 {
265 /* TODO: skip screen update when handling a sequence of keys. */
266 update_screen(0);
267 setcursor();
268 out_flush();
269 c = vgetc();
270
271 if (c == Ctrl_W)
272 {
273 stuffcharReadbuff(Ctrl_W);
274 return;
275 }
276
277 /* Convert the typed key to a sequence of bytes for the job. */
278 len = term_convert_key(c, buf);
279 if (len > 0)
280 /* TODO: if FAIL is returned, stop? */
281 channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN,
282 (char_u *)buf, len, NULL);
283 }
284}
285
286/*
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200287 * Called to update the window that contains the terminal.
288 */
289 void
290term_update_window(win_T *wp)
291{
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200292 term_update_lines(wp);
293}
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200294
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200295#ifdef WIN3264
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200296
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200297/**************************************
298 * 2. MS-Windows implementation.
299 */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200300
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200301/*
302 * Create a new terminal of "rows" by "cols" cells.
303 * Store a reference in "term".
304 * Return OK or FAIL.
305 */
306 static int
307term_init(term_T *term, int rows, int cols)
308{
309 /* TODO: Create a hidden console */
310 return FAIL;
311}
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200312
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200313/*
314 * Free the terminal emulator part of "term".
315 */
316 static void
317term_free(term_T *term)
318{
319 /* TODO */
320}
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200321
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200322/*
323 * Write job output "msg[len]" to the terminal.
324 */
325 static void
326term_write_job_output(term_T *term, char_u *msg, size_t len)
327{
328 /* TODO */
329}
330
331/*
332 * Convert typed key "c" into bytes to send to the job.
333 * Return the number of bytes in "buf".
334 */
335 static int
336term_convert_key(int c, char *buf)
337{
338 /* TODO */
339 return 0;
340}
341
342/*
343 * Called to update the window that contains the terminal.
344 */
345 static void
346term_update_lines(win_T *wp)
347{
348 /* TODO */
349}
350
351#else
352
353/**************************************
354 * 3. Unix-like implementation.
355 *
356 * For a terminal one VTerm is constructed. This uses libvterm. A copy of
357 * that library is in the libvterm directory.
358 */
359
360static int handle_damage(VTermRect rect, void *user);
361static int handle_moverect(VTermRect dest, VTermRect src, void *user);
362static int handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
363static int handle_resize(int rows, int cols, void *user);
364
365static VTermScreenCallbacks screen_callbacks = {
366 handle_damage, /* damage */
367 handle_moverect, /* moverect */
368 handle_movecursor, /* movecursor */
369 NULL, /* settermprop */
370 NULL, /* bell */
371 handle_resize, /* resize */
372 NULL, /* sb_pushline */
373 NULL /* sb_popline */
374};
375
376/*
377 * Create a new terminal of "rows" by "cols" cells.
378 * Store a reference in "term".
379 * Return OK or FAIL.
380 */
381 static int
382term_init(term_T *term, int rows, int cols)
383{
384 VTerm *vterm = vterm_new(rows, cols);
385 VTermScreen *screen;
386
387 term->tl_vterm = vterm;
388 screen = vterm_obtain_screen(vterm);
389 vterm_screen_set_callbacks(screen, &screen_callbacks, term);
390 /* TODO: depends on 'encoding'. */
391 vterm_set_utf8(vterm, 1);
392 /* Required to initialize most things. */
393 vterm_screen_reset(screen, 1 /* hard */);
394
395 /* By default NL means CR-NL. */
396 vterm_input_write(vterm, "\x1b[20h", 5);
397
398 return OK;
399}
400
401/*
402 * Free the terminal emulator part of "term".
403 */
404 static void
405term_free(term_T *term)
406{
407 vterm_free(term->tl_vterm);
408}
409
410/*
411 * Write job output "msg[len]" to the terminal.
412 */
413 static void
414term_write_job_output(term_T *term, char_u *msg, size_t len)
415{
416 VTerm *vterm = term->tl_vterm;
417
418 vterm_input_write(vterm, (char *)msg, len);
419 vterm_screen_flush_damage(vterm_obtain_screen(vterm));
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200420}
421
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200422 static int
423handle_damage(VTermRect rect, void *user)
424{
425 term_T *term = (term_T *)user;
426
427 term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row);
428 term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row);
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200429 redraw_buf_later(term->tl_buffer, NOT_VALID);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200430 return 1;
431}
432
433 static int
434handle_moverect(VTermRect dest, VTermRect src, void *user)
435{
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200436 term_T *term = (term_T *)user;
437
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200438 /* TODO */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200439 redraw_buf_later(term->tl_buffer, NOT_VALID);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200440 return 1;
441}
442
443 static int
444handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
445{
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200446 term_T *term = (term_T *)user;
447 win_T *wp;
448 int is_current = FALSE;
449
450 FOR_ALL_WINDOWS(wp)
451 {
452 if (wp->w_buffer == term->tl_buffer)
453 {
454 /* TODO: limit to window size? */
455 wp->w_wrow = pos.row;
456 wp->w_wcol = pos.col;
457 if (wp == curwin)
458 is_current = TRUE;
459 }
460 }
461
462 if (is_current)
463 {
464 setcursor();
465 out_flush();
466 }
467
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200468 return 1;
469}
470
471 static int
472handle_resize(int rows, int cols, void *user)
473{
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200474 term_T *term = (term_T *)user;
475
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200476 /* TODO: handle terminal resize. */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200477 redraw_buf_later(term->tl_buffer, NOT_VALID);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200478 return 1;
479}
480
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200481/*
482 * Convert typed key "c" into bytes to send to the job.
483 * Return the number of bytes in "buf".
484 */
485 static int
486term_convert_key(int c, char *buf)
487{
488 VTerm *vterm = curbuf->b_term->tl_vterm;
489 VTermKey key = VTERM_KEY_NONE;
490 VTermModifier mod = VTERM_MOD_NONE;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200491
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200492 switch (c)
493 {
494 /* TODO: which of these two should be used? */
495#if 0
496 case CAR: key = VTERM_KEY_ENTER; break;
497#else
498 case CAR: c = NL; break;
499#endif
500 case ESC: key = VTERM_KEY_ESCAPE; break;
501 case K_BS: key = VTERM_KEY_BACKSPACE; break;
502 case K_DEL: key = VTERM_KEY_DEL; break;
503 case K_DOWN: key = VTERM_KEY_DOWN; break;
504 case K_END: key = VTERM_KEY_END; break;
505 case K_F10: key = VTERM_KEY_FUNCTION(10); break;
506 case K_F11: key = VTERM_KEY_FUNCTION(11); break;
507 case K_F12: key = VTERM_KEY_FUNCTION(12); break;
508 case K_F1: key = VTERM_KEY_FUNCTION(1); break;
509 case K_F2: key = VTERM_KEY_FUNCTION(2); break;
510 case K_F3: key = VTERM_KEY_FUNCTION(3); break;
511 case K_F4: key = VTERM_KEY_FUNCTION(4); break;
512 case K_F5: key = VTERM_KEY_FUNCTION(5); break;
513 case K_F6: key = VTERM_KEY_FUNCTION(6); break;
514 case K_F7: key = VTERM_KEY_FUNCTION(7); break;
515 case K_F8: key = VTERM_KEY_FUNCTION(8); break;
516 case K_F9: key = VTERM_KEY_FUNCTION(9); break;
517 case K_HOME: key = VTERM_KEY_HOME; break;
518 case K_INS: key = VTERM_KEY_INS; break;
519 case K_K0: key = VTERM_KEY_KP_0; break;
520 case K_K1: key = VTERM_KEY_KP_1; break;
521 case K_K2: key = VTERM_KEY_KP_2; break;
522 case K_K3: key = VTERM_KEY_KP_3; break;
523 case K_K4: key = VTERM_KEY_KP_4; break;
524 case K_K5: key = VTERM_KEY_KP_5; break;
525 case K_K6: key = VTERM_KEY_KP_6; break;
526 case K_K7: key = VTERM_KEY_KP_7; break;
527 case K_K8: key = VTERM_KEY_KP_8; break;
528 case K_K9: key = VTERM_KEY_KP_9; break;
529 case K_KDEL: key = VTERM_KEY_DEL; break; /* TODO */
530 case K_KDIVIDE: key = VTERM_KEY_KP_DIVIDE; break;
531 case K_KEND: key = VTERM_KEY_KP_1; break; /* TODO */
532 case K_KENTER: key = VTERM_KEY_KP_ENTER; break;
533 case K_KHOME: key = VTERM_KEY_KP_7; break; /* TODO */
534 case K_KINS: key = VTERM_KEY_KP_0; break; /* TODO */
535 case K_KMINUS: key = VTERM_KEY_KP_MINUS; break;
536 case K_KMULTIPLY: key = VTERM_KEY_KP_MULT; break;
537 case K_KPAGEDOWN: key = VTERM_KEY_KP_3; break; /* TODO */
538 case K_KPAGEUP: key = VTERM_KEY_KP_9; break; /* TODO */
539 case K_KPLUS: key = VTERM_KEY_KP_PLUS; break;
540 case K_KPOINT: key = VTERM_KEY_KP_PERIOD; break;
541 case K_LEFT: key = VTERM_KEY_LEFT; break;
542 case K_PAGEDOWN: key = VTERM_KEY_PAGEDOWN; break;
543 case K_PAGEUP: key = VTERM_KEY_PAGEUP; break;
544 case K_RIGHT: key = VTERM_KEY_RIGHT; break;
545 case K_UP: key = VTERM_KEY_UP; break;
546 case TAB: key = VTERM_KEY_TAB; break;
547 }
548
549 /*
550 * Convert special keys to vterm keys:
551 * - Write keys to vterm: vterm_keyboard_key()
552 * - Write output to channel.
553 */
554 if (key != VTERM_KEY_NONE)
555 /* Special key, let vterm convert it. */
556 vterm_keyboard_key(vterm, key, mod);
557 else
558 /* Normal character, let vterm convert it. */
559 vterm_keyboard_unichar(vterm, c, mod);
560
561 /* Read back the converted escape sequence. */
562 return vterm_output_read(vterm, buf, KEY_BUF_LEN);
563}
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200564
Bram Moolenaar938783d2017-07-16 20:13:26 +0200565/*
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200566 * Called to update the window that contains the terminal.
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200567 */
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200568 static void
569term_update_lines(win_T *wp)
Bram Moolenaar938783d2017-07-16 20:13:26 +0200570{
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200571 int vterm_rows;
572 int vterm_cols;
573 VTerm *vterm = wp->w_buffer->b_term->tl_vterm;
574 VTermScreen *screen = vterm_obtain_screen(vterm);
575 VTermPos pos;
Bram Moolenaar938783d2017-07-16 20:13:26 +0200576
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200577 vterm_get_size(vterm, &vterm_rows, &vterm_cols);
578
579 /* TODO: Only redraw what changed. */
580 for (pos.row = 0; pos.row < wp->w_height; ++pos.row)
Bram Moolenaar938783d2017-07-16 20:13:26 +0200581 {
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200582 int off = screen_get_current_line_off();
Bram Moolenaar938783d2017-07-16 20:13:26 +0200583
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200584 if (pos.row < vterm_rows)
585 for (pos.col = 0; pos.col < wp->w_width && pos.col < vterm_cols;
586 ++pos.col)
587 {
588 VTermScreenCell cell;
589 int c;
Bram Moolenaar938783d2017-07-16 20:13:26 +0200590
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200591 vterm_screen_get_cell(screen, pos, &cell);
592 /* TODO: use cell.attrs and colors */
593 /* TODO: use cell.width */
594 /* TODO: multi-byte chars */
595 c = cell.chars[0];
596 ScreenLines[off] = c == NUL ? ' ' : c;
597 ScreenAttrs[off] = 0;
598 ++off;
599 }
Bram Moolenaar938783d2017-07-16 20:13:26 +0200600
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200601 screen_line(wp->w_winrow + pos.row, wp->w_wincol, pos.col, wp->w_width,
602 FALSE);
Bram Moolenaar938783d2017-07-16 20:13:26 +0200603 }
604}
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200605
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200606#endif
607
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200608#endif /* FEAT_TERMINAL */