blob: 4069e9b33d9f6f01ef7a81b10bdfcf37f5307966 [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 Moolenaare4f25e42017-07-07 11:54:15 +020032 * - set buffer options to be scratch, hidden, nomodifiable, etc.
33 * - set buffer name to command, add (1) to avoid duplicates.
Bram Moolenaar96ca27a2017-07-17 23:20:24 +020034 * - If [command] is not given the 'shell' option is used.
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020035 * - Add a scrollback buffer (contains lines to scroll off the top).
36 * Can use the buf_T lines, store attributes somewhere else?
37 * - When the job ends:
38 * - Write "-- JOB ENDED --" in the terminal.
39 * - Put the terminal contents in the scrollback buffer.
40 * - Free the terminal emulator.
41 * - Display the scrollback buffer (but with attributes).
42 * Make the buffer not modifiable, drop attributes when making changes.
Bram Moolenaar938783d2017-07-16 20:13:26 +020043 * - when closing window and job has not ended, make terminal hidden?
44 * - Use a pty for I/O with the job.
45 * - Windows implementation:
46 * (WiP): https://github.com/mattn/vim/tree/terminal
47 * src/os_win32.c mch_open_terminal()
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020048 * Using winpty ?
49 * - use win_del_lines() to make scroll-up efficient.
Bram Moolenaar938783d2017-07-16 20:13:26 +020050 * - command line completion for :terminal
Bram Moolenaare4f25e42017-07-07 11:54:15 +020051 * - support fixed size when 'termsize' is "rowsXcols".
52 * - support minimal size when 'termsize' is "rows*cols".
53 * - support minimal size when 'termsize' is empty.
54 * - implement ":buf {term-buf-name}"
Bram Moolenaar96ca27a2017-07-17 23:20:24 +020055 * - implement term_list() list of buffers with a terminal
56 * - implement term_getsize(buf)
57 * - implement term_setsize(buf)
58 * - implement term_sendkeys(buf, keys) send keystrokes to a terminal
59 * - implement term_wait(buf) wait for screen to be updated
60 * - implement term_scrape(buf, row) inspect terminal screen
61 * - implement term_open(command, options) open terminal window
62 * - implement term_getjob(buf)
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +020063 * - implement 'termkey'
Bram Moolenaare4f25e42017-07-07 11:54:15 +020064 */
65
66#include "vim.h"
67
68#ifdef FEAT_TERMINAL
69
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020070#ifdef WIN3264
71/* MS-Windows: use a native console. */
72#else
73/* Unix-like: use libvterm. */
74# include "libvterm/include/vterm.h"
75#endif
Bram Moolenaare4f25e42017-07-07 11:54:15 +020076
77/* typedef term_T in structs.h */
78struct terminal_S {
79 term_T *tl_next;
80
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020081#ifdef WIN3264
82 /* console handle? */
83#else
Bram Moolenaare4f25e42017-07-07 11:54:15 +020084 VTerm *tl_vterm;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020085#endif
Bram Moolenaare4f25e42017-07-07 11:54:15 +020086 job_T *tl_job;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +020087 buf_T *tl_buffer;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020088
89 /* Range of screen rows to update. Zero based. */
90 int tl_dirty_row_start; /* -1 if nothing dirty */
91 int tl_dirty_row_end; /* row below last one to update */
92
93 pos_T tl_cursor;
94};
95
96#define MAX_ROW 999999 /* used for tl_dirty_row_end to update all rows */
Bram Moolenaar8c0095c2017-07-18 22:53:21 +020097#define KEY_BUF_LEN 200
98
99/* Functions implemented for MS-Windows and Unix-like systems. */
100static int term_init(term_T *term, int rows, int cols);
101static void term_free(term_T *term);
102static void term_write_job_output(term_T *term, char_u *msg, size_t len);
103static int term_convert_key(int c, char *buf);
104static void term_update_lines(win_T *wp);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200105
106/*
107 * List of all active terminals.
108 */
109static term_T *first_term = NULL;
110
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200111/**************************************
112 * 1. Generic code for all systems.
113 */
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200114
115/*
116 * ":terminal": open a terminal window and execute a job in it.
117 */
118 void
119ex_terminal(exarg_T *eap)
120{
121 int rows;
122 int cols;
123 exarg_T split_ea;
124 win_T *old_curwin = curwin;
125 typval_T argvars[2];
126 term_T *term;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200127 jobopt_T opt;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200128
129 if (check_restricted() || check_secure())
130 return;
131
132 term = (term_T *)alloc_clear(sizeof(term_T));
133 if (term == NULL)
134 return;
135 term->tl_dirty_row_end = MAX_ROW;
136
137 /* Open a new window or tab. */
138 vim_memset(&split_ea, 0, sizeof(split_ea));
139 split_ea.cmdidx = CMD_new;
140 split_ea.cmd = (char_u *)"new";
141 split_ea.arg = (char_u *)"";
142 ex_splitview(&split_ea);
143 if (curwin == old_curwin)
144 {
145 /* split failed */
146 vim_free(term);
147 return;
148 }
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200149 term->tl_buffer = curbuf;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200150
151 curbuf->b_term = term;
152 term->tl_next = first_term;
153 first_term = term;
154
155 /* TODO: set buffer type, hidden, etc. */
156
157 if (*curwin->w_p_tms != NUL)
158 {
159 char_u *p = vim_strchr(curwin->w_p_tms, 'x') + 1;
160
161 rows = atoi((char *)curwin->w_p_tms);
162 cols = atoi((char *)p);
163 /* TODO: resize window if possible. */
164 }
165 else
166 {
167 rows = curwin->w_height;
168 cols = curwin->w_width;
169 }
170
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200171 if (term_init(term, rows, cols) == OK)
172 {
173 argvars[0].v_type = VAR_STRING;
174 argvars[0].vval.v_string = eap->arg;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200175
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200176 clear_job_options(&opt);
177 opt.jo_mode = MODE_RAW;
178 opt.jo_out_mode = MODE_RAW;
179 opt.jo_err_mode = MODE_RAW;
180 opt.jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE;
181 opt.jo_io[PART_OUT] = JIO_BUFFER;
182 opt.jo_io[PART_ERR] = JIO_BUFFER;
183 opt.jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT));
184 opt.jo_io_buf[PART_OUT] = curbuf->b_fnum;
185 opt.jo_io_buf[PART_ERR] = curbuf->b_fnum;
186 opt.jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT));
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200187 opt.jo_term_rows = rows;
188 opt.jo_term_cols = cols;
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.
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200254 * Return when the start of a CTRL-W command is typed or anything else that
255 * should be handled as a Normal mode command.
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200256 */
257 void
258terminal_loop(void)
259{
260 char buf[KEY_BUF_LEN];
261 int c;
262 size_t len;
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200263 static int mouse_was_outside = FALSE;
264 int dragging_outside = FALSE;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200265
266 for (;;)
267 {
268 /* TODO: skip screen update when handling a sequence of keys. */
269 update_screen(0);
270 setcursor();
271 out_flush();
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200272 ++no_mapping;
273 ++allow_keys;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200274 c = vgetc();
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200275 --no_mapping;
276 --allow_keys;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200277
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200278 /* Catch keys that need to be handled as in Normal mode. */
279 switch (c)
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200280 {
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200281 case Ctrl_W:
282 case NUL:
283 case K_ZERO:
284 stuffcharReadbuff(c);
285 return;
286
287 case K_IGNORE: continue;
288
289 case K_LEFTDRAG:
290 case K_MIDDLEDRAG:
291 case K_RIGHTDRAG:
292 case K_X1DRAG:
293 case K_X2DRAG:
294 dragging_outside = mouse_was_outside;
295 /* FALLTHROUGH */
296 case K_LEFTMOUSE:
297 case K_LEFTMOUSE_NM:
298 case K_LEFTRELEASE:
299 case K_LEFTRELEASE_NM:
300 case K_MIDDLEMOUSE:
301 case K_MIDDLERELEASE:
302 case K_RIGHTMOUSE:
303 case K_RIGHTRELEASE:
304 case K_X1MOUSE:
305 case K_X1RELEASE:
306 case K_X2MOUSE:
307 case K_X2RELEASE:
308 if (mouse_row < W_WINROW(curwin)
309 || mouse_row >= (W_WINROW(curwin) + curwin->w_height)
310 || mouse_col < W_WINCOL(curwin)
311 || mouse_col >= W_ENDCOL(curwin)
312 || dragging_outside)
313 {
314 /* click outside the current window */
315 stuffcharReadbuff(c);
316 mouse_was_outside = TRUE;
317 return;
318 }
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200319 }
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200320 mouse_was_outside = FALSE;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200321
322 /* Convert the typed key to a sequence of bytes for the job. */
323 len = term_convert_key(c, buf);
324 if (len > 0)
325 /* TODO: if FAIL is returned, stop? */
326 channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN,
327 (char_u *)buf, len, NULL);
328 }
329}
330
331/*
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200332 * Called to update the window that contains the terminal.
333 */
334 void
335term_update_window(win_T *wp)
336{
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200337 term_update_lines(wp);
338}
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200339
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200340 static void
341position_cursor(win_T *wp, VTermPos *pos)
342{
343 wp->w_wrow = MIN(pos->row, MAX(0, wp->w_height - 1));
344 wp->w_wcol = MIN(pos->col, MAX(0, wp->w_width - 1));
345}
346
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200347#ifdef WIN3264
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200348
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200349/**************************************
350 * 2. MS-Windows implementation.
351 */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200352
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200353/*
354 * Create a new terminal of "rows" by "cols" cells.
355 * Store a reference in "term".
356 * Return OK or FAIL.
357 */
358 static int
359term_init(term_T *term, int rows, int cols)
360{
361 /* TODO: Create a hidden console */
362 return FAIL;
363}
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200364
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200365/*
366 * Free the terminal emulator part of "term".
367 */
368 static void
369term_free(term_T *term)
370{
371 /* TODO */
372}
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200373
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200374/*
375 * Write job output "msg[len]" to the terminal.
376 */
377 static void
378term_write_job_output(term_T *term, char_u *msg, size_t len)
379{
380 /* TODO */
381}
382
383/*
384 * Convert typed key "c" into bytes to send to the job.
385 * Return the number of bytes in "buf".
386 */
387 static int
388term_convert_key(int c, char *buf)
389{
390 /* TODO */
391 return 0;
392}
393
394/*
395 * Called to update the window that contains the terminal.
396 */
397 static void
398term_update_lines(win_T *wp)
399{
400 /* TODO */
401}
402
403#else
404
405/**************************************
406 * 3. Unix-like implementation.
407 *
408 * For a terminal one VTerm is constructed. This uses libvterm. A copy of
409 * that library is in the libvterm directory.
410 */
411
412static int handle_damage(VTermRect rect, void *user);
413static int handle_moverect(VTermRect dest, VTermRect src, void *user);
414static int handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
415static int handle_resize(int rows, int cols, void *user);
416
417static VTermScreenCallbacks screen_callbacks = {
418 handle_damage, /* damage */
419 handle_moverect, /* moverect */
420 handle_movecursor, /* movecursor */
421 NULL, /* settermprop */
422 NULL, /* bell */
423 handle_resize, /* resize */
424 NULL, /* sb_pushline */
425 NULL /* sb_popline */
426};
427
428/*
429 * Create a new terminal of "rows" by "cols" cells.
430 * Store a reference in "term".
431 * Return OK or FAIL.
432 */
433 static int
434term_init(term_T *term, int rows, int cols)
435{
436 VTerm *vterm = vterm_new(rows, cols);
437 VTermScreen *screen;
438
439 term->tl_vterm = vterm;
440 screen = vterm_obtain_screen(vterm);
441 vterm_screen_set_callbacks(screen, &screen_callbacks, term);
442 /* TODO: depends on 'encoding'. */
443 vterm_set_utf8(vterm, 1);
444 /* Required to initialize most things. */
445 vterm_screen_reset(screen, 1 /* hard */);
446
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200447 return OK;
448}
449
450/*
451 * Free the terminal emulator part of "term".
452 */
453 static void
454term_free(term_T *term)
455{
456 vterm_free(term->tl_vterm);
457}
458
459/*
460 * Write job output "msg[len]" to the terminal.
461 */
462 static void
463term_write_job_output(term_T *term, char_u *msg, size_t len)
464{
465 VTerm *vterm = term->tl_vterm;
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200466 char_u *p;
467 size_t done;
468 size_t len_now;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200469
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200470 for (done = 0; done < len; done += len_now)
471 {
472 for (p = msg + done; p < msg + len; )
473 {
474 if (*p == NL)
475 break;
476 p += mb_ptr2len_len(p, len - (p - msg));
477 }
478 len_now = p - msg - done;
479 vterm_input_write(vterm, (char *)msg + done, len_now);
480 if (p < msg + len && *p == NL)
481 {
482 /* Convert NL to CR-NL, that appears to work best. */
483 vterm_input_write(vterm, "\r\n", 2);
484 ++len_now;
485 }
486 }
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200487 vterm_screen_flush_damage(vterm_obtain_screen(vterm));
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200488}
489
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200490 static int
491handle_damage(VTermRect rect, void *user)
492{
493 term_T *term = (term_T *)user;
494
495 term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row);
496 term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row);
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200497 redraw_buf_later(term->tl_buffer, NOT_VALID);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200498 return 1;
499}
500
501 static int
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200502handle_moverect(VTermRect dest UNUSED, VTermRect src UNUSED, void *user)
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200503{
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200504 term_T *term = (term_T *)user;
505
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200506 /* TODO */
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200507 redraw_buf_later(term->tl_buffer, NOT_VALID);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200508 return 1;
509}
510
511 static int
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200512handle_movecursor(
513 VTermPos pos,
514 VTermPos oldpos UNUSED,
515 int visible UNUSED,
516 void *user)
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200517{
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200518 term_T *term = (term_T *)user;
519 win_T *wp;
520 int is_current = FALSE;
521
522 FOR_ALL_WINDOWS(wp)
523 {
524 if (wp->w_buffer == term->tl_buffer)
525 {
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200526 position_cursor(wp, &pos);
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200527 if (wp == curwin)
528 is_current = TRUE;
529 }
530 }
531
532 if (is_current)
533 {
534 setcursor();
535 out_flush();
536 }
537
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200538 return 1;
539}
540
541 static int
542handle_resize(int rows, int cols, void *user)
543{
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200544 term_T *term = (term_T *)user;
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200545 win_T *wp;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200546
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200547 FOR_ALL_WINDOWS(wp)
548 {
549 if (wp->w_buffer == term->tl_buffer)
550 {
551 win_setheight_win(rows, wp);
552 win_setwidth_win(cols, wp);
553 }
554 }
555
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +0200556 redraw_buf_later(term->tl_buffer, NOT_VALID);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200557 return 1;
558}
559
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200560/*
561 * Convert typed key "c" into bytes to send to the job.
562 * Return the number of bytes in "buf".
563 */
564 static int
565term_convert_key(int c, char *buf)
566{
567 VTerm *vterm = curbuf->b_term->tl_vterm;
568 VTermKey key = VTERM_KEY_NONE;
569 VTermModifier mod = VTERM_MOD_NONE;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200570
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200571 switch (c)
572 {
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200573 case CAR: key = VTERM_KEY_ENTER; break;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200574 case ESC: key = VTERM_KEY_ESCAPE; break;
Bram Moolenaare906ae82017-07-21 21:10:01 +0200575 /* VTERM_KEY_BACKSPACE becomes 0x7f DEL */
576 case K_BS: c = BS; break;
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200577 case K_DEL: key = VTERM_KEY_DEL; break;
578 case K_DOWN: key = VTERM_KEY_DOWN; break;
579 case K_END: key = VTERM_KEY_END; break;
580 case K_F10: key = VTERM_KEY_FUNCTION(10); break;
581 case K_F11: key = VTERM_KEY_FUNCTION(11); break;
582 case K_F12: key = VTERM_KEY_FUNCTION(12); break;
583 case K_F1: key = VTERM_KEY_FUNCTION(1); break;
584 case K_F2: key = VTERM_KEY_FUNCTION(2); break;
585 case K_F3: key = VTERM_KEY_FUNCTION(3); break;
586 case K_F4: key = VTERM_KEY_FUNCTION(4); break;
587 case K_F5: key = VTERM_KEY_FUNCTION(5); break;
588 case K_F6: key = VTERM_KEY_FUNCTION(6); break;
589 case K_F7: key = VTERM_KEY_FUNCTION(7); break;
590 case K_F8: key = VTERM_KEY_FUNCTION(8); break;
591 case K_F9: key = VTERM_KEY_FUNCTION(9); break;
592 case K_HOME: key = VTERM_KEY_HOME; break;
593 case K_INS: key = VTERM_KEY_INS; break;
594 case K_K0: key = VTERM_KEY_KP_0; break;
595 case K_K1: key = VTERM_KEY_KP_1; break;
596 case K_K2: key = VTERM_KEY_KP_2; break;
597 case K_K3: key = VTERM_KEY_KP_3; break;
598 case K_K4: key = VTERM_KEY_KP_4; break;
599 case K_K5: key = VTERM_KEY_KP_5; break;
600 case K_K6: key = VTERM_KEY_KP_6; break;
601 case K_K7: key = VTERM_KEY_KP_7; break;
602 case K_K8: key = VTERM_KEY_KP_8; break;
603 case K_K9: key = VTERM_KEY_KP_9; break;
604 case K_KDEL: key = VTERM_KEY_DEL; break; /* TODO */
605 case K_KDIVIDE: key = VTERM_KEY_KP_DIVIDE; break;
606 case K_KEND: key = VTERM_KEY_KP_1; break; /* TODO */
607 case K_KENTER: key = VTERM_KEY_KP_ENTER; break;
608 case K_KHOME: key = VTERM_KEY_KP_7; break; /* TODO */
609 case K_KINS: key = VTERM_KEY_KP_0; break; /* TODO */
610 case K_KMINUS: key = VTERM_KEY_KP_MINUS; break;
611 case K_KMULTIPLY: key = VTERM_KEY_KP_MULT; break;
612 case K_KPAGEDOWN: key = VTERM_KEY_KP_3; break; /* TODO */
613 case K_KPAGEUP: key = VTERM_KEY_KP_9; break; /* TODO */
614 case K_KPLUS: key = VTERM_KEY_KP_PLUS; break;
615 case K_KPOINT: key = VTERM_KEY_KP_PERIOD; break;
616 case K_LEFT: key = VTERM_KEY_LEFT; break;
617 case K_PAGEDOWN: key = VTERM_KEY_PAGEDOWN; break;
618 case K_PAGEUP: key = VTERM_KEY_PAGEUP; break;
619 case K_RIGHT: key = VTERM_KEY_RIGHT; break;
620 case K_UP: key = VTERM_KEY_UP; break;
621 case TAB: key = VTERM_KEY_TAB; break;
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200622
623 case K_MOUSEUP: /* TODO */ break;
624 case K_MOUSEDOWN: /* TODO */ break;
625 case K_MOUSELEFT: /* TODO */ break;
626 case K_MOUSERIGHT: /* TODO */ break;
627
628 case K_LEFTMOUSE: /* TODO */ break;
629 case K_LEFTMOUSE_NM: /* TODO */ break;
630 case K_LEFTDRAG: /* TODO */ break;
631 case K_LEFTRELEASE: /* TODO */ break;
632 case K_LEFTRELEASE_NM: /* TODO */ break;
633 case K_MIDDLEMOUSE: /* TODO */ break;
634 case K_MIDDLEDRAG: /* TODO */ break;
635 case K_MIDDLERELEASE: /* TODO */ break;
636 case K_RIGHTMOUSE: /* TODO */ break;
637 case K_RIGHTDRAG: /* TODO */ break;
638 case K_RIGHTRELEASE: /* TODO */ break;
639 case K_X1MOUSE: /* TODO */ break;
640 case K_X1DRAG: /* TODO */ break;
641 case K_X1RELEASE: /* TODO */ break;
642 case K_X2MOUSE: /* TODO */ break;
643 case K_X2DRAG: /* TODO */ break;
644 case K_X2RELEASE: /* TODO */ break;
645
646 /* TODO: handle all special keys and modifiers that terminal_loop()
647 * does not handle. */
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200648 }
649
650 /*
651 * Convert special keys to vterm keys:
652 * - Write keys to vterm: vterm_keyboard_key()
653 * - Write output to channel.
654 */
655 if (key != VTERM_KEY_NONE)
656 /* Special key, let vterm convert it. */
657 vterm_keyboard_key(vterm, key, mod);
658 else
659 /* Normal character, let vterm convert it. */
660 vterm_keyboard_unichar(vterm, c, mod);
661
662 /* Read back the converted escape sequence. */
663 return vterm_output_read(vterm, buf, KEY_BUF_LEN);
664}
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200665
Bram Moolenaar938783d2017-07-16 20:13:26 +0200666/*
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200667 * Called to update the window that contains the terminal.
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200668 */
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200669 static void
670term_update_lines(win_T *wp)
Bram Moolenaar938783d2017-07-16 20:13:26 +0200671{
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200672 int vterm_rows;
673 int vterm_cols;
674 VTerm *vterm = wp->w_buffer->b_term->tl_vterm;
675 VTermScreen *screen = vterm_obtain_screen(vterm);
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200676 VTermState *state = vterm_obtain_state(vterm);
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200677 VTermPos pos;
Bram Moolenaar938783d2017-07-16 20:13:26 +0200678
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200679 vterm_get_size(vterm, &vterm_rows, &vterm_cols);
680
Bram Moolenaar58556cd2017-07-20 23:04:46 +0200681 if (*wp->w_p_tms == NUL
682 && (vterm_rows != wp->w_height || vterm_cols != wp->w_width))
683 {
684 vterm_set_size(vterm, wp->w_height, wp->w_width);
685 /* Get the size again, in case setting the didn't work. */
686 vterm_get_size(vterm, &vterm_rows, &vterm_cols);
687 }
688
689 /* The cursor may have been moved when resizing. */
690 vterm_state_get_cursorpos(state, &pos);
691 position_cursor(wp, &pos);
692
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200693 /* TODO: Only redraw what changed. */
694 for (pos.row = 0; pos.row < wp->w_height; ++pos.row)
Bram Moolenaar938783d2017-07-16 20:13:26 +0200695 {
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200696 int off = screen_get_current_line_off();
Bram Moolenaar938783d2017-07-16 20:13:26 +0200697
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200698 if (pos.row < vterm_rows)
699 for (pos.col = 0; pos.col < wp->w_width && pos.col < vterm_cols;
700 ++pos.col)
701 {
702 VTermScreenCell cell;
703 int c;
Bram Moolenaar938783d2017-07-16 20:13:26 +0200704
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200705 vterm_screen_get_cell(screen, pos, &cell);
706 /* TODO: use cell.attrs and colors */
707 /* TODO: use cell.width */
708 /* TODO: multi-byte chars */
709 c = cell.chars[0];
710 ScreenLines[off] = c == NUL ? ' ' : c;
711 ScreenAttrs[off] = 0;
712 ++off;
713 }
Bram Moolenaare825d8b2017-07-19 23:20:19 +0200714 else
715 pos.col = 0;
Bram Moolenaar938783d2017-07-16 20:13:26 +0200716
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200717 screen_line(wp->w_winrow + pos.row, wp->w_wincol, pos.col, wp->w_width,
718 FALSE);
Bram Moolenaar938783d2017-07-16 20:13:26 +0200719 }
720}
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200721
Bram Moolenaar8c0095c2017-07-18 22:53:21 +0200722#endif
723
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200724#endif /* FEAT_TERMINAL */