To: vim_dev@googlegroups.com Subject: Patch 8.0.0730 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.0730 Problem: Terminal feature only supports Unix-like systems. Solution: Prepare for adding an MS-Windows implementaiton. Files: src/terminal.c *** ../vim-8.0.0729/src/terminal.c 2017-07-17 23:20:18.335903533 +0200 --- src/terminal.c 2017-07-18 22:48:15.997398685 +0200 *************** *** 10,27 **** /* * Terminal window support, see ":help :terminal". * ! * For a terminal one VTerm is constructed. This uses libvterm. A copy of ! * that library is in the libvterm directory. * ! * The VTerm invokes callbacks when its screen contents changes. The line ! * range is stored in tl_dirty_row_start and tl_dirty_row_end. Once in a ! * while, if the terminal window is visible, the screen contents is drawn. * * If the terminal window has keyboard focus, typed keys are converted to the * terminal encoding and writting to the job over a channel. * ! * If the job produces output, it is written to the VTerm. ! * This will result in screen updates. * * TODO: * - pressing Enter sends two CR and/or NL characters to "bash -i"? --- 10,32 ---- /* * Terminal window support, see ":help :terminal". * ! * There are three parts: ! * 1. Generic code for all systems. ! * 2. The MS-Windows implementation. ! * Uses a hidden console for the terminal emulator. ! * 3. The Unix-like implementation. ! * Uses libvterm for the terminal emulator. * ! * When a terminal window is opened, a job is started that will be connected to ! * the terminal emulator. * * If the terminal window has keyboard focus, typed keys are converted to the * terminal encoding and writting to the job over a channel. * ! * If the job produces output, it is written to the terminal emulator. The ! * terminal emulator invokes callbacks when its screen content changes. The ! * line range is stored in tl_dirty_row_start and tl_dirty_row_end. Once in a ! * while, if the terminal window is visible, the screen contents is drawn. * * TODO: * - pressing Enter sends two CR and/or NL characters to "bash -i"? *************** *** 29,42 **** * - set buffer options to be scratch, hidden, nomodifiable, etc. * - set buffer name to command, add (1) to avoid duplicates. * - If [command] is not given the 'shell' option is used. ! * - if the job ends, write "-- JOB ENDED --" in the terminal ! * - when closing window and job ended, delete the terminal * - when closing window and job has not ended, make terminal hidden? * - Use a pty for I/O with the job. * - Windows implementation: * (WiP): https://github.com/mattn/vim/tree/terminal * src/os_win32.c mch_open_terminal() ! Using winpty ? * - command line completion for :terminal * - support fixed size when 'termsize' is "rowsXcols". * - support minimal size when 'termsize' is "rows*cols". --- 34,54 ---- * - set buffer options to be scratch, hidden, nomodifiable, etc. * - set buffer name to command, add (1) to avoid duplicates. * - If [command] is not given the 'shell' option is used. ! * - Add a scrollback buffer (contains lines to scroll off the top). ! * Can use the buf_T lines, store attributes somewhere else? ! * - When the job ends: ! * - Write "-- JOB ENDED --" in the terminal. ! * - Put the terminal contents in the scrollback buffer. ! * - Free the terminal emulator. ! * - Display the scrollback buffer (but with attributes). ! * Make the buffer not modifiable, drop attributes when making changes. * - when closing window and job has not ended, make terminal hidden? * - Use a pty for I/O with the job. * - Windows implementation: * (WiP): https://github.com/mattn/vim/tree/terminal * src/os_win32.c mch_open_terminal() ! * Using winpty ? ! * - use win_del_lines() to make scroll-up efficient. * - command line completion for :terminal * - support fixed size when 'termsize' is "rowsXcols". * - support minimal size when 'termsize' is "rows*cols". *************** *** 57,69 **** #ifdef FEAT_TERMINAL ! #include "libvterm/include/vterm.h" /* typedef term_T in structs.h */ struct terminal_S { term_T *tl_next; VTerm *tl_vterm; job_T *tl_job; buf_T *tl_buffer; --- 69,90 ---- #ifdef FEAT_TERMINAL ! #ifdef WIN3264 ! /* MS-Windows: use a native console. */ ! #else ! /* Unix-like: use libvterm. */ ! # include "libvterm/include/vterm.h" ! #endif /* typedef term_T in structs.h */ struct terminal_S { term_T *tl_next; + #ifdef WIN3264 + /* console handle? */ + #else VTerm *tl_vterm; + #endif job_T *tl_job; buf_T *tl_buffer; *************** *** 75,101 **** }; #define MAX_ROW 999999 /* used for tl_dirty_row_end to update all rows */ /* * List of all active terminals. */ static term_T *first_term = NULL; ! static int handle_damage(VTermRect rect, void *user); ! static int handle_moverect(VTermRect dest, VTermRect src, void *user); ! static int handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user); ! static int handle_resize(int rows, int cols, void *user); ! ! static VTermScreenCallbacks screen_callbacks = { ! handle_damage, /* damage */ ! handle_moverect, /* moverect */ ! handle_movecursor, /* movecursor */ ! NULL, /* settermprop */ ! NULL, /* bell */ ! handle_resize, /* resize */ ! NULL, /* sb_pushline */ ! NULL /* sb_popline */ ! }; /* * ":terminal": open a terminal window and execute a job in it. --- 96,118 ---- }; #define MAX_ROW 999999 /* used for tl_dirty_row_end to update all rows */ + #define KEY_BUF_LEN 200 + + /* Functions implemented for MS-Windows and Unix-like systems. */ + static int term_init(term_T *term, int rows, int cols); + static void term_free(term_T *term); + static void term_write_job_output(term_T *term, char_u *msg, size_t len); + static int term_convert_key(int c, char *buf); + static void term_update_lines(win_T *wp); /* * List of all active terminals. */ static term_T *first_term = NULL; ! /************************************** ! * 1. Generic code for all systems. ! */ /* * ":terminal": open a terminal window and execute a job in it. *************** *** 109,116 **** win_T *old_curwin = curwin; typval_T argvars[2]; term_T *term; - VTerm *vterm; - VTermScreen *screen; jobopt_T opt; if (check_restricted() || check_secure()) --- 126,131 ---- *************** *** 155,194 **** cols = curwin->w_width; } ! vterm = vterm_new(rows, cols); ! term->tl_vterm = vterm; ! screen = vterm_obtain_screen(vterm); ! vterm_screen_set_callbacks(screen, &screen_callbacks, term); ! /* TODO: depends on 'encoding'. */ ! vterm_set_utf8(vterm, 1); ! /* Required to initialize most things. */ ! vterm_screen_reset(screen, 1 /* hard */); ! ! /* By default NL means CR-NL. */ ! vterm_input_write(vterm, "\x1b[20h", 5); ! ! argvars[0].v_type = VAR_STRING; ! argvars[0].vval.v_string = eap->arg; ! clear_job_options(&opt); ! opt.jo_mode = MODE_RAW; ! opt.jo_out_mode = MODE_RAW; ! opt.jo_err_mode = MODE_RAW; ! opt.jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE; ! opt.jo_io[PART_OUT] = JIO_BUFFER; ! opt.jo_io[PART_ERR] = JIO_BUFFER; ! opt.jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT)); ! opt.jo_io_buf[PART_OUT] = curbuf->b_fnum; ! opt.jo_io_buf[PART_ERR] = curbuf->b_fnum; ! opt.jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT)); ! term->tl_job = job_start(argvars, &opt); if (term->tl_job == NULL) /* Wiping out the buffer will also close the window. */ do_buffer(DOBUF_WIPE, DOBUF_CURRENT, FORWARD, 0, TRUE); ! /* Setup pty, see mch_call_shell(). */ } /* --- 170,200 ---- cols = curwin->w_width; } ! if (term_init(term, rows, cols) == OK) ! { ! argvars[0].v_type = VAR_STRING; ! argvars[0].vval.v_string = eap->arg; ! clear_job_options(&opt); ! opt.jo_mode = MODE_RAW; ! opt.jo_out_mode = MODE_RAW; ! opt.jo_err_mode = MODE_RAW; ! opt.jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE; ! opt.jo_io[PART_OUT] = JIO_BUFFER; ! opt.jo_io[PART_ERR] = JIO_BUFFER; ! opt.jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT)); ! opt.jo_io_buf[PART_OUT] = curbuf->b_fnum; ! opt.jo_io_buf[PART_ERR] = curbuf->b_fnum; ! opt.jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT)); ! term->tl_job = job_start(argvars, &opt); ! } if (term->tl_job == NULL) /* Wiping out the buffer will also close the window. */ do_buffer(DOBUF_WIPE, DOBUF_CURRENT, FORWARD, 0, TRUE); ! /* TODO: Setup pty, see mch_call_shell(). */ } /* *************** *** 220,226 **** job_unref(term->tl_job); } ! vterm_free(term->tl_vterm); vim_free(term); } --- 226,232 ---- job_unref(term->tl_job); } ! term_free(term); vim_free(term); } *************** *** 232,242 **** write_to_term(buf_T *buffer, char_u *msg, channel_T *channel) { size_t len = STRLEN(msg); ! VTerm *vterm = buffer->b_term->tl_vterm; ch_logn(channel, "writing %d bytes to terminal", (int)len); ! vterm_input_write(vterm, (char *)msg, len); ! vterm_screen_flush_damage(vterm_obtain_screen(vterm)); /* TODO: only update once in a while. */ update_screen(0); --- 238,247 ---- write_to_term(buf_T *buffer, char_u *msg, channel_T *channel) { size_t len = STRLEN(msg); ! term_T *term = buffer->b_term; ch_logn(channel, "writing %d bytes to terminal", (int)len); ! term_write_job_output(term, msg, len); /* TODO: only update once in a while. */ update_screen(0); *************** *** 245,288 **** } /* * Called to update the window that contains the terminal. */ void term_update_window(win_T *wp) { ! int vterm_rows; ! int vterm_cols; ! VTerm *vterm = wp->w_buffer->b_term->tl_vterm; ! VTermScreen *screen = vterm_obtain_screen(vterm); ! VTermPos pos; ! vterm_get_size(vterm, &vterm_rows, &vterm_cols); ! /* TODO: Only redraw what changed. */ ! for (pos.row = 0; pos.row < wp->w_height; ++pos.row) ! { ! int off = screen_get_current_line_off(); ! if (pos.row < vterm_rows) ! for (pos.col = 0; pos.col < wp->w_width && pos.col < vterm_cols; ! ++pos.col) ! { ! VTermScreenCell cell; ! int c; ! vterm_screen_get_cell(screen, pos, &cell); ! /* TODO: use cell.attrs and colors */ ! /* TODO: use cell.width */ ! /* TODO: multi-byte chars */ ! c = cell.chars[0]; ! ScreenLines[off] = c == NUL ? ' ' : c; ! ScreenAttrs[off] = 0; ! ++off; ! } ! screen_line(wp->w_winrow + pos.row, wp->w_wincol, pos.col, wp->w_width, ! FALSE); ! } } static int --- 250,422 ---- } /* + * Wait for input and send it to the job. + * Return when a CTRL-W command is typed that moves to another window. + */ + void + terminal_loop(void) + { + char buf[KEY_BUF_LEN]; + int c; + size_t len; + + for (;;) + { + /* TODO: skip screen update when handling a sequence of keys. */ + update_screen(0); + setcursor(); + out_flush(); + c = vgetc(); + + if (c == Ctrl_W) + { + stuffcharReadbuff(Ctrl_W); + return; + } + + /* Convert the typed key to a sequence of bytes for the job. */ + len = term_convert_key(c, buf); + if (len > 0) + /* TODO: if FAIL is returned, stop? */ + channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN, + (char_u *)buf, len, NULL); + } + } + + /* * Called to update the window that contains the terminal. */ void term_update_window(win_T *wp) { ! term_update_lines(wp); ! } ! #ifdef WIN3264 ! /************************************** ! * 2. MS-Windows implementation. ! */ ! /* ! * Create a new terminal of "rows" by "cols" cells. ! * Store a reference in "term". ! * Return OK or FAIL. ! */ ! static int ! term_init(term_T *term, int rows, int cols) ! { ! /* TODO: Create a hidden console */ ! return FAIL; ! } ! /* ! * Free the terminal emulator part of "term". ! */ ! static void ! term_free(term_T *term) ! { ! /* TODO */ ! } ! /* ! * Write job output "msg[len]" to the terminal. ! */ ! static void ! term_write_job_output(term_T *term, char_u *msg, size_t len) ! { ! /* TODO */ ! } ! ! /* ! * Convert typed key "c" into bytes to send to the job. ! * Return the number of bytes in "buf". ! */ ! static int ! term_convert_key(int c, char *buf) ! { ! /* TODO */ ! return 0; ! } ! ! /* ! * Called to update the window that contains the terminal. ! */ ! static void ! term_update_lines(win_T *wp) ! { ! /* TODO */ ! } ! ! #else ! ! /************************************** ! * 3. Unix-like implementation. ! * ! * For a terminal one VTerm is constructed. This uses libvterm. A copy of ! * that library is in the libvterm directory. ! */ ! ! static int handle_damage(VTermRect rect, void *user); ! static int handle_moverect(VTermRect dest, VTermRect src, void *user); ! static int handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user); ! static int handle_resize(int rows, int cols, void *user); ! ! static VTermScreenCallbacks screen_callbacks = { ! handle_damage, /* damage */ ! handle_moverect, /* moverect */ ! handle_movecursor, /* movecursor */ ! NULL, /* settermprop */ ! NULL, /* bell */ ! handle_resize, /* resize */ ! NULL, /* sb_pushline */ ! NULL /* sb_popline */ ! }; ! ! /* ! * Create a new terminal of "rows" by "cols" cells. ! * Store a reference in "term". ! * Return OK or FAIL. ! */ ! static int ! term_init(term_T *term, int rows, int cols) ! { ! VTerm *vterm = vterm_new(rows, cols); ! VTermScreen *screen; ! ! term->tl_vterm = vterm; ! screen = vterm_obtain_screen(vterm); ! vterm_screen_set_callbacks(screen, &screen_callbacks, term); ! /* TODO: depends on 'encoding'. */ ! vterm_set_utf8(vterm, 1); ! /* Required to initialize most things. */ ! vterm_screen_reset(screen, 1 /* hard */); ! ! /* By default NL means CR-NL. */ ! vterm_input_write(vterm, "\x1b[20h", 5); ! ! return OK; ! } ! ! /* ! * Free the terminal emulator part of "term". ! */ ! static void ! term_free(term_T *term) ! { ! vterm_free(term->tl_vterm); ! } ! ! /* ! * Write job output "msg[len]" to the terminal. ! */ ! static void ! term_write_job_output(term_T *term, char_u *msg, size_t len) ! { ! VTerm *vterm = term->tl_vterm; ! ! vterm_input_write(vterm, (char *)msg, len); ! vterm_screen_flush_damage(vterm_obtain_screen(vterm)); } static int *************** *** 344,454 **** return 1; } - /* TODO: Use win_del_lines() to make scroll up efficient. */ - - /* ! * Wait for input and send it to the job. ! * Return when a CTRL-W command is typed that moves to another window. */ ! void ! terminal_loop(void) { ! VTerm *vterm = curbuf->b_term->tl_vterm; ! char buf[200]; ! for (;;) { ! int c; ! VTermKey key = VTERM_KEY_NONE; ! VTermModifier mod = VTERM_MOD_NONE; ! size_t len; ! ! update_screen(0); ! setcursor(); ! out_flush(); ! ! c = vgetc(); ! switch (c) ! { ! case Ctrl_W: ! stuffcharReadbuff(Ctrl_W); ! return; ! ! /* TODO: which of these two should be used? */ #if 0 ! case CAR: key = VTERM_KEY_ENTER; break; #else ! case CAR: c = NL; break; #endif ! case ESC: key = VTERM_KEY_ESCAPE; break; ! case K_BS: key = VTERM_KEY_BACKSPACE; break; ! case K_DEL: key = VTERM_KEY_DEL; break; ! case K_DOWN: key = VTERM_KEY_DOWN; break; ! case K_END: key = VTERM_KEY_END; break; ! case K_F10: key = VTERM_KEY_FUNCTION(10); break; ! case K_F11: key = VTERM_KEY_FUNCTION(11); break; ! case K_F12: key = VTERM_KEY_FUNCTION(12); break; ! case K_F1: key = VTERM_KEY_FUNCTION(1); break; ! case K_F2: key = VTERM_KEY_FUNCTION(2); break; ! case K_F3: key = VTERM_KEY_FUNCTION(3); break; ! case K_F4: key = VTERM_KEY_FUNCTION(4); break; ! case K_F5: key = VTERM_KEY_FUNCTION(5); break; ! case K_F6: key = VTERM_KEY_FUNCTION(6); break; ! case K_F7: key = VTERM_KEY_FUNCTION(7); break; ! case K_F8: key = VTERM_KEY_FUNCTION(8); break; ! case K_F9: key = VTERM_KEY_FUNCTION(9); break; ! case K_HOME: key = VTERM_KEY_HOME; break; ! case K_INS: key = VTERM_KEY_INS; break; ! case K_K0: key = VTERM_KEY_KP_0; break; ! case K_K1: key = VTERM_KEY_KP_1; break; ! case K_K2: key = VTERM_KEY_KP_2; break; ! case K_K3: key = VTERM_KEY_KP_3; break; ! case K_K4: key = VTERM_KEY_KP_4; break; ! case K_K5: key = VTERM_KEY_KP_5; break; ! case K_K6: key = VTERM_KEY_KP_6; break; ! case K_K7: key = VTERM_KEY_KP_7; break; ! case K_K8: key = VTERM_KEY_KP_8; break; ! case K_K9: key = VTERM_KEY_KP_9; break; ! case K_KDEL: key = VTERM_KEY_DEL; break; /* TODO */ ! case K_KDIVIDE: key = VTERM_KEY_KP_DIVIDE; break; ! case K_KEND: key = VTERM_KEY_KP_1; break; /* TODO */ ! case K_KENTER: key = VTERM_KEY_KP_ENTER; break; ! case K_KHOME: key = VTERM_KEY_KP_7; break; /* TODO */ ! case K_KINS: key = VTERM_KEY_KP_0; break; /* TODO */ ! case K_KMINUS: key = VTERM_KEY_KP_MINUS; break; ! case K_KMULTIPLY: key = VTERM_KEY_KP_MULT; break; ! case K_KPAGEDOWN: key = VTERM_KEY_KP_3; break; /* TODO */ ! case K_KPAGEUP: key = VTERM_KEY_KP_9; break; /* TODO */ ! case K_KPLUS: key = VTERM_KEY_KP_PLUS; break; ! case K_KPOINT: key = VTERM_KEY_KP_PERIOD; break; ! case K_LEFT: key = VTERM_KEY_LEFT; break; ! case K_PAGEDOWN: key = VTERM_KEY_PAGEDOWN; break; ! case K_PAGEUP: key = VTERM_KEY_PAGEUP; break; ! case K_RIGHT: key = VTERM_KEY_RIGHT; break; ! case K_UP: key = VTERM_KEY_UP; break; ! case TAB: key = VTERM_KEY_TAB; break; ! } ! /* ! * Convert special keys to vterm keys: ! * - Write keys to vterm: vterm_keyboard_key() ! * - Write output to channel. ! */ ! if (key != VTERM_KEY_NONE) ! /* Special key, let vterm convert it. */ ! vterm_keyboard_key(vterm, key, mod); ! else ! /* Normal character, let vterm convert it. */ ! vterm_keyboard_unichar(vterm, c, mod); ! /* Read back the converted escape sequence. */ ! len = vterm_output_read(vterm, buf, sizeof(buf)); ! /* TODO: if FAIL is returned, stop? */ ! channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN, ! (char_u *)buf, len, NULL); } } #endif /* FEAT_TERMINAL */ --- 478,608 ---- return 1; } /* ! * Convert typed key "c" into bytes to send to the job. ! * Return the number of bytes in "buf". */ ! static int ! term_convert_key(int c, char *buf) { ! VTerm *vterm = curbuf->b_term->tl_vterm; ! VTermKey key = VTERM_KEY_NONE; ! VTermModifier mod = VTERM_MOD_NONE; ! switch (c) { ! /* TODO: which of these two should be used? */ #if 0 ! case CAR: key = VTERM_KEY_ENTER; break; #else ! case CAR: c = NL; break; #endif ! case ESC: key = VTERM_KEY_ESCAPE; break; ! case K_BS: key = VTERM_KEY_BACKSPACE; break; ! case K_DEL: key = VTERM_KEY_DEL; break; ! case K_DOWN: key = VTERM_KEY_DOWN; break; ! case K_END: key = VTERM_KEY_END; break; ! case K_F10: key = VTERM_KEY_FUNCTION(10); break; ! case K_F11: key = VTERM_KEY_FUNCTION(11); break; ! case K_F12: key = VTERM_KEY_FUNCTION(12); break; ! case K_F1: key = VTERM_KEY_FUNCTION(1); break; ! case K_F2: key = VTERM_KEY_FUNCTION(2); break; ! case K_F3: key = VTERM_KEY_FUNCTION(3); break; ! case K_F4: key = VTERM_KEY_FUNCTION(4); break; ! case K_F5: key = VTERM_KEY_FUNCTION(5); break; ! case K_F6: key = VTERM_KEY_FUNCTION(6); break; ! case K_F7: key = VTERM_KEY_FUNCTION(7); break; ! case K_F8: key = VTERM_KEY_FUNCTION(8); break; ! case K_F9: key = VTERM_KEY_FUNCTION(9); break; ! case K_HOME: key = VTERM_KEY_HOME; break; ! case K_INS: key = VTERM_KEY_INS; break; ! case K_K0: key = VTERM_KEY_KP_0; break; ! case K_K1: key = VTERM_KEY_KP_1; break; ! case K_K2: key = VTERM_KEY_KP_2; break; ! case K_K3: key = VTERM_KEY_KP_3; break; ! case K_K4: key = VTERM_KEY_KP_4; break; ! case K_K5: key = VTERM_KEY_KP_5; break; ! case K_K6: key = VTERM_KEY_KP_6; break; ! case K_K7: key = VTERM_KEY_KP_7; break; ! case K_K8: key = VTERM_KEY_KP_8; break; ! case K_K9: key = VTERM_KEY_KP_9; break; ! case K_KDEL: key = VTERM_KEY_DEL; break; /* TODO */ ! case K_KDIVIDE: key = VTERM_KEY_KP_DIVIDE; break; ! case K_KEND: key = VTERM_KEY_KP_1; break; /* TODO */ ! case K_KENTER: key = VTERM_KEY_KP_ENTER; break; ! case K_KHOME: key = VTERM_KEY_KP_7; break; /* TODO */ ! case K_KINS: key = VTERM_KEY_KP_0; break; /* TODO */ ! case K_KMINUS: key = VTERM_KEY_KP_MINUS; break; ! case K_KMULTIPLY: key = VTERM_KEY_KP_MULT; break; ! case K_KPAGEDOWN: key = VTERM_KEY_KP_3; break; /* TODO */ ! case K_KPAGEUP: key = VTERM_KEY_KP_9; break; /* TODO */ ! case K_KPLUS: key = VTERM_KEY_KP_PLUS; break; ! case K_KPOINT: key = VTERM_KEY_KP_PERIOD; break; ! case K_LEFT: key = VTERM_KEY_LEFT; break; ! case K_PAGEDOWN: key = VTERM_KEY_PAGEDOWN; break; ! case K_PAGEUP: key = VTERM_KEY_PAGEUP; break; ! case K_RIGHT: key = VTERM_KEY_RIGHT; break; ! case K_UP: key = VTERM_KEY_UP; break; ! case TAB: key = VTERM_KEY_TAB; break; ! } ! ! /* ! * Convert special keys to vterm keys: ! * - Write keys to vterm: vterm_keyboard_key() ! * - Write output to channel. ! */ ! if (key != VTERM_KEY_NONE) ! /* Special key, let vterm convert it. */ ! vterm_keyboard_key(vterm, key, mod); ! else ! /* Normal character, let vterm convert it. */ ! vterm_keyboard_unichar(vterm, c, mod); ! /* Read back the converted escape sequence. */ ! return vterm_output_read(vterm, buf, KEY_BUF_LEN); ! } ! /* ! * Called to update the window that contains the terminal. ! */ ! static void ! term_update_lines(win_T *wp) ! { ! int vterm_rows; ! int vterm_cols; ! VTerm *vterm = wp->w_buffer->b_term->tl_vterm; ! VTermScreen *screen = vterm_obtain_screen(vterm); ! VTermPos pos; ! vterm_get_size(vterm, &vterm_rows, &vterm_cols); ! ! /* TODO: Only redraw what changed. */ ! for (pos.row = 0; pos.row < wp->w_height; ++pos.row) ! { ! int off = screen_get_current_line_off(); ! ! if (pos.row < vterm_rows) ! for (pos.col = 0; pos.col < wp->w_width && pos.col < vterm_cols; ! ++pos.col) ! { ! VTermScreenCell cell; ! int c; ! ! vterm_screen_get_cell(screen, pos, &cell); ! /* TODO: use cell.attrs and colors */ ! /* TODO: use cell.width */ ! /* TODO: multi-byte chars */ ! c = cell.chars[0]; ! ScreenLines[off] = c == NUL ? ' ' : c; ! ScreenAttrs[off] = 0; ! ++off; ! } ! ! screen_line(wp->w_winrow + pos.row, wp->w_wincol, pos.col, wp->w_width, ! FALSE); } } + #endif + #endif /* FEAT_TERMINAL */ *** ../vim-8.0.0729/src/version.c 2017-07-18 21:33:16.354319501 +0200 --- src/version.c 2017-07-18 22:42:39.423860618 +0200 *************** *** 771,772 **** --- 771,774 ---- { /* Add new patch number below this line */ + /**/ + 730, /**/ -- hundred-and-one symptoms of being an internet addict: 179. You wonder why your household garbage can doesn't have an "empty recycle bin" button. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///