To: vim_dev@googlegroups.com Subject: Patch 8.0.0693 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.0693 Problem: No terminal emulator support. Cannot properly run commands in the GUI. Cannot run a job interactively with an ssh connection. Solution: Very early implementation of the :terminal command. Includes libvterm converted to ANSI C. Many parts still missing. Files: src/feature.h, src/Makefile, src/configure.ac, src/auto/configure, src/config.mk.in, src/config.h.in, src/terminal.c, src/structs.h, src/ex_cmdidxs.h, src/ex_docmd.c, src/option.c, src/option.h, src/evalfunc.c, src/proto/terminal.pro, src/proto.h, runtime/doc/terminal.txt, runtime/doc/Makefile, Filelist, src/libvterm/.bzrignore, src/libvterm/.gitignore, src/libvterm/LICENSE, src/libvterm/README, src/libvterm/Makefile, src/libvterm/tbl2inc_c.pl, src/libvterm/vterm.pc.in, src/libvterm/bin/unterm.c, src/libvterm/bin/vterm-ctrl.c, src/libvterm/bin/vterm-dump.c, src/libvterm/doc/URLs, src/libvterm/doc/seqs.txt, src/libvterm/include/vterm.h, src/libvterm/include/vterm_keycodes.h, src/libvterm/src/encoding.c, src/libvterm/src/encoding/DECdrawing.inc, src/libvterm/src/encoding/DECdrawing.tbl, src/libvterm/src/encoding/uk.inc, src/libvterm/src/encoding/uk.tbl, src/libvterm/src/keyboard.c, src/libvterm/src/mouse.c, src/libvterm/src/parser.c, src/libvterm/src/pen.c, src/libvterm/src/rect.h, src/libvterm/src/screen.c, src/libvterm/src/state.c, src/libvterm/src/unicode.c, src/libvterm/src/utf8.h, src/libvterm/src/vterm.c, src/libvterm/src/vterm_internal.h, src/libvterm/t/02parser.test, src/libvterm/t/03encoding_utf8.test, src/libvterm/t/10state_putglyph.test, src/libvterm/t/11state_movecursor.test, src/libvterm/t/12state_scroll.test, src/libvterm/t/13state_edit.test, src/libvterm/t/14state_encoding.test, src/libvterm/t/15state_mode.test, src/libvterm/t/16state_resize.test, src/libvterm/t/17state_mouse.test, src/libvterm/t/18state_termprops.test, src/libvterm/t/20state_wrapping.test, src/libvterm/t/21state_tabstops.test, src/libvterm/t/22state_save.test, src/libvterm/t/25state_input.test, src/libvterm/t/26state_query.test, src/libvterm/t/27state_reset.test, src/libvterm/t/28state_dbl_wh.test, src/libvterm/t/29state_fallback.test, src/libvterm/t/30pen.test, src/libvterm/t/40screen_ascii.test, src/libvterm/t/41screen_unicode.test, src/libvterm/t/42screen_damage.test, src/libvterm/t/43screen_resize.test, src/libvterm/t/44screen_pen.test, src/libvterm/t/45screen_protect.test, src/libvterm/t/46screen_extent.test, src/libvterm/t/47screen_dbl_wh.test, src/libvterm/t/48screen_termprops.test, src/libvterm/t/90vttest_01-movement-1.test, src/libvterm/t/90vttest_01-movement-2.test, src/libvterm/t/90vttest_01-movement-3.test, src/libvterm/t/90vttest_01-movement-4.test, src/libvterm/t/90vttest_02-screen-1.test, src/libvterm/t/90vttest_02-screen-2.test, src/libvterm/t/90vttest_02-screen-3.test, src/libvterm/t/90vttest_02-screen-4.test, src/libvterm/t/92lp1640917.test, src/libvterm/t/harness.c, src/libvterm/t/run-test.pl *** ../vim-8.0.0692/src/feature.h 2016-09-06 21:18:24.000000000 +0200 --- src/feature.h 2017-07-02 22:29:20.089251944 +0200 *************** *** 1268,1273 **** --- 1268,1280 ---- #endif /* + * +terminal ":terminal" command. Runs a terminal in a window. + */ + #if !defined(FEAT_JOB_CHANNEL) && defined(FEAT_TERMINAL) + # undef FEAT_TERMINAL + #endif + + /* * +signs Allow signs to be displayed to the left of text lines. * Adds the ":sign" command. */ *** ../vim-8.0.0692/src/Makefile 2017-06-27 18:28:52.558196805 +0200 --- src/Makefile 2017-07-04 22:11:20.997610053 +0200 *************** *** 482,487 **** --- 482,492 ---- # Uncomment this when you do not want inter process communication. #CONF_OPT_CHANNEL = --disable-channel + # TERMINAL - Terminal emulator support, :terminal command. Requires the + # channel feature. + # Uncomment this when you want terminal emulator support. + #CONF_OPT_TERMINAL = --enable-terminal + # MULTIBYTE - To edit multi-byte characters. # Uncomment this when you want to edit a multibyte language. # It's automatically enabled with normal features, GTK or IME support. *************** *** 598,603 **** --- 603,611 ---- # Use this with GCC to check for mistakes, unused arguments, etc. #CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 + # Add -Wpedantic to find // comments and other C99 constructs. + # Better disable Perl and Python to avoid a lot of warnings. + #CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 #CFLAGS = -g -O2 -Wall -Wextra -Wmissing-prototypes -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -DU_DEBUG #PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers #MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter *************** *** 1371,1376 **** --- 1379,1391 ---- # }}} + TERM_DEPS = \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h \ + libvterm/src/rect.h \ + libvterm/src/utf8.h \ + libvterm/src/vterm_internal.h + ### Command to create dependencies based on #include "..." ### prototype headers are ignored due to -DPROTO, system ### headers #include <...> are ignored if we use the -MM option, as *************** *** 1560,1565 **** --- 1575,1581 ---- syntax.c \ tag.c \ term.c \ + terminal.c \ ui.c \ undo.c \ userfunc.c \ *************** *** 1569,1574 **** --- 1585,1591 ---- SRC = $(BASIC_SRC) \ $(GUI_SRC) \ + $(TERM_SRC) \ $(HANGULIN_SRC) \ $(LUA_SRC) \ $(MZSCHEME_SRC) \ *************** *** 1610,1616 **** LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) \ $(PYTHON_SRC) $(PYTHON3_SRC) $(TCL_SRC) \ $(WORKSHOP_SRC) $(WSDEBUG_SRC) \ ! $(NETBEANS_SRC) $(CHANNEL_SRC) #LINT_SRC = $(SRC) #LINT_SRC = $(ALL_SRC) #LINT_SRC = $(BASIC_SRC) --- 1627,1633 ---- LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) \ $(PYTHON_SRC) $(PYTHON3_SRC) $(TCL_SRC) \ $(WORKSHOP_SRC) $(WSDEBUG_SRC) \ ! $(NETBEANS_SRC) $(CHANNEL_SRC) $(TERM_SRC) #LINT_SRC = $(SRC) #LINT_SRC = $(ALL_SRC) #LINT_SRC = $(BASIC_SRC) *************** *** 1665,1676 **** --- 1682,1695 ---- objects/syntax.o \ objects/tag.o \ objects/term.o \ + objects/terminal.o \ objects/ui.o \ objects/undo.o \ objects/userfunc.o \ objects/version.o \ objects/window.o \ $(GUI_OBJ) \ + $(TERM_OBJ) \ $(LUA_OBJ) \ $(MZSCHEME_OBJ) \ $(PERL_OBJ) \ *************** *** 1795,1800 **** --- 1814,1820 ---- syntax.pro \ tag.pro \ term.pro \ + terminal.pro \ termlib.pro \ ui.pro \ undo.pro \ *************** *** 1848,1854 **** $(CONF_OPT_OUTPUT) $(CONF_OPT_GPM) $(CONF_OPT_WORKSHOP) \ $(CONF_OPT_FEAT) $(CONF_TERM_LIB) \ $(CONF_OPT_COMPBY) $(CONF_OPT_ACL) $(CONF_OPT_NETBEANS) \ ! $(CONF_OPT_CHANNEL) \ $(CONF_ARGS) $(CONF_OPT_MZSCHEME) $(CONF_OPT_PLTHOME) \ $(CONF_OPT_LUA) $(CONF_OPT_LUA_PREFIX) \ $(CONF_OPT_SYSMOUSE); \ --- 1868,1874 ---- $(CONF_OPT_OUTPUT) $(CONF_OPT_GPM) $(CONF_OPT_WORKSHOP) \ $(CONF_OPT_FEAT) $(CONF_TERM_LIB) \ $(CONF_OPT_COMPBY) $(CONF_OPT_ACL) $(CONF_OPT_NETBEANS) \ ! $(CONF_OPT_CHANNEL) $(CONF_OPT_TERMINAL) \ $(CONF_ARGS) $(CONF_OPT_MZSCHEME) $(CONF_OPT_PLTHOME) \ $(CONF_OPT_LUA) $(CONF_OPT_LUA_PREFIX) \ $(CONF_OPT_SYSMOUSE); \ *************** *** 3228,3233 **** --- 3248,3256 ---- objects/term.o: term.c $(CCC) -o $@ term.c + objects/terminal.o: terminal.c $(TERM_DEPS) + $(CCC) -o $@ terminal.c + objects/ui.o: ui.c $(CCC) -o $@ ui.c *************** *** 3255,3260 **** --- 3278,3311 ---- Makefile: @echo The name of the makefile MUST be "Makefile" (with capital M)!!!! + CCCTERM = $(CCC) -Ilibvterm/include -DINLINE="" + objects/term_encoding.o: libvterm/src/encoding.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/encoding.c + + objects/term_keyboard.o: libvterm/src/keyboard.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/keyboard.c + + objects/term_mouse.o: libvterm/src/mouse.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/mouse.c + + objects/term_parser.o: libvterm/src/parser.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/parser.c + + objects/term_pen.o: libvterm/src/pen.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/pen.c + + objects/term_screen.o: libvterm/src/screen.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/screen.c + + objects/term_state.o: libvterm/src/state.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/state.c + + objects/term_unicode.o: libvterm/src/unicode.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/unicode.c + + objects/term_vterm.o: libvterm/src/vterm.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/vterm.c + ############################################################################### ### MacOS X installation ### *************** *** 3399,3405 **** objects/ex_docmd.o: ex_docmd.c vim.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \ regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h \ ! proto.h globals.h farsi.h arabic.h objects/ex_eval.o: ex_eval.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \ gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ --- 3450,3456 ---- objects/ex_docmd.o: ex_docmd.c vim.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \ regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h \ ! proto.h globals.h farsi.h arabic.h ex_cmdidxs.h objects/ex_eval.o: ex_eval.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \ gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ *** ../vim-8.0.0692/src/configure.ac 2017-06-05 15:07:04.940381608 +0200 --- src/configure.ac 2017-07-02 22:37:03.417763467 +0200 *************** *** 2028,2033 **** --- 2028,2055 ---- AC_SUBST(CHANNEL_OBJ) fi + AC_MSG_CHECKING(--enable-terminal argument) + AC_ARG_ENABLE(terminal, + [ --enable-terminal Disable terminal emulation support.], + [enable_terminal="yes"], ) + if test "$enable_terminal" = "yes"; then + if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then + AC_MSG_RESULT([cannot use terminal emulator with tiny or small features]) + enable_terminal="no" + else + AC_MSG_RESULT(yes) + fi + else + AC_MSG_RESULT(no) + fi + if test "$enable_terminal" = "yes"; then + AC_DEFINE(FEAT_TERMINAL) + TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/screen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c" + AC_SUBST(TERM_SRC) + TERM_OBJ="objects/term_encoding.o objects/term_keyboard.o objects/term_mouse.o objects/term_parser.o objects/term_pen.o objects/term_screen.o objects/term_state.o objects/term_unicode.o objects/term_vterm.o" + AC_SUBST(TERM_OBJ) + fi + AC_MSG_CHECKING(--enable-multibyte argument) AC_ARG_ENABLE(multibyte, [ --enable-multibyte Include multibyte editing support.], , *** ../vim-8.0.0692/src/auto/configure 2017-06-05 15:07:04.944381581 +0200 --- src/auto/configure 2017-07-02 22:37:07.625731803 +0200 *************** *** 655,660 **** --- 655,662 ---- X_CFLAGS XMKMF xmkmfpath + TERM_OBJ + TERM_SRC CHANNEL_OBJ CHANNEL_SRC NETBEANS_OBJ *************** *** 814,819 **** --- 816,822 ---- enable_workshop enable_netbeans enable_channel + enable_terminal enable_multibyte enable_hangulinput enable_xim *************** *** 1491,1496 **** --- 1494,1500 ---- --enable-workshop Include Sun Visual Workshop support. --disable-netbeans Disable NetBeans integration support. --disable-channel Disable process communication support. + --enable-terminal Disable terminal emulation support. --enable-multibyte Include multibyte editing support. --enable-hangulinput Include Hangul input support. --enable-xim Include XIM input support. *************** *** 7464,7469 **** --- 7468,7502 ---- fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-terminal argument" >&5 + $as_echo_n "checking --enable-terminal argument... " >&6; } + # Check whether --enable-terminal was given. + if test "${enable_terminal+set}" = set; then : + enableval=$enable_terminal; enable_terminal="yes" + fi + + if test "$enable_terminal" = "yes"; then + if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use terminal emulator with tiny or small features" >&5 + $as_echo "cannot use terminal emulator with tiny or small features" >&6; } + enable_terminal="no" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + $as_echo "yes" >&6; } + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + $as_echo "no" >&6; } + fi + if test "$enable_terminal" = "yes"; then + $as_echo "#define FEAT_TERMINAL 1" >>confdefs.h + + TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/screen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c" + + TERM_OBJ="objects/term_encoding.o objects/term_keyboard.o objects/term_mouse.o objects/term_parser.o objects/term_pen.o objects/term_screen.o objects/term_state.o objects/term_unicode.o objects/term_vterm.o" + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-multibyte argument" >&5 $as_echo_n "checking --enable-multibyte argument... " >&6; } # Check whether --enable-multibyte was given. *** ../vim-8.0.0692/src/config.mk.in 2017-04-21 22:59:58.377385472 +0200 --- src/config.mk.in 2017-07-02 22:27:35.678038649 +0200 *************** *** 91,96 **** --- 91,98 ---- NETBEANS_OBJ = @NETBEANS_OBJ@ CHANNEL_SRC = @CHANNEL_SRC@ CHANNEL_OBJ = @CHANNEL_OBJ@ + TERM_SRC = @TERM_SRC@ + TERM_OBJ = @TERM_OBJ@ RUBY = @vi_cv_path_ruby@ RUBY_SRC = @RUBY_SRC@ *** ../vim-8.0.0692/src/config.h.in 2017-06-05 15:07:04.936381636 +0200 --- src/config.h.in 2017-07-02 22:28:16.653729883 +0200 *************** *** 431,436 **** --- 431,439 ---- /* Define if you want to include process communication. */ #undef FEAT_JOB_CHANNEL + /* Define if you want to include terminal emulator support. */ + #undef FEAT_TERMINAL + /* Define default global runtime path */ #undef RUNTIME_GLOBAL *** ../vim-8.0.0692/src/terminal.c 2017-07-07 11:50:22.453319069 +0200 --- src/terminal.c 2017-07-04 22:41:06.588126047 +0200 *************** *** 0 **** --- 1,211 ---- + /* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + + /* + * 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 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: + * - +terminal in features[] in version.c + * - free b_term when closing terminal. + * - remove term from first_term list when closing terminal. + * - set buffer options to be scratch, hidden, nomodifiable, etc. + * - set buffer name to command, add (1) to avoid duplicates. + * - command line completion (command name) + * - support fixed size when 'termsize' is "rowsXcols". + * - support minimal size when 'termsize' is "rows*cols". + * - support minimal size when 'termsize' is empty. + * - implement ":buf {term-buf-name}" + * - implement term_getsize() + * - implement term_setsize() + * - implement term_sendkeys() send keystrokes to a terminal + * - implement term_wait() wait for screen to be updated + * - implement term_scrape() inspect terminal screen + * - implement term_open() open terminal window + * - implement term_getjob() + */ + + #include "vim.h" + + #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; + + /* Range of screen rows to update. Zero based. */ + int tl_dirty_row_start; /* -1 if nothing dirty */ + int tl_dirty_row_end; /* row below last one to update */ + + pos_T tl_cursor; + }; + + #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. + */ + void + ex_terminal(exarg_T *eap) + { + int rows; + int cols; + exarg_T split_ea; + win_T *old_curwin = curwin; + typval_T argvars[2]; + term_T *term; + VTerm *vterm; + VTermScreen *screen; + + if (check_restricted() || check_secure()) + return; + + term = (term_T *)alloc_clear(sizeof(term_T)); + if (term == NULL) + return; + term->tl_dirty_row_end = MAX_ROW; + + /* Open a new window or tab. */ + vim_memset(&split_ea, 0, sizeof(split_ea)); + split_ea.cmdidx = CMD_new; + split_ea.cmd = (char_u *)"new"; + split_ea.arg = (char_u *)""; + ex_splitview(&split_ea); + if (curwin == old_curwin) + { + /* split failed */ + vim_free(term); + return; + } + + curbuf->b_term = term; + term->tl_next = first_term; + first_term = term; + + /* TODO: set buffer type, hidden, etc. */ + + if (*curwin->w_p_tms != NUL) + { + char_u *p = vim_strchr(curwin->w_p_tms, 'x') + 1; + + rows = atoi((char *)curwin->w_p_tms); + cols = atoi((char *)p); + /* TODO: resize window if possible. */ + } + else + { + rows = curwin->w_height; + 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); + + argvars[0].v_type = VAR_STRING; + argvars[0].vval.v_string = eap->arg; + argvars[1].v_type = VAR_UNKNOWN; + term->tl_job = job_start(argvars); + + /* TODO: setup channels to/from job */ + /* Setup pty, see mch_call_shell(). */ + } + + static int + handle_damage(VTermRect rect, void *user) + { + term_T *term = (term_T *)user; + + term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row); + term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row); + return 1; + } + + static int + handle_moverect(VTermRect dest, VTermRect src, void *user) + { + /* TODO */ + return 1; + } + + static int + handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) + { + /* TODO: handle moving the cursor. */ + return 1; + } + + static int + handle_resize(int rows, int cols, void *user) + { + /* TODO: handle terminal resize. */ + return 1; + } + + /* TODO: Use win_del_lines() to make scroll up efficient. */ + + /* TODO: function to update the window. + * Get the screen contents from vterm with vterm_screen_get_cell(). + * put in current_ScreenLine and call screen_line(). + */ + + /* TODO: function to wait for input and send it to the job. + * Return when a CTRL-W command is typed that moves to another window. + * Convert special keys to vterm keys: + * - Write keys to vterm: vterm_keyboard_key() + * - read the output (xterm escape sequences): vterm_output_read() + * - Write output to channel. + */ + + /* TODO: function to read job output from the channel. + * write to vterm: vterm_input_write() + * This will invoke screen callbacks. + * call vterm_screen_flush_damage() + */ + + #endif /* FEAT_TERMINAL */ *** ../vim-8.0.0692/src/structs.h 2017-06-18 22:40:36.516444715 +0200 --- src/structs.h 2017-07-02 20:32:42.065678341 +0200 *************** *** 68,73 **** --- 68,74 ---- typedef struct frame_S frame_T; typedef int scid_T; /* script ID */ typedef struct file_buffer buf_T; /* forward declaration */ + typedef struct terminal_S term_T; /* * Reference to a buffer that stores the value of buf_free_count. *************** *** 268,273 **** --- 269,278 ---- char_u *wo_scl; # define w_p_scl w_onebuf_opt.wo_scl /* 'signcolumn' */ #endif + #ifdef FEAT_TERMINAL + char_u *wo_tms; + #define w_p_tms w_onebuf_opt.wo_tms /* 'termsize' */ + #endif #ifdef FEAT_EVAL int wo_scriptID[WV_COUNT]; /* SIDs for window-local options */ *************** *** 2351,2356 **** --- 2356,2366 ---- #endif int b_mapped_ctrl_c; /* modes where CTRL-C is mapped */ + #ifdef FEAT_TERMINAL + term_T *b_term; /* When not NULL this buffer is for a terminal + * window. */ + #endif + }; /* file_buffer */ *** ../vim-8.0.0692/src/ex_cmdidxs.h 2017-04-20 21:55:23.315604275 +0200 --- src/ex_cmdidxs.h 2017-07-02 22:40:46.432085750 +0200 *************** *** 25,36 **** /* r */ 351, /* s */ 370, /* t */ 437, ! /* u */ 472, ! /* v */ 483, ! /* w */ 501, ! /* x */ 516, ! /* y */ 525, ! /* z */ 526 }; /* --- 25,36 ---- /* r */ 351, /* s */ 370, /* t */ 437, ! /* u */ 473, ! /* v */ 484, ! /* w */ 502, ! /* x */ 517, ! /* y */ 526, ! /* z */ 527 }; /* *************** *** 60,66 **** /* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 18, 0, 0, 0, 0 }, /* s */ { 2, 6, 15, 0, 18, 22, 0, 24, 25, 0, 0, 28, 30, 34, 38, 40, 0, 48, 0, 49, 0, 61, 62, 0, 63, 0 }, ! /* t */ { 2, 0, 19, 0, 22, 23, 0, 24, 0, 25, 0, 26, 27, 28, 29, 30, 0, 31, 33, 0, 34, 0, 0, 0, 0, 0 }, /* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* v */ { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 12, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0 }, /* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 12, 0, 13, 14, 0, 0, 0, 0 }, --- 60,66 ---- /* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 18, 0, 0, 0, 0 }, /* s */ { 2, 6, 15, 0, 18, 22, 0, 24, 25, 0, 0, 28, 30, 34, 38, 40, 0, 48, 0, 49, 0, 61, 62, 0, 63, 0 }, ! /* t */ { 2, 0, 19, 0, 22, 24, 0, 25, 0, 26, 0, 27, 28, 29, 30, 31, 0, 32, 34, 0, 35, 0, 0, 0, 0, 0 }, /* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* v */ { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 12, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0 }, /* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 12, 0, 13, 14, 0, 0, 0, 0 }, *************** *** 69,72 **** /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; ! static const int command_count = 539; --- 69,72 ---- /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; ! static const int command_count = 540; *** ../vim-8.0.0692/src/ex_docmd.c 2017-06-22 20:39:13.389435271 +0200 --- src/ex_docmd.c 2017-07-04 22:12:45.560963366 +0200 *************** *** 488,493 **** --- 488,496 ---- #ifndef FEAT_PROFILE # define ex_profile ex_ni #endif + #ifndef FEAT_TERMINAL + # define ex_terminal ex_ni + #endif /* * Declare cmdnames[]. *** ../vim-8.0.0692/src/option.c 2017-06-25 20:56:41.005213752 +0200 --- src/option.c 2017-07-02 20:07:33.564709028 +0200 *************** *** 257,262 **** --- 257,265 ---- # define PV_COCU OPT_WIN(WV_COCU) # define PV_COLE OPT_WIN(WV_COLE) #endif + #ifdef FEAT_TERMINAL + # define PV_TMS OPT_WIN(WV_TMS) + #endif #ifdef FEAT_SIGNS # define PV_SCL OPT_WIN(WV_SCL) #endif *************** *** 2778,2783 **** --- 2781,2795 ---- {(char_u *)FALSE, (char_u *)FALSE} #endif SCRIPTID_INIT}, + {"termsize", "tms", P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF, + #ifdef FEAT_TERMINAL + (char_u *)VAR_WIN, PV_TMS, + {(char_u *)"", (char_u *)NULL} + #else + (char_u *)NULL, PV_NONE, + {(char_u *)NULL, (char_u *)0L} + #endif + SCRIPTID_INIT}, {"terse", NULL, P_BOOL|P_VI_DEF, (char_u *)&p_terse, PV_NONE, {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, *************** *** 10662,10669 **** case PV_CRBIND: return (char_u *)&(curwin->w_p_crb); #endif #ifdef FEAT_CONCEAL ! case PV_COCU: return (char_u *)&(curwin->w_p_cocu); ! case PV_COLE: return (char_u *)&(curwin->w_p_cole); #endif case PV_AI: return (char_u *)&(curbuf->b_p_ai); --- 10674,10684 ---- case PV_CRBIND: return (char_u *)&(curwin->w_p_crb); #endif #ifdef FEAT_CONCEAL ! case PV_COCU: return (char_u *)&(curwin->w_p_cocu); ! case PV_COLE: return (char_u *)&(curwin->w_p_cole); ! #endif ! #ifdef FEAT_TERMINAL ! case PV_TMS: return (char_u *)&(curwin->w_p_tms); #endif case PV_AI: return (char_u *)&(curbuf->b_p_ai); *************** *** 10871,10876 **** --- 10886,10894 ---- to->wo_cocu = vim_strsave(from->wo_cocu); to->wo_cole = from->wo_cole; #endif + #ifdef FEAT_TERMINAL + to->wo_tms = vim_strsave(from->wo_tms); + #endif #ifdef FEAT_FOLDING to->wo_fdc = from->wo_fdc; to->wo_fdc_save = from->wo_fdc_save; *************** *** 10937,10942 **** --- 10955,10963 ---- #ifdef FEAT_CONCEAL check_string_option(&wop->wo_cocu); #endif + #ifdef FEAT_TERMINAL + check_string_option(&wop->wo_tms); + #endif #ifdef FEAT_LINEBREAK check_string_option(&wop->wo_briopt); #endif *************** *** 10976,10981 **** --- 10997,11005 ---- #ifdef FEAT_CONCEAL clear_string_option(&wop->wo_cocu); #endif + #ifdef FEAT_TERMINAL + clear_string_option(&wop->wo_tms); + #endif } /* *** ../vim-8.0.0692/src/option.h 2017-03-05 17:43:10.620245573 +0100 --- src/option.h 2017-07-02 20:09:02.648057974 +0200 *************** *** 1130,1135 **** --- 1130,1138 ---- , WV_COCU , WV_COLE #endif + #ifdef FEAT_TERMINAL + , WV_TMS + #endif #ifdef FEAT_CURSORBIND , WV_CRBIND #endif *** ../vim-8.0.0692/src/evalfunc.c 2017-06-25 20:56:41.001213784 +0200 --- src/evalfunc.c 2017-07-04 22:14:51.028013393 +0200 *************** *** 5870,5875 **** --- 5870,5878 ---- #ifdef FEAT_TERMGUICOLORS "termguicolors", #endif + #ifdef FEAT_TERMINAL + "terminal", + #endif #ifdef TERMINFO "terminfo", #endif *** ../vim-8.0.0692/src/proto/terminal.pro 2017-07-07 11:50:22.521318544 +0200 --- src/proto/terminal.pro 2017-07-02 20:11:11.911123584 +0200 *************** *** 0 **** --- 1,3 ---- + /* terminal.c */ + void ex_terminal(exarg_T *eap); + /* vim: set ft=c : */ *** ../vim-8.0.0692/src/proto.h 2016-08-29 22:42:20.000000000 +0200 --- src/proto.h 2017-07-02 20:12:00.814770098 +0200 *************** *** 162,167 **** --- 162,170 ---- # include "syntax.pro" # include "tag.pro" # include "term.pro" + # ifdef FEAT_TERMINAL + # include "terminal.pro" + # endif # if defined(HAVE_TGETENT) && (defined(AMIGA) || defined(VMS)) # include "termlib.pro" # endif *** ../vim-8.0.0692/runtime/doc/terminal.txt 2017-07-07 11:50:22.529318484 +0200 --- runtime/doc/terminal.txt 2017-07-04 22:38:39.953236302 +0200 *************** *** 0 **** --- 1,130 ---- + *terminal.txt* For Vim version 8.0. Last change: 2017 Jul 04 + + + VIM REFERENCE MANUAL by Bram Moolenaar + + + Terminal window support *terminal* + + + WARNING: THIS IS ONLY PARTLY IMPLEMENTED, ANYTHING CAN STILL CHANGE + + + 1. Basic use |terminal-use| + 2. Remote testing |terminal-testing| + 3. Debugging |terminal-debug| + + {Vi does not have any of these commands} + + ============================================================================== + 1. Basic use *terminal-use* + + This feature is for running a terminal emulator in a Vim window. A job can be + started connected to the terminal emulator. For example, to run a shell: > + :term bash + + Or to run a debugger: > + :term gdb vim + + The job runs asynchronously from Vim, the window will be updated to show + output from the job, also while editing in any other window. + + When the keyboard focus is in the terminal window, typed keys will be send to + the job. This uses a pty when possible. + + Navigate between windows with CTRL-W commands (and mouse). + E.g. CTRL-W CTRL-W moves focus to the next window. + + Option 'termkey' + Specify key for Vim command in terminal window. local to window. + Default is CTRL-W. + + Option 'termsize' + Specify terminal size. Local to window. + When empty the terminal gets the size from the window. + When set (e.g., "24x80") the terminal size is fixed. If the window is smaller + only the top-left part is displayed. (TODO: scrolling?) + + Syntax ~ + *:ter* *:terminal* + :terminal[!] [command] Open a new terminal window. + + If [command] is provided run it as a job and connect + the input and output to the terminal. + If [command] is not given the 'shell' option is used. + + A new buffer will be created, using [command] or + 'shell' as the name. If a buffer by this name already + exists a number is added in parenthesis. + E.g. if "gdb" exists the second terminal buffer will + use "gdb (1)". + + The window can be closed, in which case the buffer + becomes hidden. The command will not be stopped. The + `:buffer` command can be used to turn the current + window into a terminal window, using the existing + buffer. If there are unsaved changes this fails, use + ! to force, as usual. + + Resizing ~ + + The size of the terminal can be in one of three modes: + + 1. The 'termsize' option is empty: The terminal size follows the window size. + The minimal size is 2 screen lines with 10 cells. + + 2. The 'termsize' option is "rows*cols", where "rows" is the minimal number of + screen rows and "cols" is the minial number of cells. + + 3. The 'termsize' option is "rowsXcols" (where the x is upper or lower case). + The terminal size is fixed to the specified number of screen lines and + cells. If the window is bigger there will be unused empty space. + + If the window is smaller than the terminal size, only part of the terminal can + be seen (the lower-left part). + + The |term_getsize()| function can be used to get the current size of the + terminal. |term_setsize()| can be used only when in the first or second mode, + not when 'termsize' is "rowsXcols". + + ============================================================================== + 2. Remote testing *terminal-testing* + + Most Vim tests execute a script inside Vim. For some tests this does not + work, running the test interferes with the code being tested. To avoid this + Vim is executed in a terminal window. The test sends keystrokes to it and + inspects the resulting screen state. + + Functions ~ + + term_sendkeys() send keystrokes to a terminal + term_wait() wait for screen to be updated + term_scrape() inspect terminal screen + + + ============================================================================== + 3. Debugging *terminal-debug* + + The Terminal debugging plugin can be used to debug a program with gdb and view + the source code in a Vim window. For example: > + + :TermDebug vim + + This opens three windows: + - A terminal window in which "gdb vim" is executed. Here you can directly + interact with gdb. + - A terminal window for the executed program. When "run" is used in gdb the + program I/O will happen in this window, so that it does not interfere with + controlling gdb. + - A normal Vim window used to show the source code. When gdb jumps to a + source file location this window will display the code, if possible. Values + of variables can be inspected, breakpoints set and cleared, etc. + + This uses two terminal windows. To open the gdb window: > + :term gdb [arguments] + To open the terminal to run the tested program |term_open()| is used. + + TODO + + + vim:tw=78:ts=8:ft=help:norl: *** ../vim-8.0.0692/runtime/doc/Makefile 2016-03-31 20:47:51.000000000 +0200 --- runtime/doc/Makefile 2017-07-02 21:43:56.565776815 +0200 *************** *** 100,105 **** --- 101,107 ---- tabpage.txt \ tagsrch.txt \ term.txt \ + terminal.txt \ tips.txt \ todo.txt \ uganda.txt \ *************** *** 234,239 **** --- 237,243 ---- tabpage.html \ tagsrch.html \ term.html \ + terminal.html \ tips.html \ todo.html \ uganda.html \ *** ../vim-8.0.0692/Filelist 2017-04-20 21:55:23.319604249 +0200 --- Filelist 2017-07-05 21:57:22.586628458 +0200 *************** *** 85,90 **** --- 85,91 ---- src/syntax.c \ src/tag.c \ src/term.c \ + src/terminal.c \ src/term.h \ src/termlib.c \ src/ui.c \ *************** *** 187,192 **** --- 188,194 ---- src/proto/syntax.pro \ src/proto/tag.pro \ src/proto/term.pro \ + src/proto/terminal.pro \ src/proto/termlib.pro \ src/proto/ui.pro \ src/proto/undo.pro \ *************** *** 194,199 **** --- 196,271 ---- src/proto/version.pro \ src/proto/winclip.pro \ src/proto/window.pro \ + src/libvterm/.bzrignore \ + src/libvterm/.gitignore \ + src/libvterm/LICENSE \ + src/libvterm/Makefile \ + src/libvterm/README \ + src/libvterm/tbl2inc_c.pl \ + src/libvterm/vterm.pc.in \ + src/libvterm/bin/unterm.c \ + src/libvterm/bin/vterm-ctrl.c \ + src/libvterm/bin/vterm-dump.c \ + src/libvterm/doc/URLs \ + src/libvterm/doc/seqs.txt \ + src/libvterm/include/vterm.h \ + src/libvterm/include/vterm_keycodes.h \ + src/libvterm/src/encoding.c \ + src/libvterm/src/encoding/DECdrawing.inc \ + src/libvterm/src/encoding/DECdrawing.tbl \ + src/libvterm/src/encoding/uk.inc \ + src/libvterm/src/encoding/uk.tbl \ + src/libvterm/src/keyboard.c \ + src/libvterm/src/mouse.c \ + src/libvterm/src/parser.c \ + src/libvterm/src/pen.c \ + src/libvterm/src/rect.h \ + src/libvterm/src/screen.c \ + src/libvterm/src/state.c \ + src/libvterm/src/unicode.c \ + src/libvterm/src/utf8.h \ + src/libvterm/src/vterm.c \ + src/libvterm/src/vterm_internal.h \ + src/libvterm/t/02parser.test \ + src/libvterm/t/03encoding_utf8.test \ + src/libvterm/t/10state_putglyph.test \ + src/libvterm/t/11state_movecursor.test \ + src/libvterm/t/12state_scroll.test \ + src/libvterm/t/13state_edit.test \ + src/libvterm/t/14state_encoding.test \ + src/libvterm/t/15state_mode.test \ + src/libvterm/t/16state_resize.test \ + src/libvterm/t/17state_mouse.test \ + src/libvterm/t/18state_termprops.test \ + src/libvterm/t/20state_wrapping.test \ + src/libvterm/t/21state_tabstops.test \ + src/libvterm/t/22state_save.test \ + src/libvterm/t/25state_input.test \ + src/libvterm/t/26state_query.test \ + src/libvterm/t/27state_reset.test \ + src/libvterm/t/28state_dbl_wh.test \ + src/libvterm/t/29state_fallback.test \ + src/libvterm/t/30pen.test \ + src/libvterm/t/40screen_ascii.test \ + src/libvterm/t/41screen_unicode.test \ + src/libvterm/t/42screen_damage.test \ + src/libvterm/t/43screen_resize.test \ + src/libvterm/t/44screen_pen.test \ + src/libvterm/t/45screen_protect.test \ + src/libvterm/t/46screen_extent.test \ + src/libvterm/t/47screen_dbl_wh.test \ + src/libvterm/t/48screen_termprops.test \ + src/libvterm/t/90vttest_01-movement-1.test \ + src/libvterm/t/90vttest_01-movement-2.test \ + src/libvterm/t/90vttest_01-movement-3.test \ + src/libvterm/t/90vttest_01-movement-4.test \ + src/libvterm/t/90vttest_02-screen-1.test \ + src/libvterm/t/90vttest_02-screen-2.test \ + src/libvterm/t/90vttest_02-screen-3.test \ + src/libvterm/t/90vttest_02-screen-4.test \ + src/libvterm/t/92lp1640917.test \ + src/libvterm/t/harness.c \ + src/libvterm/t/run-test.pl \ # source files for Unix only *** ../vim-8.0.0692/src/libvterm/.bzrignore 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/.bzrignore 2017-06-24 16:44:02.168325016 +0200 *************** *** 0 **** --- 1,13 ---- + .libs + *.lo + *.la + + bin/* + !bin/*.c + + pangoterm + t/test + t/suites.h + t/externs.h + t/harness + src/encoding/*.inc *** ../vim-8.0.0692/src/libvterm/.gitignore 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/.gitignore 2017-07-01 20:18:43.895797351 +0200 *************** *** 0 **** --- 1,18 ---- + *~ + *.swp + + tags + src/*.o + src/*.lo + src/encoding/*.inc + + libvterm.la + bin/unterm + bin/vterm-ctrl + bin/vterm-dump + + t/harness + t/harness.lo + t/harness.o + + .libs/ *** ../vim-8.0.0692/src/libvterm/LICENSE 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/LICENSE 2017-06-24 16:44:02.172324984 +0200 *************** *** 0 **** --- 1,23 ---- + + + The MIT License + + Copyright (c) 2008 Paul Evans + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. *** ../vim-8.0.0692/src/libvterm/README 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/README 2017-07-05 21:56:42.950933984 +0200 *************** *** 0 **** --- 1,13 ---- + This is a MODIFIED version of libvterm. + + The original can be found: + On the original site (tar archive and Bazaar repository): + http://www.leonerd.org.uk/code/libvterm/ + Cloned on Github: + https://github.com/neovim/libvterm + + Modifications: + - Add a .gitignore file. + - Convert from C99 to C90. + - Other changes to support embedding in Vim. + - *** ../vim-8.0.0692/src/libvterm/Makefile 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/Makefile 2017-06-30 22:56:07.456723251 +0200 *************** *** 0 **** --- 1,145 ---- + ifeq ($(shell uname),Darwin) + LIBTOOL ?= glibtool + else + LIBTOOL ?= libtool + endif + + ifneq ($(VERBOSE),1) + LIBTOOL +=--quiet + endif + + # override CFLAGS +=-Wall -Iinclude -std=c99 -DINLINE="static inline" -DUSE_INLINE + override CFLAGS +=-Wall -Iinclude -std=c90 -Wpedantic -DINLINE="" + + ifeq ($(shell uname),SunOS) + override CFLAGS +=-D__EXTENSIONS__ -D_XPG6 -D__XOPEN_OR_POSIX + endif + + ifeq ($(DEBUG),1) + override CFLAGS +=-ggdb -DDEBUG + endif + + ifeq ($(PROFILE),1) + override CFLAGS +=-pg + override LDFLAGS+=-pg + endif + + CFILES=$(sort $(wildcard src/*.c)) + HFILES=$(sort $(wildcard include/*.h)) + OBJECTS=$(CFILES:.c=.lo) + LIBRARY=libvterm.la + + BINFILES_SRC=$(sort $(wildcard bin/*.c)) + BINFILES=$(BINFILES_SRC:.c=) + + TBLFILES=$(sort $(wildcard src/encoding/*.tbl)) + INCFILES=$(TBLFILES:.tbl=.inc) + + HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES) + + VERSION_MAJOR=0 + VERSION_MINOR=0 + + VERSION_CURRENT=0 + VERSION_REVISION=0 + VERSION_AGE=0 + + VERSION=0 + + PREFIX=/usr/local + BINDIR=$(PREFIX)/bin + LIBDIR=$(PREFIX)/lib + INCDIR=$(PREFIX)/include + MANDIR=$(PREFIX)/share/man + MAN3DIR=$(MANDIR)/man3 + + all: $(LIBRARY) $(BINFILES) + + $(LIBRARY): $(OBJECTS) + @echo LINK $@ + @$(LIBTOOL) --mode=link --tag=CC $(CC) -rpath $(LIBDIR) -version-info $(VERSION_CURRENT):$(VERSION_REVISION):$(VERSION_AGE) -o $@ $^ $(LDFLAGS) + + src/%.lo: src/%.c $(HFILES_INT) + @echo CC $< + @$(LIBTOOL) --mode=compile --tag=CC $(CC) $(CFLAGS) -o $@ -c $< + + src/encoding/%.inc: src/encoding/%.tbl + @echo TBL $< + @perl -CSD tbl2inc_c.pl $< >$@ + + src/encoding.lo: $(INCFILES) + + bin/%: bin/%.c $(LIBRARY) + @echo CC $< + @$(LIBTOOL) --mode=link --tag=CC $(CC) $(CFLAGS) -o $@ $< -lvterm $(LDFLAGS) + + t/harness.lo: t/harness.c $(HFILES) + @echo CC $< + @$(LIBTOOL) --mode=compile --tag=CC $(CC) $(CFLAGS) -o $@ -c $< + + t/harness: t/harness.lo $(LIBRARY) + @echo LINK $@ + @$(LIBTOOL) --mode=link --tag=CC $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + + .PHONY: test + test: $(LIBRARY) t/harness + for T in `ls t/[0-9]*.test`; do echo "** $$T **"; perl t/run-test.pl $$T $(if $(VALGRIND),--valgrind) || exit 1; done + + .PHONY: clean + clean: + $(LIBTOOL) --mode=clean rm -f $(OBJECTS) $(INCFILES) + $(LIBTOOL) --mode=clean rm -f t/harness.lo t/harness + $(LIBTOOL) --mode=clean rm -f $(LIBRARY) $(BINFILES) + + .PHONY: install + install: install-inc install-lib install-bin + + install-inc: + install -d $(DESTDIR)$(INCDIR) + install -m644 $(HFILES) $(DESTDIR)$(INCDIR) + install -d $(DESTDIR)$(LIBDIR)/pkgconfig + sed -e "s,@PREFIX@,$(PREFIX)," -e "s,@LIBDIR@,$(LIBDIR)," -e "s,@VERSION@,$(VERSION)," $(DESTDIR)$(LIBDIR)/pkgconfig/vterm.pc + + install-lib: $(LIBRARY) + install -d $(DESTDIR)$(LIBDIR) + $(LIBTOOL) --mode=install install $(LIBRARY) $(DESTDIR)$(LIBDIR)/$(LIBRARY) + $(LIBTOOL) --mode=finish $(DESTDIR)$(LIBDIR) + + install-bin: $(BINFILES) + install -d $(DESTDIR)$(BINDIR) + $(LIBTOOL) --mode=install install $(BINFILES) $(DESTDIR)$(BINDIR)/ + + # DIST CUT + + VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) + + DISTDIR=libvterm-$(VERSION) + + distdir: $(INCFILES) + mkdir __distdir + cp LICENSE __distdir + mkdir __distdir/src + cp src/*.c src/*.h __distdir/src + mkdir __distdir/src/encoding + cp src/encoding/*.inc __distdir/src/encoding + mkdir __distdir/include + cp include/*.h __distdir/include + mkdir __distdir/bin + cp bin/*.c __distdir/bin + mkdir __distdir/t + cp t/*.test t/harness.c t/run-test.pl __distdir/t + sed "s,@VERSION@,$(VERSION)," __distdir/vterm.pc.in + sed "/^# DIST CUT/Q" __distdir/Makefile + mv __distdir $(DISTDIR) + + TARBALL=$(DISTDIR).tar.gz + + dist: distdir + tar -czf $(TARBALL) $(DISTDIR) + rm -rf $(DISTDIR) + + dist+bzr: + $(MAKE) dist VERSION=$(VERSION)+bzr`bzr revno` + + distdir+bzr: + $(MAKE) distdir VERSION=$(VERSION)+bzr`bzr revno` *** ../vim-8.0.0692/src/libvterm/tbl2inc_c.pl 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/tbl2inc_c.pl 2017-07-01 15:08:17.871052763 +0200 *************** *** 0 **** --- 1,51 ---- + #!/usr/bin/perl + + use strict; + use warnings; + + my ( $encname ) = $ARGV[0] =~ m{/([^/.]+).tbl} + or die "Cannot parse encoding name out of $ARGV[0]\n"; + + print <<"EOF"; + static const struct StaticTableEncoding encoding_$encname = { + { + NULL, /* init */ + &decode_table /* decode */ + }, + { + EOF + + my $row = 0; + while( <> ) { + s/\s*#.*//; # strip comment + + if ($_ =~ m{^\d+/\d+}) { + my ($up, $low) = ($_ =~ m{^(\d+)/(\d+)}); + my $thisrow = $up * 16 + $low; + while ($row < $thisrow) { + print " 0x0, /* $row */\n"; + ++$row; + } + } + + s{^(\d+)/(\d+)}{""}e; # Remove 3/1 + s{ = }{""}e; # Remove " = " + s{"(.)"}{sprintf "0x%04x", ord $1}e; # Convert "A" to 0x41 + s{U\+}{0x}; # Convert U+0041 to 0x0041 + + s{$}{, /* $row */}; # append comma and index + + print " $_"; + + ++$row; + } + + while ($row < 128) { + print " 0x0, /* $row */\n"; + ++$row; + } + + print <<"EOF"; + } + }; + EOF *** ../vim-8.0.0692/src/libvterm/vterm.pc.in 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/vterm.pc.in 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,9 ---- + prefix=@PREFIX@ + libdir=@LIBDIR@ + includedir=${prefix}/include + + Name: vterm + Description: Abstract VT220/Xterm/ECMA-48 emulation library + Version: @VERSION@ + Libs: -L${libdir} -lvterm + Cflags: -I${includedir} *** ../vim-8.0.0692/src/libvterm/bin/unterm.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/bin/unterm.c 2017-06-29 22:56:15.413225053 +0200 *************** *** 0 **** --- 1,287 ---- + #include + #include + + #include + #include + #include + #include + + #include "vterm.h" + + #define DEFINE_INLINES + #include "../src/utf8.h" /* fill_utf8 */ + + #define streq(a,b) (!strcmp(a,b)) + + static VTerm *vt; + static VTermScreen *vts; + + static int cols; + static int rows; + + static enum { + FORMAT_PLAIN, + FORMAT_SGR + } format = FORMAT_PLAIN; + + static int col2index(VTermColor target) + { + int index; + + for(index = 0; index < 256; index++) { + VTermColor col; + vterm_state_get_palette_color(NULL, index, &col); + if(col.red == target.red && col.green == target.green && col.blue == target.blue) + return index; + } + return -1; + } + + static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell) + { + switch(format) { + case FORMAT_PLAIN: + break; + case FORMAT_SGR: + { + /* If all 7 attributes change, that means 7 SGRs max */ + /* Each colour could consume up to 3 */ + int sgr[7 + 2*3]; int sgri = 0; + + if(!prevcell->attrs.bold && cell->attrs.bold) + sgr[sgri++] = 1; + if(prevcell->attrs.bold && !cell->attrs.bold) + sgr[sgri++] = 22; + + if(!prevcell->attrs.underline && cell->attrs.underline) + sgr[sgri++] = 4; + if(prevcell->attrs.underline && !cell->attrs.underline) + sgr[sgri++] = 24; + + if(!prevcell->attrs.italic && cell->attrs.italic) + sgr[sgri++] = 3; + if(prevcell->attrs.italic && !cell->attrs.italic) + sgr[sgri++] = 23; + + if(!prevcell->attrs.blink && cell->attrs.blink) + sgr[sgri++] = 5; + if(prevcell->attrs.blink && !cell->attrs.blink) + sgr[sgri++] = 25; + + if(!prevcell->attrs.reverse && cell->attrs.reverse) + sgr[sgri++] = 7; + if(prevcell->attrs.reverse && !cell->attrs.reverse) + sgr[sgri++] = 27; + + if(!prevcell->attrs.strike && cell->attrs.strike) + sgr[sgri++] = 9; + if(prevcell->attrs.strike && !cell->attrs.strike) + sgr[sgri++] = 29; + + if(!prevcell->attrs.font && cell->attrs.font) + sgr[sgri++] = 10 + cell->attrs.font; + if(prevcell->attrs.font && !cell->attrs.font) + sgr[sgri++] = 10; + + if(prevcell->fg.red != cell->fg.red || + prevcell->fg.green != cell->fg.green || + prevcell->fg.blue != cell->fg.blue) { + int index = col2index(cell->fg); + if(index == -1) + sgr[sgri++] = 39; + else if(index < 8) + sgr[sgri++] = 30 + index; + else if(index < 16) + sgr[sgri++] = 90 + (index - 8); + else { + sgr[sgri++] = 38; + sgr[sgri++] = 5 | (1<<31); + sgr[sgri++] = index | (1<<31); + } + } + + if(prevcell->bg.red != cell->bg.red || + prevcell->bg.green != cell->bg.green || + prevcell->bg.blue != cell->bg.blue) { + int index = col2index(cell->bg); + if(index == -1) + sgr[sgri++] = 49; + else if(index < 8) + sgr[sgri++] = 40 + index; + else if(index < 16) + sgr[sgri++] = 100 + (index - 8); + else { + sgr[sgri++] = 48; + sgr[sgri++] = 5 | (1<<31); + sgr[sgri++] = index | (1<<31); + } + } + + if(!sgri) + break; + + printf("\x1b["); + { + int i; + for(i = 0; i < sgri; i++) + printf(!i ? "%d" : + sgr[i] & (1<<31) ? ":%d" : + ";%d", + sgr[i] & ~(1<<31)); + } + printf("m"); + } + break; + } + + { + int i; + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { + char bytes[6]; + bytes[fill_utf8(cell->chars[i], bytes)] = 0; + printf("%s", bytes); + } + } + } + + static void dump_eol(const VTermScreenCell *prevcell) + { + switch(format) { + case FORMAT_PLAIN: + break; + case FORMAT_SGR: + if(prevcell->attrs.bold || prevcell->attrs.underline || prevcell->attrs.italic || + prevcell->attrs.blink || prevcell->attrs.reverse || prevcell->attrs.strike || + prevcell->attrs.font) + printf("\x1b[m"); + break; + } + + printf("\n"); + } + + void dump_row(int row) + { + VTermPos pos; + VTermScreenCell prevcell; + pos.row = row; + pos.col = 0; + memset(&prevcell, 0, sizeof(prevcell)); + vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg); + + while(pos.col < cols) { + VTermScreenCell cell; + vterm_screen_get_cell(vts, pos, &cell); + + dump_cell(&cell, &prevcell); + + pos.col += cell.width; + prevcell = cell; + } + + dump_eol(&prevcell); + } + + static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user) + { + VTermScreenCell prevcell; + int col; + + memset(&prevcell, 0, sizeof(prevcell)); + vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg); + + for(col = 0; col < cols; col++) { + dump_cell(cells + col, &prevcell); + prevcell = cells[col]; + } + + dump_eol(&prevcell); + + return 1; + } + + static int screen_resize(int new_rows, int new_cols, void *user) + { + rows = new_rows; + cols = new_cols; + return 1; + } + + static VTermScreenCallbacks cb_screen = { + NULL, /* damage */ + NULL, /* moverect */ + NULL, /* movecursor */ + NULL, /* settermprop */ + NULL, /* bell */ + &screen_resize, /* resize */ + &screen_sb_pushline, /* sb_pushline */ + NULL, /* popline */ + }; + + int main(int argc, char *argv[]) + { + int opt; + const char *file; + int fd; + int len; + char buffer[1024]; + int row; + + rows = 25; + cols = 80; + + while((opt = getopt(argc, argv, "f:l:c:")) != -1) { + switch(opt) { + case 'f': + if(streq(optarg, "plain")) + format = FORMAT_PLAIN; + else if(streq(optarg, "sgr")) + format = FORMAT_SGR; + else { + fprintf(stderr, "Unrecognised format '%s'\n", optarg); + exit(1); + } + break; + + case 'l': + rows = atoi(optarg); + if(!rows) + rows = 25; + break; + + case 'c': + cols = atoi(optarg); + if(!cols) + cols = 80; + break; + } + } + + file = argv[optind++]; + fd = open(file, O_RDONLY); + if(fd == -1) { + fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno)); + exit(1); + } + + vt = vterm_new(rows, cols); + vterm_set_utf8(vt, true); + + vts = vterm_obtain_screen(vt); + vterm_screen_set_callbacks(vts, &cb_screen, NULL); + + vterm_screen_reset(vts, 1); + + while((len = read(fd, buffer, sizeof(buffer))) > 0) { + vterm_input_write(vt, buffer, len); + } + + for(row = 0; row < rows; row++) { + dump_row(row); + } + + close(fd); + + vterm_free(vt); + return 0; + } *** ../vim-8.0.0692/src/libvterm/bin/vterm-ctrl.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/bin/vterm-ctrl.c 2017-06-30 19:13:08.538340096 +0200 *************** *** 0 **** --- 1,362 ---- + #define _XOPEN_SOURCE 500 /* strdup */ + + #include + #include + #include + #include + #define streq(a,b) (strcmp(a,b)==0) + + #include + + static char *getvalue(int *argip, int argc, char *argv[]) + { + if(*argip >= argc) { + fprintf(stderr, "Expected an option value\n"); + exit(1); + } + + return argv[(*argip)++]; + } + + static int getchoice(int *argip, int argc, char *argv[], const char *options[]) + { + const char *arg = getvalue(argip, argc, argv); + + int value = -1; + while(options[++value]) + if(streq(arg, options[value])) + return value; + + fprintf(stderr, "Unrecognised option value %s\n", arg); + exit(1); + } + + typedef enum { + OFF, + ON, + QUERY + } BoolQuery; + + static BoolQuery getboolq(int *argip, int argc, char *argv[]) + { + const char *choices[] = {"off", "on", "query", NULL}; + return getchoice(argip, argc, argv, choices); + } + + static char *helptext[] = { + "reset", + "s8c1t [off|on]", + "keypad [app|num]", + "screen [off|on|query]", + "cursor [off|on|query]", + "curblink [off|on|query]", + "curshape [block|under|bar|query]", + "mouse [off|click|clickdrag|motion]", + "altscreen [off|on|query]", + "bracketpaste [off|on|query]", + "icontitle [STR]", + "icon [STR]", + "title [STR]", + NULL + }; + + static bool seticanon(bool icanon, bool echo) + { + struct termios termios; + + tcgetattr(0, &termios); + + bool ret = (termios.c_lflag & ICANON); + + if(icanon) termios.c_lflag |= ICANON; + else termios.c_lflag &= ~ICANON; + + if(echo) termios.c_lflag |= ECHO; + else termios.c_lflag &= ~ECHO; + + tcsetattr(0, TCSANOW, &termios); + + return ret; + } + + static void await_c1(int c1) + { + int c; + + /* await CSI - 8bit or 2byte 7bit form */ + bool in_esc = false; + while((c = getchar())) { + if(c == c1) + break; + if(in_esc && c == (char)(c1 - 0x40)) + break; + if(!in_esc && c == 0x1b) + in_esc = true; + else + in_esc = false; + } + } + + static char *read_csi() + { + unsigned char csi[32]; + int i = 0; + + await_c1(0x9B); /* CSI */ + + /* TODO: This really should be a more robust CSI parser + */ + for(; i < sizeof(csi)-1; i++) { + int c = csi[i] = getchar(); + if(c >= 0x40 && c <= 0x7e) + break; + } + csi[++i] = 0; + + /* TODO: returns longer than 32? */ + + return strdup((char *)csi); + } + + static char *read_dcs() + { + unsigned char dcs[32]; + bool in_esc = false; + int i; + + await_c1(0x90); + + for(i = 0; i < sizeof(dcs)-1; ) { + char c = getchar(); + if(c == 0x9c) /* ST */ + break; + if(in_esc && c == 0x5c) + break; + if(!in_esc && c == 0x1b) + in_esc = true; + else { + dcs[i++] = c; + in_esc = false; + } + } + dcs[++i] = 0; + + return strdup((char *)dcs); + } + + static void usage(int exitcode) + { + char **p; + + fprintf(stderr, "Control a libvterm-based terminal\n" + "\n" + "Options:\n"); + + for(p = helptext; *p; p++) + fprintf(stderr, " %s\n", *p); + + exit(exitcode); + } + + static bool query_dec_mode(int mode) + { + char *s = NULL; + + printf("\x1b[?%d$p", mode); + + do { + int reply_mode, reply_value; + char reply_cmd; + + if(s) + free(s); + s = read_csi(); + + /* expect "?" mode ";" value "$y" */ + + /* If the sscanf format string ends in a literal, we can't tell from + * its return value if it matches. Hence we'll %c the cmd and check it + * explicitly + */ + if(sscanf(s, "?%d;%d$%c", &reply_mode, &reply_value, &reply_cmd) < 3) + continue; + if(reply_cmd != 'y') + continue; + + if(reply_mode != mode) + continue; + + free(s); + + if(reply_value == 1 || reply_value == 3) + return true; + if(reply_value == 2 || reply_value == 4) + return false; + + printf("Unrecognised reply to DECRQM: %d\n", reply_value); + return false; + } while(1); + } + + static void do_dec_mode(int mode, BoolQuery val, const char *name) + { + switch(val) { + case OFF: + case ON: + printf("\x1b[?%d%c", mode, val == ON ? 'h' : 'l'); + break; + + case QUERY: + if(query_dec_mode(mode)) + printf("%s on\n", name); + else + printf("%s off\n", name); + break; + } + } + + static int query_rqss_numeric(char *cmd) + { + char *s = NULL; + + printf("\x1bP$q%s\x1b\\", cmd); + + do { + int num; + + if(s) + free(s); + s = read_dcs(); + + if(!s) + return -1; + if(strlen(s) < strlen(cmd)) + return -1; + if(strcmp(s + strlen(s) - strlen(cmd), cmd) != 0) { + printf("No match\n"); + continue; + } + + if(s[0] != '1' || s[1] != '$' || s[2] != 'r') + return -1; + + if(sscanf(s + 3, "%d", &num) != 1) + return -1; + + return num; + } while(1); + } + + bool wasicanon; + + void restoreicanon(void) + { + seticanon(wasicanon, true); + } + + int main(int argc, char *argv[]) + { + int argi = 1; + + if(argc == 1) + usage(0); + + wasicanon = seticanon(false, false); + atexit(restoreicanon); + + while(argi < argc) { + const char *arg = argv[argi++]; + + if(streq(arg, "reset")) { + printf("\x1b" "c"); + } + else if(streq(arg, "s8c1t")) { + const char *choices[] = {"off", "on", NULL}; + switch(getchoice(&argi, argc, argv, choices)) { + case 0: + printf("\x1b F"); break; + case 1: + printf("\x1b G"); break; + } + } + else if(streq(arg, "keypad")) { + const char *choices[] = {"app", "num", NULL}; + switch(getchoice(&argi, argc, argv, choices)) { + case 0: + printf("\x1b="); break; + case 1: + printf("\x1b>"); break; + } + } + else if(streq(arg, "screen")) { + do_dec_mode(5, getboolq(&argi, argc, argv), "screen"); + } + else if(streq(arg, "cursor")) { + do_dec_mode(25, getboolq(&argi, argc, argv), "cursor"); + } + else if(streq(arg, "curblink")) { + do_dec_mode(12, getboolq(&argi, argc, argv), "curblink"); + } + else if(streq(arg, "curshape")) { + /* TODO: This ought to query the current value of DECSCUSR because it */ + /* may need blinking on or off */ + const char *choices[] = {"block", "under", "bar", "query", NULL}; + int shape = getchoice(&argi, argc, argv, choices); + switch(shape) { + case 3: /* query */ + shape = query_rqss_numeric(" q"); + switch(shape) { + case 1: case 2: + printf("curshape block\n"); + break; + case 3: case 4: + printf("curshape under\n"); + break; + case 5: case 6: + printf("curshape bar\n"); + break; + } + break; + + case 0: + case 1: + case 2: + printf("\x1b[%d q", 1 + (shape * 2)); + break; + } + } + else if(streq(arg, "mouse")) { + const char *choices[] = {"off", "click", "clickdrag", "motion", NULL}; + switch(getchoice(&argi, argc, argv, choices)) { + case 0: + printf("\x1b[?1000l"); break; + case 1: + printf("\x1b[?1000h"); break; + case 2: + printf("\x1b[?1002h"); break; + case 3: + printf("\x1b[?1003h"); break; + } + } + else if(streq(arg, "altscreen")) { + do_dec_mode(1049, getboolq(&argi, argc, argv), "altscreen"); + } + else if(streq(arg, "bracketpaste")) { + do_dec_mode(2004, getboolq(&argi, argc, argv), "bracketpaste"); + } + else if(streq(arg, "icontitle")) { + printf("\x1b]0;%s\a", getvalue(&argi, argc, argv)); + } + else if(streq(arg, "icon")) { + printf("\x1b]1;%s\a", getvalue(&argi, argc, argv)); + } + else if(streq(arg, "title")) { + printf("\x1b]2;%s\a", getvalue(&argi, argc, argv)); + } + else { + fprintf(stderr, "Unrecognised command %s\n", arg); + exit(1); + } + } + return 0; + } *** ../vim-8.0.0692/src/libvterm/bin/vterm-dump.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/bin/vterm-dump.c 2017-06-30 20:58:30.450909582 +0200 *************** *** 0 **** --- 1,231 ---- + /* Require getopt(3) */ + #define _XOPEN_SOURCE + + #include + #include + #define streq(a,b) (strcmp(a,b)==0) + + #include + #include + #include + #include + #include + + #include "vterm.h" + + static const char *special_begin = "{"; + static const char *special_end = "}"; + + static int parser_text(const char bytes[], size_t len, void *user) + { + unsigned char *b = (unsigned char *)bytes; + + int i; + for(i = 0; i < len; /* none */) { + if(b[i] < 0x20) /* C0 */ + break; + else if(b[i] < 0x80) /* ASCII */ + i++; + else if(b[i] < 0xa0) /* C1 */ + break; + else if(b[i] < 0xc0) /* UTF-8 continuation */ + break; + else if(b[i] < 0xe0) { /* UTF-8 2-byte */ + /* 2-byte UTF-8 */ + if(len < i+2) break; + i += 2; + } + else if(b[i] < 0xf0) { /* UTF-8 3-byte */ + if(len < i+3) break; + i += 3; + } + else if(b[i] < 0xf8) { /* UTF-8 4-byte */ + if(len < i+4) break; + i += 4; + } + else /* otherwise invalid */ + break; + } + + printf("%.*s", i, b); + return i; + } + + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + static const char *name_c0[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "LS0", "LS1", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US", + }; + static const char *name_c1[] = { + NULL, NULL, "BPH", "NBH", NULL, "NEL", "SSA", "ESA", "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3", + "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", "SOS", NULL, "SCI", "CSI", "ST", "OSC", "PM", "APC", + }; + + static int parser_control(unsigned char control, void *user) + { + if(control < 0x20) + printf("%s%s%s", special_begin, name_c0[control], special_end); + else if(control >= 0x80 && control < 0xa0 && name_c1[control - 0x80]) + printf("%s%s%s", special_begin, name_c1[control - 0x80], special_end); + else + printf("%sCONTROL 0x%02x%s", special_begin, control, special_end); + + if(control == 0x0a) + printf("\n"); + return 1; + } + + static int parser_escape(const char bytes[], size_t len, void *user) + { + if(bytes[0] >= 0x20 && bytes[0] < 0x30) { + if(len < 2) + return -1; + len = 2; + } + else { + len = 1; + } + + printf("%sESC %.*s%s", special_begin, (int)len, bytes, special_end); + + return len; + } + + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + static const char *name_csi_plain[] = { + "ICH", "CUU", "CUD", "CUF", "CUB", "CNL", "CPL", "CHA", "CUP", "CHT", "ED", "EL", "IL", "DL", "EF", "EA", + "DCH", "SSE", "CPR", "SU", "SD", "NP", "PP", "CTC", "ECH", "CVT", "CBT", "SRS", "PTX", "SDS", "SIMD",NULL, + "HPA", "HPR", "REP", "DA", "VPA", "VPR", "HVP", "TBC", "SM", "MC", "HPB", "VPB", "RM", "SGR", "DSR", "DAQ", + }; + + /*0 4 8 B */ + static const int newline_csi_plain[] = { + 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, + }; + + static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) + { + const char *name = NULL; + if(!leader && !intermed && command < 0x70) + name = name_csi_plain[command - 0x40]; + else if(leader && streq(leader, "?") && !intermed) { + /* DEC */ + switch(command) { + case 'h': name = "DECSM"; break; + case 'l': name = "DECRM"; break; + } + if(name) + leader = NULL; + } + + if(!leader && !intermed && command < 0x70 && newline_csi_plain[command - 0x40]) + printf("\n"); + + if(name) + printf("%s%s", special_begin, name); + else + printf("%sCSI", special_begin); + + if(leader && leader[0]) + printf(" %s", leader); + + { + int i; + for(i = 0; i < argcount; i++) { + printf(i ? "," : " "); + } + + if(args[i] == CSI_ARG_MISSING) + printf("*"); + else { + while(CSI_ARG_HAS_MORE(args[i])) + printf("%ld+", CSI_ARG(args[i++])); + printf("%ld", CSI_ARG(args[i])); + } + } + + if(intermed && intermed[0]) + printf(" %s", intermed); + + if(name) + printf("%s", special_end); + else + printf(" %c%s", command, special_end); + + return 1; + } + + static int parser_osc(const char *command, size_t cmdlen, void *user) + { + printf("%sOSC %.*s%s", special_begin, (int)cmdlen, command, special_end); + + return 1; + } + + static int parser_dcs(const char *command, size_t cmdlen, void *user) + { + printf("%sDCS %.*s%s", special_begin, (int)cmdlen, command, special_end); + + return 1; + } + + static VTermParserCallbacks parser_cbs = { + &parser_text, /* text */ + &parser_control, /* control */ + &parser_escape, /* escape */ + &parser_csi, /* csi */ + &parser_osc, /* osc */ + &parser_dcs, /* dcs */ + NULL /* resize */ + }; + + int main(int argc, char *argv[]) + { + int use_colour = isatty(1); + const char *file; + int fd; + VTerm *vt; + int len; + char buffer[1024]; + + int opt; + while((opt = getopt(argc, argv, "c")) != -1) { + switch(opt) { + case 'c': use_colour = 1; break; + } + } + + file = argv[optind++]; + + if(!file || streq(file, "-")) + fd = 0; /* stdin */ + else { + fd = open(file, O_RDONLY); + if(fd == -1) { + fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno)); + exit(1); + } + } + + if(use_colour) { + special_begin = "\x1b[7m{"; + special_end = "}\x1b[m"; + } + + /* Size matters not for the parser */ + vt = vterm_new(25, 80); + vterm_set_utf8(vt, 1); + vterm_parser_set_callbacks(vt, &parser_cbs, NULL); + + while((len = read(fd, buffer, sizeof(buffer))) > 0) { + vterm_input_write(vt, buffer, len); + } + + printf("\n"); + + close(fd); + vterm_free(vt); + return 0; + } *** ../vim-8.0.0692/src/libvterm/doc/URLs 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/doc/URLs 2017-06-24 16:44:02.172324984 +0200 *************** *** 0 **** --- 1,11 ---- + ECMA-48: + http://www.ecma-international.org/publications/standards/Ecma-048.htm + + Xterm Control Sequences: + http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + + Digital VT100 User Guide: + http://vt100.net/docs/vt100-ug/ + + Digital VT220 Programmer Reference Manual + http://vt100.net/docs/vt220-rm/ *** ../vim-8.0.0692/src/libvterm/doc/seqs.txt 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/doc/seqs.txt 2017-06-24 16:44:02.172324984 +0200 *************** *** 0 **** --- 1,226 ---- + Sequences documented in parens are implicit ones from parser.c, which move + between states. + + 1 = VT100 + 2 = VT220 + 3 = VT320 + + C0 controls + + 123 0x00 = NUL + 123 0x07 = BEL + 123 0x08 = BS + 123 0x09 = HT + 123 0x0A = LF + 123 0x0B = VT + 123 0x0C = FF + 123 0x0D = CR + 123 0x0E = LS1 + 123 0x0F = LS0 + (0x18 = CAN) + (0x1A = SUB) + (0x1B = ESC) + + 123 0x7f = DEL (ignored) + + C1 controls + + 123 0x84 = IND + 123 0x85 = NEL + 123 0x88 = HTS + 123 0x8D = RI + 23 0x8e = SS2 + 23 0x8f = SS3 + (0x90 = DCS) + (0x9B = CSI) + (0x9C = ST) + (0x9D = OSC) + + Escape sequences + - excluding sequences that are C1 aliases + + 123 ESC () = SCS, select character set (G0, G1) + 23 ESC *+ = SCS, select character set (G2, G3) + 123 ESC 7 = DECSC - save cursor + 123 ESC 8 = DECRC - restore cursor + 123 ESC # 3 = DECDHL, double-height line (top half) + 123 ESC # 4 = DECDHL, double-height line (bottom half) + 123 ESC # 5 = DECSWL, single-width single-height line + 123 ESC # 6 = DECDWL, double-width single-height line + 123 ESC # 8 = DECALN + 123 ESC < = Ignored (used by VT100 to exit VT52 mode) + 123 ESC = = DECKPAM, keypad application mode + 123 ESC > = DECKPNM, keypad numeric mode + 23 ESC Sp F = S7C1T + 23 ESC Sp G = S8C1T + (ESC P = DCS) + (ESC [ = CSI) + (ESC \ = ST) + (ESC ] = OSC) + 123 ESC c = RIS, reset initial state + 3 ESC n = LS2 + 3 ESC o = LS3 + 3 ESC ~ = LS1R + 3 ESC } = LS2R + 3 ESC | = LS3R + + DCSes + + 3 DCS $ q ST = DECRQSS + 3 m = Request SGR + Sp q = Request DECSCUSR + 3 " q = Request DECSCA + 3 r = Request DECSTBM + s = Request DECSLRM + + CSIs + 23 CSI @ = ICH + 123 CSI A = CUU + 123 CSI B = CUD + 123 CSI C = CUF + 123 CSI D = CUB + CSI E = CNL + CSI F = CPL + CSI G = CHA + 123 CSI H = CUP + CSI I = CHT + 123 CSI J = ED + 23 CSI ? J = DECSED, selective erase in display + 123 CSI K = EL + 23 CSI ? K = DECSEL, selective erase in line + 23 CSI L = IL + 23 CSI M = DL + 23 CSI P = DCH + CSI S = SU + CSI T = SD + 23 CSI X = ECH + CSI Z = CBT + CSI ` = HPA + CSI a = HPR + 123 CSI c = DA, device attributes + 123 0 = DA + 23 CSI > c = DECSDA + 23 0 = SDA + CSI d = VPA + CSI e = VPR + 123 CSI f = HVP + 123 CSI g = TBC + 123 CSI h = SM, Set mode + 123 CSI ? h = DECSM, DEC set mode + CSI j = HPB + CSI k = VPB + 123 CSI l = RM, Reset mode + 123 CSI ? l = DECRM, DEC reset mode + 123 CSI m = SGR, Set Graphic Rendition + 123 CSI n = DSR, Device Status Report + 23 5 = operating status + 23 6 = CPR = cursor position + 23 CSI ? n = DECDSR; behaves as DSR but uses CSI ? instead of CSI to respond + 23 CSI ! p = DECSTR, soft terminal reset + 3 CSI ? $ p = DECRQM, request mode + CSI Sp q = DECSCUSR (odd numbers blink, even numbers solid) + 1 or 2 = block + 3 or 4 = underline + 5 or 6 = I-beam to left + 23 CSI " q = DECSCA, select character attributes + 123 CSI r = DECSTBM + CSI s = DECSLRM + CSI ' } = DECIC + CSI ' ~ = DECDC + + OSCs + + OSC 0; = Set icon name and title + OSC 1; = Set icon name + OSC 2; = Set title + + Standard modes + + 23 SM 4 = IRM + 123 SM 20 = NLM, linefeed/newline + + DEC modes + + 123 DECSM 1 = DECCKM, cursor keys + 123 DECSM 5 = DECSCNM, screen + 123 DECSM 6 = DECOM, origin + 123 DECSM 7 = DECAWM, autowrap + DECSM 12 = Cursor blink + 23 DECSM 25 = DECTCEM, text cursor enable + DECSM 69 = DECVSSM, vertical screen split + DECSM 1000 = Mouse click/release tracking + DECSM 1002 = Mouse click/release/drag tracking + DECSM 1003 = Mouse all movements tracking + DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended + DECSM 1006 = Mouse protocol SGR + DECSM 1015 = Mouse protocol rxvt + DECSM 1047 = Altscreen + DECSM 1048 = Save cursor + DECSM 1049 = 1047 + 1048 + DECSM 2004 = Bracketed paste + + Graphic Renditions + + 123 SGR 0 = Reset + 123 SGR 1 = Bold on + SGR 3 = Italic on + 123 SGR 4 = Underline single + 123 SGR 5 = Blink on + 123 SGR 7 = Reverse on + SGR 9 = Strikethrough on + SGR 10-19 = Select font + SGR 21 = Underline double + 23 SGR 22 = Bold off + SGR 23 = Italic off + 23 SGR 24 = Underline off + 23 SGR 25 = Blink off + 23 SGR 27 = Reverse off + SGR 29 = Strikethrough off + SGR 30-37 = Foreground ANSI + SGR 38 = Foreground alternative palette + SGR 39 = Foreground default + SGR 40-47 = Background ANSI + SGR 48 = Background alternative palette + SGR 49 = Background default + SGR 90-97 = Foreground ANSI high-intensity + SGR 100-107 = Background ANSI high-intensity + + The state storage used by ESC 7 and DECSM 1048/1049 is shared. + + Unimplemented sequences: + + The following sequences are not recognised by libvterm. + + 123 0x05 = ENQ + 3 0x11 = DC1 (XON) + 3 0x13 = DC3 (XOFF) + 12 ESC Z = DECID, identify terminal + DCS $ q = [DECRQSS] + 3 " p = Request DECSCL + 3 $ } = Request DECSASD + 3 $ ~ = Request DECSSDT + 23 DCS { = DECDLD, down-line-loadable character set + 23 DCS | = DECUDK, user-defined key + 23 CSI i = DEC printer control + 23 CSI " p = DECSCL, set compatibility level + 1 CSI q = DECLL, load LEDs + 3 CSI $ u = DECRQTSR, request terminal state report + 3 1 = terminal state report + 3 CSI & u = DECRQUPSS, request user-preferred supplemental set + 3 CSI $ w = DECRQPSR, request presentation state report + 3 1 = cursor information report + 3 2 = tab stop report + 1 CSI x = DECREQTPARM, request terminal parameters + 123 CSI y = DECTST, invoke confidence test + 3 CSI $ } = DECSASD, select active status display + 3 CSI $ ~ = DECSSDT, select status line type + 23 SM 2 = KAM, keyboard action + 123 SM 12 = SRM, send/receive + 123 DECSM 2 = DECANM, ANSI/VT52 + 123 DECSM 3 = DECCOLM, 132 column + 123 DECSM 4 = DECSCLM, scrolling + 123 DECSM 8 = DECARM, auto-repeat + 12 DECSM 9 = DECINLM, interlace + 23 DECSM 18 = DECPFF, print form feed + 23 DECSM 19 = DECPEX, print extent + 23 DECSM 42 = DECNRCM, national/multinational character *** ../vim-8.0.0692/src/libvterm/include/vterm.h 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/include/vterm.h 2017-07-05 22:17:51.365165798 +0200 *************** *** 0 **** --- 1,370 ---- + /* + * NOTE: This is a MODIFIED version of libvterm, see the README file. + */ + #ifndef __VTERM_H__ + #define __VTERM_H__ + + #ifdef __cplusplus + extern "C" { + #endif + + #include + #include + #include + + #include "vterm_keycodes.h" + + typedef struct VTerm VTerm; + typedef struct VTermState VTermState; + typedef struct VTermScreen VTermScreen; + + /* Specifies a screen point. */ + typedef struct { + int row; + int col; + } VTermPos; + + /* + * Some small utility functions; we can just keep these static here. + */ + + /* + * Order points by on-screen flow order: + * Return < 0 if "a" is before "b" + * Return 0 if "a" and "b" are equal + * Return > 0 if "a" is after "b". + */ + int vterm_pos_cmp(VTermPos a, VTermPos b); + + #if defined(DEFINE_INLINES) || USE_INLINE + INLINE int vterm_pos_cmp(VTermPos a, VTermPos b) + { + return (a.row == b.row) ? a.col - b.col : a.row - b.row; + } + #endif + + /* Specifies a rectangular screen area. */ + typedef struct { + int start_row; + int end_row; + int start_col; + int end_col; + } VTermRect; + + /* Return true if the rect "r" contains the point "p". */ + int vterm_rect_contains(VTermRect r, VTermPos p); + + #if defined(DEFINE_INLINES) || USE_INLINE + INLINE int vterm_rect_contains(VTermRect r, VTermPos p) + { + return p.row >= r.start_row && p.row < r.end_row && + p.col >= r.start_col && p.col < r.end_col; + } + #endif + + /* Move "rect" "row_delta" down and "col_delta" right. + * Does not check boundaries. */ + void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta); + + #if defined(DEFINE_INLINES) || USE_INLINE + INLINE void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta) + { + rect->start_row += row_delta; rect->end_row += row_delta; + rect->start_col += col_delta; rect->end_col += col_delta; + } + #endif + + typedef struct { + uint8_t red, green, blue; + } VTermColor; + + typedef enum { + /* VTERM_VALUETYPE_NONE = 0 */ + VTERM_VALUETYPE_BOOL = 1, + VTERM_VALUETYPE_INT, + VTERM_VALUETYPE_STRING, + VTERM_VALUETYPE_COLOR + } VTermValueType; + + typedef union { + int boolean; + int number; + char *string; + VTermColor color; + } VTermValue; + + typedef enum { + /* VTERM_ATTR_NONE = 0 */ + VTERM_ATTR_BOLD = 1, /* bool: 1, 22 */ + VTERM_ATTR_UNDERLINE, /* number: 4, 21, 24 */ + VTERM_ATTR_ITALIC, /* bool: 3, 23 */ + VTERM_ATTR_BLINK, /* bool: 5, 25 */ + VTERM_ATTR_REVERSE, /* bool: 7, 27 */ + VTERM_ATTR_STRIKE, /* bool: 9, 29 */ + VTERM_ATTR_FONT, /* number: 10-19 */ + VTERM_ATTR_FOREGROUND, /* color: 30-39 90-97 */ + VTERM_ATTR_BACKGROUND /* color: 40-49 100-107 */ + } VTermAttr; + + typedef enum { + /* VTERM_PROP_NONE = 0 */ + VTERM_PROP_CURSORVISIBLE = 1, /* bool */ + VTERM_PROP_CURSORBLINK, /* bool */ + VTERM_PROP_ALTSCREEN, /* bool */ + VTERM_PROP_TITLE, /* string */ + VTERM_PROP_ICONNAME, /* string */ + VTERM_PROP_REVERSE, /* bool */ + VTERM_PROP_CURSORSHAPE, /* number */ + VTERM_PROP_MOUSE /* number */ + } VTermProp; + + enum { + VTERM_PROP_CURSORSHAPE_BLOCK = 1, + VTERM_PROP_CURSORSHAPE_UNDERLINE, + VTERM_PROP_CURSORSHAPE_BAR_LEFT + }; + + enum { + VTERM_PROP_MOUSE_NONE = 0, + VTERM_PROP_MOUSE_CLICK, + VTERM_PROP_MOUSE_DRAG, + VTERM_PROP_MOUSE_MOVE + }; + + typedef struct { + const uint32_t *chars; + int width; + unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */ + unsigned int dwl:1; /* DECDWL or DECDHL double-width line */ + unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */ + } VTermGlyphInfo; + + typedef struct { + unsigned int doublewidth:1; /* DECDWL or DECDHL line */ + unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */ + } VTermLineInfo; + + typedef struct { + /* libvterm relies on the allocated memory to be zeroed out before it is + * returned by the allocator. */ + void *(*malloc)(size_t size, void *allocdata); + void (*free)(void *ptr, void *allocdata); + } VTermAllocatorFunctions; + + /* Allocate and initialize a new terminal with default allocators. */ + VTerm *vterm_new(int rows, int cols); + + /* Allocate and initialize a new terminal with specified allocators. */ + VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata); + + /* Free and cleanup a terminal and all its data. */ + void vterm_free(VTerm* vt); + + void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp); + void vterm_set_size(VTerm *vt, int rows, int cols); + + int vterm_get_utf8(const VTerm *vt); + void vterm_set_utf8(VTerm *vt, int is_utf8); + + size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len); + + size_t vterm_output_get_buffer_size(const VTerm *vt); + size_t vterm_output_get_buffer_current(const VTerm *vt); + size_t vterm_output_get_buffer_remaining(const VTerm *vt); + + size_t vterm_output_read(VTerm *vt, char *buffer, size_t len); + + void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod); + void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod); + + void vterm_keyboard_start_paste(VTerm *vt); + void vterm_keyboard_end_paste(VTerm *vt); + + void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod); + void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod); + + /* ------------ + * Parser layer + * ------------ */ + + /* Flag to indicate non-final subparameters in a single CSI parameter. + * Consider + * CSI 1;2:3:4;5a + * 1 4 and 5 are final. + * 2 and 3 are non-final and will have this bit set + * + * Don't confuse this with the final byte of the CSI escape; 'a' in this case. + */ + #define CSI_ARG_FLAG_MORE (1<<31) + #define CSI_ARG_MASK (~(1<<31)) + + #define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE) + #define CSI_ARG(a) ((a) & CSI_ARG_MASK) + + /* Can't use -1 to indicate a missing argument; use this instead */ + #define CSI_ARG_MISSING ((1UL<<31)-1) + + #define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING) + #define CSI_ARG_OR(a,def) (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a)) + #define CSI_ARG_COUNT(a) (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a)) + + typedef struct { + int (*text)(const char *bytes, size_t len, void *user); + int (*control)(unsigned char control, void *user); + int (*escape)(const char *bytes, size_t len, void *user); + int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); + int (*osc)(const char *command, size_t cmdlen, void *user); + int (*dcs)(const char *command, size_t cmdlen, void *user); + int (*resize)(int rows, int cols, void *user); + } VTermParserCallbacks; + + void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user); + void *vterm_parser_get_cbdata(VTerm *vt); + + /* ----------- + * State layer + * ----------- */ + + typedef struct { + int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user); + int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user); + int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user); + int (*moverect)(VTermRect dest, VTermRect src, void *user); + int (*erase)(VTermRect rect, int selective, void *user); + int (*initpen)(void *user); + int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user); + int (*settermprop)(VTermProp prop, VTermValue *val, void *user); + int (*bell)(void *user); + int (*resize)(int rows, int cols, VTermPos *delta, void *user); + int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user); + } VTermStateCallbacks; + + VTermState *vterm_obtain_state(VTerm *vt); + + void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user); + void *vterm_state_get_cbdata(VTermState *state); + + /* Only invokes control, csi, osc, dcs */ + void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user); + void *vterm_state_get_unrecognised_fbdata(VTermState *state); + + void vterm_state_reset(VTermState *state, int hard); + void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos); + void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg); + void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col); + void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg); + void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col); + void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright); + int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val); + int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val); + const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row); + + /* ------------ + * Screen layer + * ------------ */ + + typedef struct { + unsigned int bold : 1; + unsigned int underline : 2; + unsigned int italic : 1; + unsigned int blink : 1; + unsigned int reverse : 1; + unsigned int strike : 1; + unsigned int font : 4; /* 0 to 9 */ + unsigned int dwl : 1; /* On a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */ + } VTermScreenCellAttrs; + + typedef struct { + #define VTERM_MAX_CHARS_PER_CELL 6 + uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; + char width; + VTermScreenCellAttrs attrs; + VTermColor fg, bg; + } VTermScreenCell; + + /* All fields are optional, NULL when not used. */ + typedef struct { + int (*damage)(VTermRect rect, void *user); + int (*moverect)(VTermRect dest, VTermRect src, void *user); + int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user); + int (*settermprop)(VTermProp prop, VTermValue *val, void *user); + int (*bell)(void *user); + int (*resize)(int rows, int cols, void *user); + int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user); + int (*sb_popline)(int cols, VTermScreenCell *cells, void *user); + } VTermScreenCallbacks; + + VTermScreen *vterm_obtain_screen(VTerm *vt); + + /* + * Install screen callbacks. These are invoked when the screen contents is + * changed. "user" is passed into to the callback. + */ + void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user); + void *vterm_screen_get_cbdata(VTermScreen *screen); + + /* Only invokes control, csi, osc, dcs */ + void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user); + void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen); + + void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen); + + typedef enum { + VTERM_DAMAGE_CELL, /* every cell */ + VTERM_DAMAGE_ROW, /* entire rows */ + VTERM_DAMAGE_SCREEN, /* entire screen */ + VTERM_DAMAGE_SCROLL /* entire screen + scrollrect */ + } VTermDamageSize; + + void vterm_screen_flush_damage(VTermScreen *screen); + void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size); + + void vterm_screen_reset(VTermScreen *screen, int hard); + + /* Neither of these functions NUL-terminate the buffer */ + size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect); + size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect); + + typedef enum { + VTERM_ATTR_BOLD_MASK = 1 << 0, + VTERM_ATTR_UNDERLINE_MASK = 1 << 1, + VTERM_ATTR_ITALIC_MASK = 1 << 2, + VTERM_ATTR_BLINK_MASK = 1 << 3, + VTERM_ATTR_REVERSE_MASK = 1 << 4, + VTERM_ATTR_STRIKE_MASK = 1 << 5, + VTERM_ATTR_FONT_MASK = 1 << 6, + VTERM_ATTR_FOREGROUND_MASK = 1 << 7, + VTERM_ATTR_BACKGROUND_MASK = 1 << 8 + } VTermAttrMask; + + int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); + + int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell); + + int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos); + + /* --------- + * Utilities + * --------- */ + + VTermValueType vterm_get_attr_type(VTermAttr attr); + VTermValueType vterm_get_prop_type(VTermProp prop); + + void vterm_scroll_rect(VTermRect rect, + int downward, + int rightward, + int (*moverect)(VTermRect src, VTermRect dest, void *user), + int (*eraserect)(VTermRect rect, int selective, void *user), + void *user); + + void vterm_copy_cells(VTermRect dest, + VTermRect src, + void (*copycell)(VTermPos dest, VTermPos src, void *user), + void *user); + + #ifdef __cplusplus + } + #endif + + #endif *** ../vim-8.0.0692/src/libvterm/include/vterm_keycodes.h 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/include/vterm_keycodes.h 2017-06-27 13:11:14.597675223 +0200 *************** *** 0 **** --- 1,58 ---- + #ifndef __VTERM_INPUT_H__ + #define __VTERM_INPUT_H__ + + typedef enum { + VTERM_MOD_NONE = 0x00, + VTERM_MOD_SHIFT = 0x01, + VTERM_MOD_ALT = 0x02, + VTERM_MOD_CTRL = 0x04 + } VTermModifier; + + typedef enum { + VTERM_KEY_NONE, + + VTERM_KEY_ENTER, + VTERM_KEY_TAB, + VTERM_KEY_BACKSPACE, + VTERM_KEY_ESCAPE, + + VTERM_KEY_UP, + VTERM_KEY_DOWN, + VTERM_KEY_LEFT, + VTERM_KEY_RIGHT, + + VTERM_KEY_INS, + VTERM_KEY_DEL, + VTERM_KEY_HOME, + VTERM_KEY_END, + VTERM_KEY_PAGEUP, + VTERM_KEY_PAGEDOWN, + + VTERM_KEY_FUNCTION_0 = 256, + VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255, + + VTERM_KEY_KP_0, + VTERM_KEY_KP_1, + VTERM_KEY_KP_2, + VTERM_KEY_KP_3, + VTERM_KEY_KP_4, + VTERM_KEY_KP_5, + VTERM_KEY_KP_6, + VTERM_KEY_KP_7, + VTERM_KEY_KP_8, + VTERM_KEY_KP_9, + VTERM_KEY_KP_MULT, + VTERM_KEY_KP_PLUS, + VTERM_KEY_KP_COMMA, + VTERM_KEY_KP_MINUS, + VTERM_KEY_KP_PERIOD, + VTERM_KEY_KP_DIVIDE, + VTERM_KEY_KP_ENTER, + VTERM_KEY_KP_EQUAL, + + VTERM_KEY_MAX /* Must be last */ + } VTermKey; + + #define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n)) + + #endif *** ../vim-8.0.0692/src/libvterm/src/encoding.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/encoding.c 2017-07-02 18:00:59.899949165 +0200 *************** *** 0 **** --- 1,232 ---- + #include "vterm_internal.h" + + #define UNICODE_INVALID 0xFFFD + + #if defined(DEBUG) && DEBUG > 1 + # define DEBUG_PRINT_UTF8 + #endif + + struct UTF8DecoderData { + /* number of bytes remaining in this codepoint */ + int bytes_remaining; + + /* number of bytes total in this codepoint once it's finished + (for detecting overlongs) */ + int bytes_total; + + int this_cp; + }; + + static void init_utf8(VTermEncoding *enc UNUSED, void *data_) + { + struct UTF8DecoderData *data = data_; + + data->bytes_remaining = 0; + data->bytes_total = 0; + } + + static void decode_utf8(VTermEncoding *enc UNUSED, void *data_, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) + { + struct UTF8DecoderData *data = data_; + + #ifdef DEBUG_PRINT_UTF8 + printf("BEGIN UTF-8\n"); + #endif + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos]; + + #ifdef DEBUG_PRINT_UTF8 + printf(" pos=%zd c=%02x rem=%d\n", *pos, c, data->bytes_remaining); + #endif + + if(c < 0x20) /* C0 */ + return; + + else if(c >= 0x20 && c < 0x7f) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + cp[(*cpi)++] = c; + #ifdef DEBUG_PRINT_UTF8 + printf(" UTF-8 char: U+%04x\n", c); + #endif + data->bytes_remaining = 0; + } + + else if(c == 0x7f) /* DEL */ + return; + + else if(c >= 0x80 && c < 0xc0) { + if(!data->bytes_remaining) { + cp[(*cpi)++] = UNICODE_INVALID; + continue; + } + + data->this_cp <<= 6; + data->this_cp |= c & 0x3f; + data->bytes_remaining--; + + if(!data->bytes_remaining) { + #ifdef DEBUG_PRINT_UTF8 + printf(" UTF-8 raw char U+%04x bytelen=%d ", data->this_cp, data->bytes_total); + #endif + /* Check for overlong sequences */ + switch(data->bytes_total) { + case 2: + if(data->this_cp < 0x0080) data->this_cp = UNICODE_INVALID; + break; + case 3: + if(data->this_cp < 0x0800) data->this_cp = UNICODE_INVALID; + break; + case 4: + if(data->this_cp < 0x10000) data->this_cp = UNICODE_INVALID; + break; + case 5: + if(data->this_cp < 0x200000) data->this_cp = UNICODE_INVALID; + break; + case 6: + if(data->this_cp < 0x4000000) data->this_cp = UNICODE_INVALID; + break; + } + /* Now look for plain invalid ones */ + if((data->this_cp >= 0xD800 && data->this_cp <= 0xDFFF) || + data->this_cp == 0xFFFE || + data->this_cp == 0xFFFF) + data->this_cp = UNICODE_INVALID; + #ifdef DEBUG_PRINT_UTF8 + printf(" char: U+%04x\n", data->this_cp); + #endif + cp[(*cpi)++] = data->this_cp; + } + } + + else if(c >= 0xc0 && c < 0xe0) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x1f; + data->bytes_total = 2; + data->bytes_remaining = 1; + } + + else if(c >= 0xe0 && c < 0xf0) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x0f; + data->bytes_total = 3; + data->bytes_remaining = 2; + } + + else if(c >= 0xf0 && c < 0xf8) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x07; + data->bytes_total = 4; + data->bytes_remaining = 3; + } + + else if(c >= 0xf8 && c < 0xfc) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x03; + data->bytes_total = 5; + data->bytes_remaining = 4; + } + + else if(c >= 0xfc && c < 0xfe) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x01; + data->bytes_total = 6; + data->bytes_remaining = 5; + } + + else { + cp[(*cpi)++] = UNICODE_INVALID; + } + } + } + + static VTermEncoding encoding_utf8 = { + &init_utf8, /* init */ + &decode_utf8 /* decode */ + }; + + static void decode_usascii(VTermEncoding *enc UNUSED, void *data UNUSED, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) + { + int is_gr = bytes[*pos] & 0x80; + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos] ^ is_gr; + + if(c < 0x20 || c == 0x7f || c >= 0x80) + return; + + cp[(*cpi)++] = c; + } + } + + static VTermEncoding encoding_usascii = { + NULL, /* init */ + &decode_usascii /* decode */ + }; + + struct StaticTableEncoding { + const VTermEncoding enc; + const uint32_t chars[128]; + }; + + static void decode_table(VTermEncoding *enc, void *data UNUSED, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) + { + struct StaticTableEncoding *table = (struct StaticTableEncoding *)enc; + int is_gr = bytes[*pos] & 0x80; + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos] ^ is_gr; + + if(c < 0x20 || c == 0x7f || c >= 0x80) + return; + + if(table->chars[c]) + cp[(*cpi)++] = table->chars[c]; + else + cp[(*cpi)++] = c; + } + } + + #include "encoding/DECdrawing.inc" + #include "encoding/uk.inc" + + static struct { + VTermEncodingType type; + char designation; + VTermEncoding *enc; + } + encodings[] = { + { ENC_UTF8, 'u', &encoding_utf8 }, + { ENC_SINGLE_94, '0', (VTermEncoding*)&encoding_DECdrawing }, + { ENC_SINGLE_94, 'A', (VTermEncoding*)&encoding_uk }, + { ENC_SINGLE_94, 'B', &encoding_usascii }, + { 0 }, + }; + + /* This ought to be INTERNAL but isn't because it's used by unit testing */ + VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation) + { + int i; + for(i = 0; encodings[i].designation; i++) + if(encodings[i].type == type && encodings[i].designation == designation) + return encodings[i].enc; + return NULL; + } *** ../vim-8.0.0692/src/libvterm/src/encoding/DECdrawing.inc 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/encoding/DECdrawing.inc 2017-07-01 15:15:44.547706645 +0200 *************** *** 0 **** --- 1,136 ---- + static const struct StaticTableEncoding encoding_DECdrawing = { + { + NULL, /* init */ + &decode_table /* decode */ + }, + { + 0x0, /* 0 */ + 0x0, /* 1 */ + 0x0, /* 2 */ + 0x0, /* 3 */ + 0x0, /* 4 */ + 0x0, /* 5 */ + 0x0, /* 6 */ + 0x0, /* 7 */ + 0x0, /* 8 */ + 0x0, /* 9 */ + 0x0, /* 10 */ + 0x0, /* 11 */ + 0x0, /* 12 */ + 0x0, /* 13 */ + 0x0, /* 14 */ + 0x0, /* 15 */ + 0x0, /* 16 */ + 0x0, /* 17 */ + 0x0, /* 18 */ + 0x0, /* 19 */ + 0x0, /* 20 */ + 0x0, /* 21 */ + 0x0, /* 22 */ + 0x0, /* 23 */ + 0x0, /* 24 */ + 0x0, /* 25 */ + 0x0, /* 26 */ + 0x0, /* 27 */ + 0x0, /* 28 */ + 0x0, /* 29 */ + 0x0, /* 30 */ + 0x0, /* 31 */ + 0x0, /* 32 */ + 0x0, /* 33 */ + 0x0, /* 34 */ + 0x0, /* 35 */ + 0x0, /* 36 */ + 0x0, /* 37 */ + 0x0, /* 38 */ + 0x0, /* 39 */ + 0x0, /* 40 */ + 0x0, /* 41 */ + 0x0, /* 42 */ + 0x0, /* 43 */ + 0x0, /* 44 */ + 0x0, /* 45 */ + 0x0, /* 46 */ + 0x0, /* 47 */ + 0x0, /* 48 */ + 0x0, /* 49 */ + 0x0, /* 50 */ + 0x0, /* 51 */ + 0x0, /* 52 */ + 0x0, /* 53 */ + 0x0, /* 54 */ + 0x0, /* 55 */ + 0x0, /* 56 */ + 0x0, /* 57 */ + 0x0, /* 58 */ + 0x0, /* 59 */ + 0x0, /* 60 */ + 0x0, /* 61 */ + 0x0, /* 62 */ + 0x0, /* 63 */ + 0x0, /* 64 */ + 0x0, /* 65 */ + 0x0, /* 66 */ + 0x0, /* 67 */ + 0x0, /* 68 */ + 0x0, /* 69 */ + 0x0, /* 70 */ + 0x0, /* 71 */ + 0x0, /* 72 */ + 0x0, /* 73 */ + 0x0, /* 74 */ + 0x0, /* 75 */ + 0x0, /* 76 */ + 0x0, /* 77 */ + 0x0, /* 78 */ + 0x0, /* 79 */ + 0x0, /* 80 */ + 0x0, /* 81 */ + 0x0, /* 82 */ + 0x0, /* 83 */ + 0x0, /* 84 */ + 0x0, /* 85 */ + 0x0, /* 86 */ + 0x0, /* 87 */ + 0x0, /* 88 */ + 0x0, /* 89 */ + 0x0, /* 90 */ + 0x0, /* 91 */ + 0x0, /* 92 */ + 0x0, /* 93 */ + 0x0, /* 94 */ + 0x0, /* 95 */ + 0x25C6, /* 96 */ + 0x2592, /* 97 */ + 0x2409, /* 98 */ + 0x240C, /* 99 */ + 0x240D, /* 100 */ + 0x240A, /* 101 */ + 0x00B0, /* 102 */ + 0x00B1, /* 103 */ + 0x2424, /* 104 */ + 0x240B, /* 105 */ + 0x2518, /* 106 */ + 0x2510, /* 107 */ + 0x250C, /* 108 */ + 0x2514, /* 109 */ + 0x253C, /* 110 */ + 0x23BA, /* 111 */ + 0x23BB, /* 112 */ + 0x2500, /* 113 */ + 0x23BC, /* 114 */ + 0x23BD, /* 115 */ + 0x251C, /* 116 */ + 0x2524, /* 117 */ + 0x2534, /* 118 */ + 0x252C, /* 119 */ + 0x2502, /* 120 */ + 0x2A7D, /* 121 */ + 0x2A7E, /* 122 */ + 0x03C0, /* 123 */ + 0x2260, /* 124 */ + 0x00A3, /* 125 */ + 0x00B7, /* 126 */ + 0x0, /* 127 */ + } + }; *** ../vim-8.0.0692/src/libvterm/src/encoding/DECdrawing.tbl 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/encoding/DECdrawing.tbl 2017-06-24 16:44:02.172324984 +0200 *************** *** 0 **** --- 1,31 ---- + 6/0 = U+25C6 # BLACK DIAMOND + 6/1 = U+2592 # MEDIUM SHADE (checkerboard) + 6/2 = U+2409 # SYMBOL FOR HORIZONTAL TAB + 6/3 = U+240C # SYMBOL FOR FORM FEED + 6/4 = U+240D # SYMBOL FOR CARRIAGE RETURN + 6/5 = U+240A # SYMBOL FOR LINE FEED + 6/6 = U+00B0 # DEGREE SIGN + 6/7 = U+00B1 # PLUS-MINUS SIGN (plus or minus) + 6/8 = U+2424 # SYMBOL FOR NEW LINE + 6/9 = U+240B # SYMBOL FOR VERTICAL TAB + 6/10 = U+2518 # BOX DRAWINGS LIGHT UP AND LEFT (bottom-right corner) + 6/11 = U+2510 # BOX DRAWINGS LIGHT DOWN AND LEFT (top-right corner) + 6/12 = U+250C # BOX DRAWINGS LIGHT DOWN AND RIGHT (top-left corner) + 6/13 = U+2514 # BOX DRAWINGS LIGHT UP AND RIGHT (bottom-left corner) + 6/14 = U+253C # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL (crossing lines) + 6/15 = U+23BA # HORIZONTAL SCAN LINE-1 + 7/0 = U+23BB # HORIZONTAL SCAN LINE-3 + 7/1 = U+2500 # BOX DRAWINGS LIGHT HORIZONTAL + 7/2 = U+23BC # HORIZONTAL SCAN LINE-7 + 7/3 = U+23BD # HORIZONTAL SCAN LINE-9 + 7/4 = U+251C # BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 7/5 = U+2524 # BOX DRAWINGS LIGHT VERTICAL AND LEFT + 7/6 = U+2534 # BOX DRAWINGS LIGHT UP AND HORIZONTAL + 7/7 = U+252C # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 7/8 = U+2502 # BOX DRAWINGS LIGHT VERTICAL + 7/9 = U+2A7D # LESS-THAN OR SLANTED EQUAL-TO + 7/10 = U+2A7E # GREATER-THAN OR SLANTED EQUAL-TO + 7/11 = U+03C0 # GREEK SMALL LETTER PI + 7/12 = U+2260 # NOT EQUAL TO + 7/13 = U+00A3 # POUND SIGN + 7/14 = U+00B7 # MIDDLE DOT *** ../vim-8.0.0692/src/libvterm/src/encoding/uk.inc 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/encoding/uk.inc 2017-07-01 15:15:44.559706555 +0200 *************** *** 0 **** --- 1,136 ---- + static const struct StaticTableEncoding encoding_uk = { + { + NULL, /* init */ + &decode_table /* decode */ + }, + { + 0x0, /* 0 */ + 0x0, /* 1 */ + 0x0, /* 2 */ + 0x0, /* 3 */ + 0x0, /* 4 */ + 0x0, /* 5 */ + 0x0, /* 6 */ + 0x0, /* 7 */ + 0x0, /* 8 */ + 0x0, /* 9 */ + 0x0, /* 10 */ + 0x0, /* 11 */ + 0x0, /* 12 */ + 0x0, /* 13 */ + 0x0, /* 14 */ + 0x0, /* 15 */ + 0x0, /* 16 */ + 0x0, /* 17 */ + 0x0, /* 18 */ + 0x0, /* 19 */ + 0x0, /* 20 */ + 0x0, /* 21 */ + 0x0, /* 22 */ + 0x0, /* 23 */ + 0x0, /* 24 */ + 0x0, /* 25 */ + 0x0, /* 26 */ + 0x0, /* 27 */ + 0x0, /* 28 */ + 0x0, /* 29 */ + 0x0, /* 30 */ + 0x0, /* 31 */ + 0x0, /* 32 */ + 0x0, /* 33 */ + 0x0, /* 34 */ + 0x00a3, /* 35 */ + 0x0, /* 36 */ + 0x0, /* 37 */ + 0x0, /* 38 */ + 0x0, /* 39 */ + 0x0, /* 40 */ + 0x0, /* 41 */ + 0x0, /* 42 */ + 0x0, /* 43 */ + 0x0, /* 44 */ + 0x0, /* 45 */ + 0x0, /* 46 */ + 0x0, /* 47 */ + 0x0, /* 48 */ + 0x0, /* 49 */ + 0x0, /* 50 */ + 0x0, /* 51 */ + 0x0, /* 52 */ + 0x0, /* 53 */ + 0x0, /* 54 */ + 0x0, /* 55 */ + 0x0, /* 56 */ + 0x0, /* 57 */ + 0x0, /* 58 */ + 0x0, /* 59 */ + 0x0, /* 60 */ + 0x0, /* 61 */ + 0x0, /* 62 */ + 0x0, /* 63 */ + 0x0, /* 64 */ + 0x0, /* 65 */ + 0x0, /* 66 */ + 0x0, /* 67 */ + 0x0, /* 68 */ + 0x0, /* 69 */ + 0x0, /* 70 */ + 0x0, /* 71 */ + 0x0, /* 72 */ + 0x0, /* 73 */ + 0x0, /* 74 */ + 0x0, /* 75 */ + 0x0, /* 76 */ + 0x0, /* 77 */ + 0x0, /* 78 */ + 0x0, /* 79 */ + 0x0, /* 80 */ + 0x0, /* 81 */ + 0x0, /* 82 */ + 0x0, /* 83 */ + 0x0, /* 84 */ + 0x0, /* 85 */ + 0x0, /* 86 */ + 0x0, /* 87 */ + 0x0, /* 88 */ + 0x0, /* 89 */ + 0x0, /* 90 */ + 0x0, /* 91 */ + 0x0, /* 92 */ + 0x0, /* 93 */ + 0x0, /* 94 */ + 0x0, /* 95 */ + 0x0, /* 96 */ + 0x0, /* 97 */ + 0x0, /* 98 */ + 0x0, /* 99 */ + 0x0, /* 100 */ + 0x0, /* 101 */ + 0x0, /* 102 */ + 0x0, /* 103 */ + 0x0, /* 104 */ + 0x0, /* 105 */ + 0x0, /* 106 */ + 0x0, /* 107 */ + 0x0, /* 108 */ + 0x0, /* 109 */ + 0x0, /* 110 */ + 0x0, /* 111 */ + 0x0, /* 112 */ + 0x0, /* 113 */ + 0x0, /* 114 */ + 0x0, /* 115 */ + 0x0, /* 116 */ + 0x0, /* 117 */ + 0x0, /* 118 */ + 0x0, /* 119 */ + 0x0, /* 120 */ + 0x0, /* 121 */ + 0x0, /* 122 */ + 0x0, /* 123 */ + 0x0, /* 124 */ + 0x0, /* 125 */ + 0x0, /* 126 */ + 0x0, /* 127 */ + } + }; *** ../vim-8.0.0692/src/libvterm/src/encoding/uk.tbl 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/encoding/uk.tbl 2017-07-01 14:45:01.197552937 +0200 *************** *** 0 **** --- 1 ---- + 2/3 = "£" *** ../vim-8.0.0692/src/libvterm/src/keyboard.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/keyboard.c 2017-07-02 18:08:20.832744064 +0200 *************** *** 0 **** --- 1,228 ---- + #include "vterm_internal.h" + + #include + + #include "utf8.h" + + void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) + { + int needs_CSIu; + + /* The shift modifier is never important for Unicode characters + * apart from Space + */ + if(c != ' ') + mod &= ~VTERM_MOD_SHIFT; + + if(mod == 0) { + /* Normal text - ignore just shift */ + char str[6]; + int seqlen = fill_utf8(c, str); + vterm_push_output_bytes(vt, str, seqlen); + return; + } + + switch(c) { + /* Special Ctrl- letters that can't be represented elsewise */ + case 'i': case 'j': case 'm': case '[': + needs_CSIu = 1; + break; + /* Ctrl-\ ] ^ _ don't need CSUu */ + case '\\': case ']': case '^': case '_': + needs_CSIu = 0; + break; + /* Shift-space needs CSIu */ + case ' ': + needs_CSIu = !!(mod & VTERM_MOD_SHIFT); + break; + /* All other characters needs CSIu except for letters a-z */ + default: + needs_CSIu = (c < 'a' || c > 'z'); + } + + /* ALT we can just prefix with ESC; anything else requires CSI u */ + if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) { + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1); + return; + } + + if(mod & VTERM_MOD_CTRL) + c &= 0x1f; + + vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c); + } + + typedef struct { + enum { + KEYCODE_NONE, + KEYCODE_LITERAL, + KEYCODE_TAB, + KEYCODE_ENTER, + KEYCODE_SS3, + KEYCODE_CSI, + KEYCODE_CSI_CURSOR, + KEYCODE_CSINUM, + KEYCODE_KEYPAD + } type; + char literal; + int csinum; + } keycodes_s; + + static keycodes_s keycodes[] = { + { KEYCODE_NONE, 0, 0 }, /* NONE */ + + { KEYCODE_ENTER, '\r', 0 }, /* ENTER */ + { KEYCODE_TAB, '\t', 0 }, /* TAB */ + { KEYCODE_LITERAL, '\x7f', 0 }, /* BACKSPACE == ASCII DEL */ + { KEYCODE_LITERAL, '\x1b', 0 }, /* ESCAPE */ + + { KEYCODE_CSI_CURSOR, 'A', 0 }, /* UP */ + { KEYCODE_CSI_CURSOR, 'B', 0 }, /* DOWN */ + { KEYCODE_CSI_CURSOR, 'D', 0 }, /* LEFT */ + { KEYCODE_CSI_CURSOR, 'C', 0 }, /* RIGHT */ + + { KEYCODE_CSINUM, '~', 2 }, /* INS */ + { KEYCODE_CSINUM, '~', 3 }, /* DEL */ + { KEYCODE_CSI_CURSOR, 'H', 0 }, /* HOME */ + { KEYCODE_CSI_CURSOR, 'F', 0 }, /* END */ + { KEYCODE_CSINUM, '~', 5 }, /* PAGEUP */ + { KEYCODE_CSINUM, '~', 6 }, /* PAGEDOWN */ + }; + + static keycodes_s keycodes_fn[] = { + { KEYCODE_NONE, 0, 0 }, /* F0 - shouldn't happen */ + { KEYCODE_CSI_CURSOR, 'P', 0 }, /* F1 */ + { KEYCODE_CSI_CURSOR, 'Q', 0 }, /* F2 */ + { KEYCODE_CSI_CURSOR, 'R', 0 }, /* F3 */ + { KEYCODE_CSI_CURSOR, 'S', 0 }, /* F4 */ + { KEYCODE_CSINUM, '~', 15 }, /* F5 */ + { KEYCODE_CSINUM, '~', 17 }, /* F6 */ + { KEYCODE_CSINUM, '~', 18 }, /* F7 */ + { KEYCODE_CSINUM, '~', 19 }, /* F8 */ + { KEYCODE_CSINUM, '~', 20 }, /* F9 */ + { KEYCODE_CSINUM, '~', 21 }, /* F10 */ + { KEYCODE_CSINUM, '~', 23 }, /* F11 */ + { KEYCODE_CSINUM, '~', 24 }, /* F12 */ + }; + + static keycodes_s keycodes_kp[] = { + { KEYCODE_KEYPAD, '0', 'p' }, /* KP_0 */ + { KEYCODE_KEYPAD, '1', 'q' }, /* KP_1 */ + { KEYCODE_KEYPAD, '2', 'r' }, /* KP_2 */ + { KEYCODE_KEYPAD, '3', 's' }, /* KP_3 */ + { KEYCODE_KEYPAD, '4', 't' }, /* KP_4 */ + { KEYCODE_KEYPAD, '5', 'u' }, /* KP_5 */ + { KEYCODE_KEYPAD, '6', 'v' }, /* KP_6 */ + { KEYCODE_KEYPAD, '7', 'w' }, /* KP_7 */ + { KEYCODE_KEYPAD, '8', 'x' }, /* KP_8 */ + { KEYCODE_KEYPAD, '9', 'y' }, /* KP_9 */ + { KEYCODE_KEYPAD, '*', 'j' }, /* KP_MULT */ + { KEYCODE_KEYPAD, '+', 'k' }, /* KP_PLUS */ + { KEYCODE_KEYPAD, ',', 'l' }, /* KP_COMMA */ + { KEYCODE_KEYPAD, '-', 'm' }, /* KP_MINUS */ + { KEYCODE_KEYPAD, '.', 'n' }, /* KP_PERIOD */ + { KEYCODE_KEYPAD, '/', 'o' }, /* KP_DIVIDE */ + { KEYCODE_KEYPAD, '\n', 'M' }, /* KP_ENTER */ + { KEYCODE_KEYPAD, '=', 'X' }, /* KP_EQUAL */ + }; + + void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) + { + keycodes_s k; + + if(key == VTERM_KEY_NONE) + return; + + if(key < VTERM_KEY_FUNCTION_0) { + if(key >= sizeof(keycodes)/sizeof(keycodes[0])) + return; + k = keycodes[key]; + } + else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) { + if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0])) + return; + k = keycodes_fn[key - VTERM_KEY_FUNCTION_0]; + } + else if(key >= VTERM_KEY_KP_0) { + if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0])) + return; + k = keycodes_kp[key - VTERM_KEY_KP_0]; + } + + switch(k.type) { + case KEYCODE_NONE: + break; + + case KEYCODE_TAB: + /* Shift-Tab is CSI Z but plain Tab is 0x09 */ + if(mod == VTERM_MOD_SHIFT) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z"); + else if(mod & VTERM_MOD_SHIFT) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1); + else + goto case_LITERAL; + break; + + case KEYCODE_ENTER: + /* Enter is CRLF in newline mode, but just LF in linefeed */ + if(vt->state->mode.newline) + vterm_push_output_sprintf(vt, "\r\n"); + else + goto case_LITERAL; + break; + + case KEYCODE_LITERAL: case_LITERAL: + if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL)) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1); + else + vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal); + break; + + case KEYCODE_SS3: case_SS3: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal); + else + goto case_CSI; + break; + + case KEYCODE_CSI: case_CSI: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal); + else + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal); + break; + + case KEYCODE_CSINUM: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal); + else + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal); + break; + + case KEYCODE_CSI_CURSOR: + if(vt->state->mode.cursor) + goto case_SS3; + else + goto case_CSI; + + case KEYCODE_KEYPAD: + if(vt->state->mode.keypad) { + k.literal = k.csinum; + goto case_SS3; + } + else + goto case_LITERAL; + } + } + + void vterm_keyboard_start_paste(VTerm *vt) + { + if(vt->state->mode.bracketpaste) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~"); + } + + void vterm_keyboard_end_paste(VTerm *vt) + { + if(vt->state->mode.bracketpaste) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~"); + } *** ../vim-8.0.0692/src/libvterm/src/mouse.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/mouse.c 2017-06-30 21:23:28.011788404 +0200 *************** *** 0 **** --- 1,96 ---- + #include "vterm_internal.h" + + #include "utf8.h" + + static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row) + { + modifiers <<= 2; + + switch(state->mouse_protocol) { + case MOUSE_X10: + if(col + 0x21 > 0xff) + col = 0xff - 0x21; + if(row + 0x21 > 0xff) + row = 0xff - 0x21; + + if(!pressed) + code = 3; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c", + (code | modifiers) + 0x20, col + 0x21, row + 0x21); + break; + + case MOUSE_UTF8: + { + char utf8[18]; size_t len = 0; + + if(!pressed) + code = 3; + + len += fill_utf8((code | modifiers) + 0x20, utf8 + len); + len += fill_utf8(col + 0x21, utf8 + len); + len += fill_utf8(row + 0x21, utf8 + len); + utf8[len] = 0; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8); + } + break; + + case MOUSE_SGR: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c", + code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm'); + break; + + case MOUSE_RXVT: + if(!pressed) + code = 3; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM", + code | modifiers, col + 1, row + 1); + break; + } + } + + void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod) + { + VTermState *state = vt->state; + + if(col == state->mouse_col && row == state->mouse_row) + return; + + state->mouse_col = col; + state->mouse_row = row; + + if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) || + (state->mouse_flags & MOUSE_WANT_MOVE)) { + int button = state->mouse_buttons & 0x01 ? 1 : + state->mouse_buttons & 0x02 ? 2 : + state->mouse_buttons & 0x04 ? 3 : 4; + output_mouse(state, button-1 + 0x20, 1, mod, col, row); + } + } + + void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod) + { + VTermState *state = vt->state; + + int old_buttons = state->mouse_buttons; + + if(button > 0 && button <= 3) { + if(pressed) + state->mouse_buttons |= (1 << (button-1)); + else + state->mouse_buttons &= ~(1 << (button-1)); + } + + /* Most of the time we don't get button releases from 4/5 */ + if(state->mouse_buttons == old_buttons && button < 4) + return; + + if(button < 4) { + output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row); + } + else if(button < 6) { + output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row); + } + } *** ../vim-8.0.0692/src/libvterm/src/parser.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/parser.c 2017-07-02 18:08:58.368471081 +0200 *************** *** 0 **** --- 1,346 ---- + #include "vterm_internal.h" + + #include + #include + + #define CSI_ARGS_MAX 16 + #define CSI_LEADER_MAX 16 + #define CSI_INTERMED_MAX 16 + + static void do_control(VTerm *vt, unsigned char control) + { + if(vt->parser_callbacks && vt->parser_callbacks->control) + if((*vt->parser_callbacks->control)(control, vt->cbdata)) + return; + + DEBUG_LOG1("libvterm: Unhandled control 0x%02x\n", control); + } + + static void do_string_csi(VTerm *vt, const char *args, size_t arglen, char command) + { + int i = 0; + + int leaderlen = 0; + char leader[CSI_LEADER_MAX]; + int argcount = 1; /* Always at least 1 arg */ + long csi_args[CSI_ARGS_MAX]; + int argi; + int intermedlen = 0; + char intermed[CSI_INTERMED_MAX]; + + /* Extract leader bytes 0x3c to 0x3f */ + for( ; i < (int)arglen; i++) { + if(args[i] < 0x3c || args[i] > 0x3f) + break; + if(leaderlen < CSI_LEADER_MAX-1) + leader[leaderlen++] = args[i]; + } + + leader[leaderlen] = 0; + + for( ; i < (int)arglen; i++) + if(args[i] == 0x3b || args[i] == 0x3a) /* ; or : */ + argcount++; + + /* TODO: Consider if these buffers should live in the VTerm struct itself */ + if(argcount > CSI_ARGS_MAX) + argcount = CSI_ARGS_MAX; + + for(argi = 0; argi < argcount; argi++) + csi_args[argi] = CSI_ARG_MISSING; + + argi = 0; + for(i = leaderlen; i < (int)arglen && argi < argcount; i++) { + switch(args[i]) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + if(csi_args[argi] == CSI_ARG_MISSING) + csi_args[argi] = 0; + csi_args[argi] *= 10; + csi_args[argi] += args[i] - '0'; + break; + case 0x3a: + csi_args[argi] |= CSI_ARG_FLAG_MORE; + /* FALLTHROUGH */ + case 0x3b: + argi++; + break; + default: + goto done_leader; + } + } + done_leader: ; + + for( ; i < (int)arglen; i++) { + if((args[i] & 0xf0) != 0x20) + break; + + if(intermedlen < CSI_INTERMED_MAX-1) + intermed[intermedlen++] = args[i]; + } + + intermed[intermedlen] = 0; + + if(i < (int)arglen) { + DEBUG_LOG2("libvterm: TODO unhandled CSI bytes \"%.*s\"\n", (int)(arglen - i), args + i); + } + + #if 0 + printf("Parsed CSI args %.*s as:\n", arglen, args); + printf(" leader: %s\n", leader); + for(argi = 0; argi < argcount; argi++) { + printf(" %lu", CSI_ARG(csi_args[argi])); + if(!CSI_ARG_HAS_MORE(csi_args[argi])) + printf("\n"); + printf(" intermed: %s\n", intermed); + } + #endif + + if(vt->parser_callbacks && vt->parser_callbacks->csi) + if((*vt->parser_callbacks->csi)(leaderlen ? leader : NULL, csi_args, argcount, intermedlen ? intermed : NULL, command, vt->cbdata)) + return; + + DEBUG_LOG3("libvterm: Unhandled CSI %.*s %c\n", (int)arglen, args, command); + } + + static void append_strbuffer(VTerm *vt, const char *str, size_t len) + { + if(len > vt->strbuffer_len - vt->strbuffer_cur) { + len = vt->strbuffer_len - vt->strbuffer_cur; + DEBUG_LOG1("Truncating strbuffer preserve to %zd bytes\n", len); + } + + if(len > 0) { + strncpy(vt->strbuffer + vt->strbuffer_cur, str, len); + vt->strbuffer_cur += len; + } + } + + static size_t do_string(VTerm *vt, const char *str_frag, size_t len) + { + size_t eaten; + + if(vt->strbuffer_cur) { + if(str_frag) + append_strbuffer(vt, str_frag, len); + + str_frag = vt->strbuffer; + len = vt->strbuffer_cur; + } + else if(!str_frag) { + DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n"); + len = 0; + } + + vt->strbuffer_cur = 0; + + switch(vt->parser_state) { + case NORMAL: + if(vt->parser_callbacks && vt->parser_callbacks->text) + if((eaten = (*vt->parser_callbacks->text)(str_frag, len, vt->cbdata))) + return eaten; + + DEBUG_LOG1("libvterm: Unhandled text (%zu chars)\n", len); + return 0; + + case ESC: + if(len == 1 && str_frag[0] >= 0x40 && str_frag[0] < 0x60) { + /* C1 emulations using 7bit clean */ + /* ESC 0x40 == 0x80 */ + do_control(vt, str_frag[0] + 0x40); + return 0; + } + + if(vt->parser_callbacks && vt->parser_callbacks->escape) + if((*vt->parser_callbacks->escape)(str_frag, len, vt->cbdata)) + return 0; + + DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", str_frag[len-1]); + return 0; + + case CSI: + do_string_csi(vt, str_frag, len - 1, str_frag[len - 1]); + return 0; + + case OSC: + if(vt->parser_callbacks && vt->parser_callbacks->osc) + if((*vt->parser_callbacks->osc)(str_frag, len, vt->cbdata)) + return 0; + + DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str_frag); + return 0; + + case DCS: + if(vt->parser_callbacks && vt->parser_callbacks->dcs) + if((*vt->parser_callbacks->dcs)(str_frag, len, vt->cbdata)) + return 0; + + DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str_frag); + return 0; + + case ESC_IN_OSC: + case ESC_IN_DCS: + DEBUG_LOG("libvterm: ARGH! Should never do_string() in ESC_IN_{OSC,DCS}\n"); + return 0; + } + + return 0; + } + + size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) + { + size_t pos = 0; + const char *string_start; + + switch(vt->parser_state) { + case NORMAL: + string_start = NULL; + break; + case ESC: + case ESC_IN_OSC: + case ESC_IN_DCS: + case CSI: + case OSC: + case DCS: + string_start = bytes; + break; + } + + #define ENTER_STRING_STATE(st) do { vt->parser_state = st; string_start = bytes + pos + 1; } while(0) + #define ENTER_NORMAL_STATE() do { vt->parser_state = NORMAL; string_start = NULL; } while(0) + + for( ; pos < len; pos++) { + unsigned char c = bytes[pos]; + + if(c == 0x00 || c == 0x7f) { /* NUL, DEL */ + if(vt->parser_state != NORMAL) { + append_strbuffer(vt, string_start, bytes + pos - string_start); + string_start = bytes + pos + 1; + } + continue; + } + if(c == 0x18 || c == 0x1a) { /* CAN, SUB */ + ENTER_NORMAL_STATE(); + continue; + } + else if(c == 0x1b) { /* ESC */ + if(vt->parser_state == OSC) + vt->parser_state = ESC_IN_OSC; + else if(vt->parser_state == DCS) + vt->parser_state = ESC_IN_DCS; + else + ENTER_STRING_STATE(ESC); + continue; + } + else if(c == 0x07 && /* BEL, can stand for ST in OSC or DCS state */ + (vt->parser_state == OSC || vt->parser_state == DCS)) { + /* fallthrough */ + } + else if(c < 0x20) { /* other C0 */ + if(vt->parser_state != NORMAL) + append_strbuffer(vt, string_start, bytes + pos - string_start); + do_control(vt, c); + if(vt->parser_state != NORMAL) + string_start = bytes + pos + 1; + continue; + } + /* else fallthrough */ + + switch(vt->parser_state) { + case ESC_IN_OSC: + case ESC_IN_DCS: + if(c == 0x5c) { /* ST */ + switch(vt->parser_state) { + case ESC_IN_OSC: vt->parser_state = OSC; break; + case ESC_IN_DCS: vt->parser_state = DCS; break; + default: break; + } + do_string(vt, string_start, bytes + pos - string_start - 1); + ENTER_NORMAL_STATE(); + break; + } + vt->parser_state = ESC; + string_start = bytes + pos; + /* else fallthrough */ + + case ESC: + switch(c) { + case 0x50: /* DCS */ + ENTER_STRING_STATE(DCS); + break; + case 0x5b: /* CSI */ + ENTER_STRING_STATE(CSI); + break; + case 0x5d: /* OSC */ + ENTER_STRING_STATE(OSC); + break; + default: + if(c >= 0x30 && c < 0x7f) { + /* +1 to pos because we want to include this command byte as well */ + do_string(vt, string_start, bytes + pos - string_start + 1); + ENTER_NORMAL_STATE(); + } + else if(c >= 0x20 && c < 0x30) { + /* intermediate byte */ + } + else { + DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c); + } + } + break; + + case CSI: + if(c >= 0x40 && c <= 0x7f) { + /* +1 to pos because we want to include this command byte as well */ + do_string(vt, string_start, bytes + pos - string_start + 1); + ENTER_NORMAL_STATE(); + } + break; + + case OSC: + case DCS: + if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) { + do_string(vt, string_start, bytes + pos - string_start); + ENTER_NORMAL_STATE(); + } + break; + + case NORMAL: + if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) { + switch(c) { + case 0x90: /* DCS */ + ENTER_STRING_STATE(DCS); + break; + case 0x9b: /* CSI */ + ENTER_STRING_STATE(CSI); + break; + case 0x9d: /* OSC */ + ENTER_STRING_STATE(OSC); + break; + default: + do_control(vt, c); + break; + } + } + else { + size_t text_eaten = do_string(vt, bytes + pos, len - pos); + + if(text_eaten == 0) { + string_start = bytes + pos; + goto pause; + } + + pos += (text_eaten - 1); /* we'll ++ it again in a moment */ + } + break; + } + } + + pause: + if(string_start && string_start < len + bytes) { + size_t remaining = len - (string_start - bytes); + append_strbuffer(vt, string_start, remaining); + } + + return len; + } *** ../vim-8.0.0692/src/libvterm/src/pen.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/pen.c 2017-07-02 18:09:31.724228479 +0200 *************** *** 0 **** --- 1,504 ---- + #include "vterm_internal.h" + + #include + + static const VTermColor ansi_colors[] = { + /* R G B */ + { 0, 0, 0 }, /* black */ + { 224, 0, 0 }, /* red */ + { 0, 224, 0 }, /* green */ + { 224, 224, 0 }, /* yellow */ + { 0, 0, 224 }, /* blue */ + { 224, 0, 224 }, /* magenta */ + { 0, 224, 224 }, /* cyan */ + { 224, 224, 224 }, /* white == light grey */ + + /* high intensity */ + { 128, 128, 128 }, /* black */ + { 255, 64, 64 }, /* red */ + { 64, 255, 64 }, /* green */ + { 255, 255, 64 }, /* yellow */ + { 64, 64, 255 }, /* blue */ + { 255, 64, 255 }, /* magenta */ + { 64, 255, 255 }, /* cyan */ + { 255, 255, 255 }, /* white for real */ + }; + + static int ramp6[] = { + 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF, + }; + + static int ramp24[] = { + 0x00, 0x0B, 0x16, 0x21, 0x2C, 0x37, 0x42, 0x4D, 0x58, 0x63, 0x6E, 0x79, + 0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF, + }; + + static bool lookup_colour_ansi(const VTermState *state, long index, VTermColor *col) + { + if(index >= 0 && index < 16) { + *col = state->colors[index]; + return true; + } + + return false; + } + + static bool lookup_colour_palette(const VTermState *state, long index, VTermColor *col) + { + if(index >= 0 && index < 16) { + /* Normal 8 colours or high intensity - parse as palette 0 */ + return lookup_colour_ansi(state, index, col); + } + else if(index >= 16 && index < 232) { + /* 216-colour cube */ + index -= 16; + + col->blue = ramp6[index % 6]; + col->green = ramp6[index/6 % 6]; + col->red = ramp6[index/6/6 % 6]; + + return true; + } + else if(index >= 232 && index < 256) { + /* 24 greyscales */ + index -= 232; + + col->blue = ramp24[index]; + col->green = ramp24[index]; + col->red = ramp24[index]; + + return true; + } + + return false; + } + + static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col, int *index) + { + switch(palette) { + case 2: /* RGB mode - 3 args contain colour values directly */ + if(argcount < 3) + return argcount; + + col->red = CSI_ARG(args[0]); + col->green = CSI_ARG(args[1]); + col->blue = CSI_ARG(args[2]); + + return 3; + + case 5: /* XTerm 256-colour mode */ + if(index) + *index = CSI_ARG_OR(args[0], -1); + + lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col); + + return argcount ? 1 : 0; + + default: + DEBUG_LOG1("Unrecognised colour palette %d\n", palette); + return 0; + } + } + + /* Some conveniences */ + + static void setpenattr(VTermState *state, VTermAttr attr, VTermValueType type UNUSED, VTermValue *val) + { + #ifdef DEBUG + if(type != vterm_get_attr_type(attr)) { + DEBUG_LOG("Cannot set attr %d as it has type %d, not type %d\n", + attr, vterm_get_attr_type(attr), type); + return; + } + #endif + if(state->callbacks && state->callbacks->setpenattr) + (*state->callbacks->setpenattr)(attr, val, state->cbdata); + } + + static void setpenattr_bool(VTermState *state, VTermAttr attr, int boolean) + { + VTermValue val; + val.boolean = boolean; + setpenattr(state, attr, VTERM_VALUETYPE_BOOL, &val); + } + + static void setpenattr_int(VTermState *state, VTermAttr attr, int number) + { + VTermValue val; + val.number = number; + setpenattr(state, attr, VTERM_VALUETYPE_INT, &val); + } + + static void setpenattr_col(VTermState *state, VTermAttr attr, VTermColor color) + { + VTermValue val; + val.color = color; + setpenattr(state, attr, VTERM_VALUETYPE_COLOR, &val); + } + + static void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col) + { + VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg; + + lookup_colour_ansi(state, col, colp); + + setpenattr_col(state, attr, *colp); + } + + INTERNAL void vterm_state_newpen(VTermState *state) + { + int col; + + /* 90% grey so that pure white is brighter */ + state->default_fg.red = state->default_fg.green = state->default_fg.blue = 240; + state->default_bg.red = state->default_bg.green = state->default_bg.blue = 0; + + for(col = 0; col < 16; col++) + state->colors[col] = ansi_colors[col]; + } + + INTERNAL void vterm_state_resetpen(VTermState *state) + { + state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0); + state->pen.underline = 0; setpenattr_int( state, VTERM_ATTR_UNDERLINE, 0); + state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); + state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0); + state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); + state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); + state->pen.font = 0; setpenattr_int( state, VTERM_ATTR_FONT, 0); + + state->fg_index = -1; + state->bg_index = -1; + state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg); + state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg); + } + + INTERNAL void vterm_state_savepen(VTermState *state, int save) + { + if(save) { + state->saved.pen = state->pen; + } + else { + state->pen = state->saved.pen; + + setpenattr_bool(state, VTERM_ATTR_BOLD, state->pen.bold); + setpenattr_int( state, VTERM_ATTR_UNDERLINE, state->pen.underline); + setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic); + setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink); + setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse); + setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike); + setpenattr_int( state, VTERM_ATTR_FONT, state->pen.font); + setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg); + setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg); + } + } + + void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg) + { + *default_fg = state->default_fg; + *default_bg = state->default_bg; + } + + void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col) + { + lookup_colour_palette(state, index, col); + } + + void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg) + { + state->default_fg = *default_fg; + state->default_bg = *default_bg; + } + + void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col) + { + if(index >= 0 && index < 16) + state->colors[index] = *col; + } + + void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright) + { + state->bold_is_highbright = bold_is_highbright; + } + + INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount) + { + /* SGR - ECMA-48 8.3.117 */ + + int argi = 0; + int value; + + while(argi < argcount) { + /* This logic is easier to do 'done' backwards; set it true, and make it + false again in the 'default' case */ + int done = 1; + + long arg; + switch(arg = CSI_ARG(args[argi])) { + case CSI_ARG_MISSING: + case 0: /* Reset */ + vterm_state_resetpen(state); + break; + + case 1: /* Bold on */ + state->pen.bold = 1; + setpenattr_bool(state, VTERM_ATTR_BOLD, 1); + if(state->fg_index > -1 && state->fg_index < 8 && state->bold_is_highbright) + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, state->fg_index + (state->pen.bold ? 8 : 0)); + break; + + case 3: /* Italic on */ + state->pen.italic = 1; + setpenattr_bool(state, VTERM_ATTR_ITALIC, 1); + break; + + case 4: /* Underline single */ + state->pen.underline = 1; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, 1); + break; + + case 5: /* Blink */ + state->pen.blink = 1; + setpenattr_bool(state, VTERM_ATTR_BLINK, 1); + break; + + case 7: /* Reverse on */ + state->pen.reverse = 1; + setpenattr_bool(state, VTERM_ATTR_REVERSE, 1); + break; + + case 9: /* Strikethrough on */ + state->pen.strike = 1; + setpenattr_bool(state, VTERM_ATTR_STRIKE, 1); + break; + + case 10: case 11: case 12: case 13: case 14: + case 15: case 16: case 17: case 18: case 19: /* Select font */ + state->pen.font = CSI_ARG(args[argi]) - 10; + setpenattr_int(state, VTERM_ATTR_FONT, state->pen.font); + break; + + case 21: /* Underline double */ + state->pen.underline = 2; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, 2); + break; + + case 22: /* Bold off */ + state->pen.bold = 0; + setpenattr_bool(state, VTERM_ATTR_BOLD, 0); + break; + + case 23: /* Italic and Gothic (currently unsupported) off */ + state->pen.italic = 0; + setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); + break; + + case 24: /* Underline off */ + state->pen.underline = 0; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, 0); + break; + + case 25: /* Blink off */ + state->pen.blink = 0; + setpenattr_bool(state, VTERM_ATTR_BLINK, 0); + break; + + case 27: /* Reverse off */ + state->pen.reverse = 0; + setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); + break; + + case 29: /* Strikethrough off */ + state->pen.strike = 0; + setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); + break; + + case 30: case 31: case 32: case 33: + case 34: case 35: case 36: case 37: /* Foreground colour palette */ + value = CSI_ARG(args[argi]) - 30; + state->fg_index = value; + if(state->pen.bold && state->bold_is_highbright) + value += 8; + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value); + break; + + case 38: /* Foreground colour alternative palette */ + state->fg_index = -1; + if(argcount - argi < 1) + return; + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index); + setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); + break; + + case 39: /* Foreground colour default */ + state->fg_index = -1; + state->pen.fg = state->default_fg; + setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); + break; + + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: /* Background colour palette */ + value = CSI_ARG(args[argi]) - 40; + state->bg_index = value; + set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value); + break; + + case 48: /* Background colour alternative palette */ + state->bg_index = -1; + if(argcount - argi < 1) + return; + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index); + setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); + break; + + case 49: /* Default background */ + state->bg_index = -1; + state->pen.bg = state->default_bg; + setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); + break; + + case 90: case 91: case 92: case 93: + case 94: case 95: case 96: case 97: /* Foreground colour high-intensity palette */ + value = CSI_ARG(args[argi]) - 90 + 8; + state->fg_index = value; + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value); + break; + + case 100: case 101: case 102: case 103: + case 104: case 105: case 106: case 107: /* Background colour high-intensity palette */ + value = CSI_ARG(args[argi]) - 100 + 8; + state->bg_index = value; + set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value); + break; + + default: + done = 0; + break; + } + + if(!done) + { + DEBUG_LOG1("libvterm: Unhandled CSI SGR %lu\n", arg); + } + + while(CSI_ARG_HAS_MORE(args[argi++])); + } + } + + INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNUSED) + { + int argi = 0; + + if(state->pen.bold) + args[argi++] = 1; + + if(state->pen.italic) + args[argi++] = 3; + + if(state->pen.underline == 1) + args[argi++] = 4; + + if(state->pen.blink) + args[argi++] = 5; + + if(state->pen.reverse) + args[argi++] = 7; + + if(state->pen.strike) + args[argi++] = 9; + + if(state->pen.font) + args[argi++] = 10 + state->pen.font; + + if(state->pen.underline == 2) + args[argi++] = 21; + + if(state->fg_index >= 0 && state->fg_index < 8) + args[argi++] = 30 + state->fg_index; + else if(state->fg_index >= 8 && state->fg_index < 16) + args[argi++] = 90 + state->fg_index - 8; + else if(state->fg_index >= 16 && state->fg_index < 256) { + args[argi++] = CSI_ARG_FLAG_MORE|38; + args[argi++] = CSI_ARG_FLAG_MORE|5; + args[argi++] = state->fg_index; + } + else if(state->fg_index == -1) { + /* Send palette 2 if the actual FG colour is not default */ + if(state->pen.fg.red != state->default_fg.red || + state->pen.fg.green != state->default_fg.green || + state->pen.fg.blue != state->default_fg.blue ) { + args[argi++] = CSI_ARG_FLAG_MORE|38; + args[argi++] = CSI_ARG_FLAG_MORE|2; + args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.red; + args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.green; + args[argi++] = state->pen.fg.blue; + } + } + + if(state->bg_index >= 0 && state->bg_index < 8) + args[argi++] = 40 + state->bg_index; + else if(state->bg_index >= 8 && state->bg_index < 16) + args[argi++] = 100 + state->bg_index - 8; + else if(state->bg_index >= 16 && state->bg_index < 256) { + args[argi++] = CSI_ARG_FLAG_MORE|48; + args[argi++] = CSI_ARG_FLAG_MORE|5; + args[argi++] = state->bg_index; + } + else if(state->bg_index == -1) { + /* Send palette 2 if the actual BG colour is not default */ + if(state->pen.bg.red != state->default_bg.red || + state->pen.bg.green != state->default_bg.green || + state->pen.bg.blue != state->default_bg.blue ) { + args[argi++] = CSI_ARG_FLAG_MORE|48; + args[argi++] = CSI_ARG_FLAG_MORE|2; + args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.red; + args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.green; + args[argi++] = state->pen.bg.blue; + } + } + + return argi; + } + + int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val) + { + switch(attr) { + case VTERM_ATTR_BOLD: + val->boolean = state->pen.bold; + return 1; + + case VTERM_ATTR_UNDERLINE: + val->number = state->pen.underline; + return 1; + + case VTERM_ATTR_ITALIC: + val->boolean = state->pen.italic; + return 1; + + case VTERM_ATTR_BLINK: + val->boolean = state->pen.blink; + return 1; + + case VTERM_ATTR_REVERSE: + val->boolean = state->pen.reverse; + return 1; + + case VTERM_ATTR_STRIKE: + val->boolean = state->pen.strike; + return 1; + + case VTERM_ATTR_FONT: + val->number = state->pen.font; + return 1; + + case VTERM_ATTR_FOREGROUND: + val->color = state->pen.fg; + return 1; + + case VTERM_ATTR_BACKGROUND: + val->color = state->pen.bg; + return 1; + } + + return 0; + } *** ../vim-8.0.0692/src/libvterm/src/rect.h 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/rect.h 2017-06-30 20:59:02.546673287 +0200 *************** *** 0 **** --- 1,56 ---- + /* + * Some utility functions on VTermRect structures + */ + + #define STRFrect "(%d,%d-%d,%d)" + #define ARGSrect(r) (r).start_row, (r).start_col, (r).end_row, (r).end_col + + /* Expand dst to contain src as well */ + static void rect_expand(VTermRect *dst, VTermRect *src) + { + if(dst->start_row > src->start_row) dst->start_row = src->start_row; + if(dst->start_col > src->start_col) dst->start_col = src->start_col; + if(dst->end_row < src->end_row) dst->end_row = src->end_row; + if(dst->end_col < src->end_col) dst->end_col = src->end_col; + } + + /* Clip the dst to ensure it does not step outside of bounds */ + static void rect_clip(VTermRect *dst, VTermRect *bounds) + { + if(dst->start_row < bounds->start_row) dst->start_row = bounds->start_row; + if(dst->start_col < bounds->start_col) dst->start_col = bounds->start_col; + if(dst->end_row > bounds->end_row) dst->end_row = bounds->end_row; + if(dst->end_col > bounds->end_col) dst->end_col = bounds->end_col; + /* Ensure it doesn't end up negatively-sized */ + if(dst->end_row < dst->start_row) dst->end_row = dst->start_row; + if(dst->end_col < dst->start_col) dst->end_col = dst->start_col; + } + + /* True if the two rectangles are equal */ + static int rect_equal(VTermRect *a, VTermRect *b) + { + return (a->start_row == b->start_row) && + (a->start_col == b->start_col) && + (a->end_row == b->end_row) && + (a->end_col == b->end_col); + } + + /* True if small is contained entirely within big */ + static int rect_contains(VTermRect *big, VTermRect *small) + { + if(small->start_row < big->start_row) return 0; + if(small->start_col < big->start_col) return 0; + if(small->end_row > big->end_row) return 0; + if(small->end_col > big->end_col) return 0; + return 1; + } + + /* True if the rectangles overlap at all */ + static int rect_intersects(VTermRect *a, VTermRect *b) + { + if(a->start_row > b->end_row || b->start_row > a->end_row) + return 0; + if(a->start_col > b->end_col || b->start_col > a->end_col) + return 0; + return 1; + } *** ../vim-8.0.0692/src/libvterm/src/screen.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/screen.c 2017-07-02 18:10:22.287860693 +0200 *************** *** 0 **** --- 1,937 ---- + #include "vterm_internal.h" + + #include + #include + + #include "rect.h" + #include "utf8.h" + + #define UNICODE_SPACE 0x20 + #define UNICODE_LINEFEED 0x0a + + /* State of the pen at some moment in time, also used in a cell */ + typedef struct + { + /* After the bitfield */ + VTermColor fg, bg; + + unsigned int bold : 1; + unsigned int underline : 2; + unsigned int italic : 1; + unsigned int blink : 1; + unsigned int reverse : 1; + unsigned int strike : 1; + unsigned int font : 4; /* 0 to 9 */ + + /* Extra state storage that isn't strictly pen-related */ + unsigned int protected_cell : 1; + unsigned int dwl : 1; /* on a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */ + } ScreenPen; + + /* Internal representation of a screen cell */ + typedef struct + { + uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; + ScreenPen pen; + } ScreenCell; + + static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell); + + struct VTermScreen + { + VTerm *vt; + VTermState *state; + + const VTermScreenCallbacks *callbacks; + void *cbdata; + + VTermDamageSize damage_merge; + /* start_row == -1 => no damage */ + VTermRect damaged; + VTermRect pending_scrollrect; + int pending_scroll_downward, pending_scroll_rightward; + + int rows; + int cols; + int global_reverse; + + /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ + ScreenCell *buffers[2]; + + /* buffer will == buffers[0] or buffers[1], depending on altscreen */ + ScreenCell *buffer; + + /* buffer for a single screen row used in scrollback storage callbacks */ + VTermScreenCell *sb_buffer; + + ScreenPen pen; + }; + + static ScreenCell *getcell(const VTermScreen *screen, int row, int col) + { + if(row < 0 || row >= screen->rows) + return NULL; + if(col < 0 || col >= screen->cols) + return NULL; + return screen->buffer + (screen->cols * row) + col; + } + + static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols) + { + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); + int row, col; + + for(row = 0; row < new_rows; row++) { + for(col = 0; col < new_cols; col++) { + ScreenCell *new_cell = new_buffer + row*new_cols + col; + + if(buffer && row < screen->rows && col < screen->cols) + *new_cell = buffer[row * screen->cols + col]; + else { + new_cell->chars[0] = 0; + new_cell->pen = screen->pen; + } + } + } + + if(buffer) + vterm_allocator_free(screen->vt, buffer); + + return new_buffer; + } + + static void damagerect(VTermScreen *screen, VTermRect rect) + { + VTermRect emit; + + switch(screen->damage_merge) { + case VTERM_DAMAGE_CELL: + /* Always emit damage event */ + emit = rect; + break; + + case VTERM_DAMAGE_ROW: + /* Emit damage longer than one row. Try to merge with existing damage in + * the same row */ + if(rect.end_row > rect.start_row + 1) { + /* Bigger than 1 line - flush existing, emit this */ + vterm_screen_flush_damage(screen); + emit = rect; + } + else if(screen->damaged.start_row == -1) { + /* None stored yet */ + screen->damaged = rect; + return; + } + else if(rect.start_row == screen->damaged.start_row) { + /* Merge with the stored line */ + if(screen->damaged.start_col > rect.start_col) + screen->damaged.start_col = rect.start_col; + if(screen->damaged.end_col < rect.end_col) + screen->damaged.end_col = rect.end_col; + return; + } + else { + /* Emit the currently stored line, store a new one */ + emit = screen->damaged; + screen->damaged = rect; + } + break; + + case VTERM_DAMAGE_SCREEN: + case VTERM_DAMAGE_SCROLL: + /* Never emit damage event */ + if(screen->damaged.start_row == -1) + screen->damaged = rect; + else { + rect_expand(&screen->damaged, &rect); + } + return; + + default: + DEBUG_LOG1("TODO: Maybe merge damage for level %d\n", screen->damage_merge); + return; + } + + if(screen->callbacks && screen->callbacks->damage) + (*screen->callbacks->damage)(emit, screen->cbdata); + } + + static void damagescreen(VTermScreen *screen) + { + VTermRect rect = {0,0,0,0}; + rect.end_row = screen->rows; + rect.end_col = screen->cols; + + damagerect(screen, rect); + } + + static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) + { + int i; + int col; + VTermRect rect; + + VTermScreen *screen = user; + ScreenCell *cell = getcell(screen, pos.row, pos.col); + + if(!cell) + return 0; + + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) { + cell->chars[i] = info->chars[i]; + cell->pen = screen->pen; + } + if(i < VTERM_MAX_CHARS_PER_CELL) + cell->chars[i] = 0; + + for(col = 1; col < info->width; col++) + getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1; + + rect.start_row = pos.row; + rect.end_row = pos.row+1; + rect.start_col = pos.col; + rect.end_col = pos.col+info->width; + + cell->pen.protected_cell = info->protected_cell; + cell->pen.dwl = info->dwl; + cell->pen.dhl = info->dhl; + + damagerect(screen, rect); + + return 1; + } + + static int moverect_internal(VTermRect dest, VTermRect src, void *user) + { + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->sb_pushline && + dest.start_row == 0 && dest.start_col == 0 && /* starts top-left corner */ + dest.end_col == screen->cols && /* full width */ + screen->buffer == screen->buffers[0]) { /* not altscreen */ + VTermPos pos; + for(pos.row = 0; pos.row < src.start_row; pos.row++) { + for(pos.col = 0; pos.col < screen->cols; pos.col++) + vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col); + + (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata); + } + } + + { + int cols = src.end_col - src.start_col; + int downward = src.start_row - dest.start_row; + int init_row, test_row, inc_row; + int row; + + if(downward < 0) { + init_row = dest.end_row - 1; + test_row = dest.start_row - 1; + inc_row = -1; + } + else { + init_row = dest.start_row; + test_row = dest.end_row; + inc_row = +1; + } + + for(row = init_row; row != test_row; row += inc_row) + memmove(getcell(screen, row, dest.start_col), + getcell(screen, row + downward, src.start_col), + cols * sizeof(ScreenCell)); + } + + return 1; + } + + static int moverect_user(VTermRect dest, VTermRect src, void *user) + { + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->moverect) { + if(screen->damage_merge != VTERM_DAMAGE_SCROLL) + /* Avoid an infinite loop */ + vterm_screen_flush_damage(screen); + + if((*screen->callbacks->moverect)(dest, src, screen->cbdata)) + return 1; + } + + damagerect(screen, dest); + + return 1; + } + + static int erase_internal(VTermRect rect, int selective, void *user) + { + VTermScreen *screen = user; + int row, col; + + for(row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) { + const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row); + + for(col = rect.start_col; col < rect.end_col; col++) { + ScreenCell *cell = getcell(screen, row, col); + + if(selective && cell->pen.protected_cell) + continue; + + cell->chars[0] = 0; + cell->pen = screen->pen; + cell->pen.dwl = info->doublewidth; + cell->pen.dhl = info->doubleheight; + } + } + + return 1; + } + + static int erase_user(VTermRect rect, int selective UNUSED, void *user) + { + VTermScreen *screen = user; + + damagerect(screen, rect); + + return 1; + } + + static int erase(VTermRect rect, int selective, void *user) + { + erase_internal(rect, selective, user); + return erase_user(rect, 0, user); + } + + static int scrollrect(VTermRect rect, int downward, int rightward, void *user) + { + VTermScreen *screen = user; + + if(screen->damage_merge != VTERM_DAMAGE_SCROLL) { + vterm_scroll_rect(rect, downward, rightward, + moverect_internal, erase_internal, screen); + + vterm_screen_flush_damage(screen); + + vterm_scroll_rect(rect, downward, rightward, + moverect_user, erase_user, screen); + + return 1; + } + + if(screen->damaged.start_row != -1 && + !rect_intersects(&rect, &screen->damaged)) { + vterm_screen_flush_damage(screen); + } + + if(screen->pending_scrollrect.start_row == -1) { + screen->pending_scrollrect = rect; + screen->pending_scroll_downward = downward; + screen->pending_scroll_rightward = rightward; + } + else if(rect_equal(&screen->pending_scrollrect, &rect) && + ((screen->pending_scroll_downward == 0 && downward == 0) || + (screen->pending_scroll_rightward == 0 && rightward == 0))) { + screen->pending_scroll_downward += downward; + screen->pending_scroll_rightward += rightward; + } + else { + vterm_screen_flush_damage(screen); + + screen->pending_scrollrect = rect; + screen->pending_scroll_downward = downward; + screen->pending_scroll_rightward = rightward; + } + + vterm_scroll_rect(rect, downward, rightward, + moverect_internal, erase_internal, screen); + + if(screen->damaged.start_row == -1) + return 1; + + if(rect_contains(&rect, &screen->damaged)) { + /* Scroll region entirely contains the damage; just move it */ + vterm_rect_move(&screen->damaged, -downward, -rightward); + rect_clip(&screen->damaged, &rect); + } + /* There are a number of possible cases here, but lets restrict this to only + * the common case where we might actually gain some performance by + * optimising it. Namely, a vertical scroll that neatly cuts the damage + * region in half. + */ + else if(rect.start_col <= screen->damaged.start_col && + rect.end_col >= screen->damaged.end_col && + rightward == 0) { + if(screen->damaged.start_row >= rect.start_row && + screen->damaged.start_row < rect.end_row) { + screen->damaged.start_row -= downward; + if(screen->damaged.start_row < rect.start_row) + screen->damaged.start_row = rect.start_row; + if(screen->damaged.start_row > rect.end_row) + screen->damaged.start_row = rect.end_row; + } + if(screen->damaged.end_row >= rect.start_row && + screen->damaged.end_row < rect.end_row) { + screen->damaged.end_row -= downward; + if(screen->damaged.end_row < rect.start_row) + screen->damaged.end_row = rect.start_row; + if(screen->damaged.end_row > rect.end_row) + screen->damaged.end_row = rect.end_row; + } + } + else { + DEBUG_LOG2("TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n", + ARGSrect(screen->damaged), ARGSrect(rect)); + } + + return 1; + } + + static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) + { + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->movecursor) + return (*screen->callbacks->movecursor)(pos, oldpos, visible, screen->cbdata); + + return 0; + } + + static int setpenattr(VTermAttr attr, VTermValue *val, void *user) + { + VTermScreen *screen = user; + + switch(attr) { + case VTERM_ATTR_BOLD: + screen->pen.bold = val->boolean; + return 1; + case VTERM_ATTR_UNDERLINE: + screen->pen.underline = val->number; + return 1; + case VTERM_ATTR_ITALIC: + screen->pen.italic = val->boolean; + return 1; + case VTERM_ATTR_BLINK: + screen->pen.blink = val->boolean; + return 1; + case VTERM_ATTR_REVERSE: + screen->pen.reverse = val->boolean; + return 1; + case VTERM_ATTR_STRIKE: + screen->pen.strike = val->boolean; + return 1; + case VTERM_ATTR_FONT: + screen->pen.font = val->number; + return 1; + case VTERM_ATTR_FOREGROUND: + screen->pen.fg = val->color; + return 1; + case VTERM_ATTR_BACKGROUND: + screen->pen.bg = val->color; + return 1; + } + + return 0; + } + + static int settermprop(VTermProp prop, VTermValue *val, void *user) + { + VTermScreen *screen = user; + + switch(prop) { + case VTERM_PROP_ALTSCREEN: + if(val->boolean && !screen->buffers[1]) + return 0; + + screen->buffer = val->boolean ? screen->buffers[1] : screen->buffers[0]; + /* only send a damage event on disable; because during enable there's an + * erase that sends a damage anyway + */ + if(!val->boolean) + damagescreen(screen); + break; + case VTERM_PROP_REVERSE: + screen->global_reverse = val->boolean; + damagescreen(screen); + break; + default: + ; /* ignore */ + } + + if(screen->callbacks && screen->callbacks->settermprop) + return (*screen->callbacks->settermprop)(prop, val, screen->cbdata); + + return 1; + } + + static int bell(void *user) + { + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->bell) + return (*screen->callbacks->bell)(screen->cbdata); + + return 0; + } + + static int resize(int new_rows, int new_cols, VTermPos *delta, void *user) + { + VTermScreen *screen = user; + + int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]); + + int old_rows = screen->rows; + int old_cols = screen->cols; + int first_blank_row; + + if(!is_altscreen && new_rows < old_rows) { + /* Fewer rows - determine if we're going to scroll at all, and if so, push + those lines to scrollback */ + VTermPos pos = { 0, 0 }; + VTermPos cursor = screen->state->pos; + /* Find the first blank row after the cursor. */ + for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--) + if(!vterm_screen_is_eol(screen, pos) || cursor.row == pos.row) + break; + + first_blank_row = pos.row + 1; + if(first_blank_row > new_rows) { + VTermRect rect = {0,0,0,0}; + rect.end_row = old_rows; + rect.end_col = old_cols; + scrollrect(rect, first_blank_row - new_rows, 0, user); + vterm_screen_flush_damage(screen); + + delta->row -= first_blank_row - new_rows; + } + } + + screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols); + if(screen->buffers[1]) + screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols); + + screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0]; + + screen->rows = new_rows; + screen->cols = new_cols; + + if(screen->sb_buffer) + vterm_allocator_free(screen->vt, screen->sb_buffer); + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); + + if(new_cols > old_cols) { + VTermRect rect; + rect.start_row = 0; + rect.end_row = old_rows; + rect.start_col = old_cols; + rect.end_col = new_cols; + damagerect(screen, rect); + } + + if(new_rows > old_rows) { + if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) { + int rows = new_rows - old_rows; + while(rows) { + VTermRect rect = {0,0,0,0}; + VTermPos pos = { 0, 0 }; + if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata))) + break; + + rect.end_row = screen->rows; + rect.end_col = screen->cols; + scrollrect(rect, -1, 0, user); + + for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width) + vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col); + + rect.end_row = 1; + damagerect(screen, rect); + + vterm_screen_flush_damage(screen); + + rows--; + delta->row++; + } + } + + { + VTermRect rect; + rect.start_row = old_rows; + rect.end_row = new_rows; + rect.start_col = 0; + rect.end_col = new_cols; + damagerect(screen, rect); + } + } + + if(screen->callbacks && screen->callbacks->resize) + return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata); + + return 1; + } + + static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) + { + VTermScreen *screen = user; + int col; + VTermRect rect; + + if(newinfo->doublewidth != oldinfo->doublewidth || + newinfo->doubleheight != oldinfo->doubleheight) { + for(col = 0; col < screen->cols; col++) { + ScreenCell *cell = getcell(screen, row, col); + cell->pen.dwl = newinfo->doublewidth; + cell->pen.dhl = newinfo->doubleheight; + } + + rect.start_row = row; + rect.end_row = row + 1; + rect.start_col = 0; + rect.end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols; + damagerect(screen, rect); + + if(newinfo->doublewidth) { + rect.start_col = screen->cols / 2; + rect.end_col = screen->cols; + + erase_internal(rect, 0, user); + } + } + + return 1; + } + + static VTermStateCallbacks state_cbs = { + &putglyph, /* putglyph */ + &movecursor, /* movecursor */ + &scrollrect, /* scrollrect */ + NULL, /* moverect */ + &erase, /* erase */ + NULL, /* initpen */ + &setpenattr, /* setpenattr */ + &settermprop, /* settermprop */ + &bell, /* bell */ + &resize, /* resize */ + &setlineinfo /* setlineinfo */ + }; + + static VTermScreen *screen_new(VTerm *vt) + { + VTermState *state = vterm_obtain_state(vt); + VTermScreen *screen; + int rows, cols; + + if(!state) + return NULL; + + screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); + + vterm_get_size(vt, &rows, &cols); + + screen->vt = vt; + screen->state = state; + + screen->damage_merge = VTERM_DAMAGE_CELL; + screen->damaged.start_row = -1; + screen->pending_scrollrect.start_row = -1; + + screen->rows = rows; + screen->cols = cols; + + screen->callbacks = NULL; + screen->cbdata = NULL; + + screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols); + + screen->buffer = screen->buffers[0]; + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols); + + vterm_state_set_callbacks(screen->state, &state_cbs, screen); + + return screen; + } + + INTERNAL void vterm_screen_free(VTermScreen *screen) + { + vterm_allocator_free(screen->vt, screen->buffers[0]); + if(screen->buffers[1]) + vterm_allocator_free(screen->vt, screen->buffers[1]); + + vterm_allocator_free(screen->vt, screen->sb_buffer); + + vterm_allocator_free(screen->vt, screen); + } + + void vterm_screen_reset(VTermScreen *screen, int hard) + { + screen->damaged.start_row = -1; + screen->pending_scrollrect.start_row = -1; + vterm_state_reset(screen->state, hard); + vterm_screen_flush_damage(screen); + } + + static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect) + { + size_t outpos = 0; + int padding = 0; + int row, col; + + #define PUT(c) \ + if(utf8) { \ + size_t thislen = utf8_seqlen(c); \ + if(buffer && outpos + thislen <= len) \ + outpos += fill_utf8((c), (char *)buffer + outpos); \ + else \ + outpos += thislen; \ + } \ + else { \ + if(buffer && outpos + 1 <= len) \ + ((uint32_t*)buffer)[outpos++] = (c); \ + else \ + outpos++; \ + } + + for(row = rect.start_row; row < rect.end_row; row++) { + for(col = rect.start_col; col < rect.end_col; col++) { + ScreenCell *cell = getcell(screen, row, col); + int i; + + if(cell->chars[0] == 0) + /* Erased cell, might need a space */ + padding++; + else if(cell->chars[0] == (uint32_t)-1) + /* Gap behind a double-width char, do nothing */ + ; + else { + while(padding) { + PUT(UNICODE_SPACE); + padding--; + } + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { + PUT(cell->chars[i]); + } + } + } + + if(row < rect.end_row - 1) { + PUT(UNICODE_LINEFEED); + padding = 0; + } + } + + return outpos; + } + + size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect) + { + return _get_chars(screen, 0, chars, len, rect); + } + + size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect) + { + return _get_chars(screen, 1, str, len, rect); + } + + /* Copy internal to external representation of a screen cell */ + int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell) + { + ScreenCell *intcell = getcell(screen, pos.row, pos.col); + int i; + + if(!intcell) + return 0; + + for(i = 0; ; i++) { + cell->chars[i] = intcell->chars[i]; + if(!intcell->chars[i]) + break; + } + + cell->attrs.bold = intcell->pen.bold; + cell->attrs.underline = intcell->pen.underline; + cell->attrs.italic = intcell->pen.italic; + cell->attrs.blink = intcell->pen.blink; + cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse; + cell->attrs.strike = intcell->pen.strike; + cell->attrs.font = intcell->pen.font; + + cell->attrs.dwl = intcell->pen.dwl; + cell->attrs.dhl = intcell->pen.dhl; + + cell->fg = intcell->pen.fg; + cell->bg = intcell->pen.bg; + + if(pos.col < (screen->cols - 1) && + getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1) + cell->width = 2; + else + cell->width = 1; + + return 1; + } + + /* Copy external to internal representation of a screen cell */ + /* static because it's only used internally for sb_popline during resize */ + static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell) + { + ScreenCell *intcell = getcell(screen, pos.row, pos.col); + int i; + + if(!intcell) + return 0; + + for(i = 0; ; i++) { + intcell->chars[i] = cell->chars[i]; + if(!cell->chars[i]) + break; + } + + intcell->pen.bold = cell->attrs.bold; + intcell->pen.underline = cell->attrs.underline; + intcell->pen.italic = cell->attrs.italic; + intcell->pen.blink = cell->attrs.blink; + intcell->pen.reverse = cell->attrs.reverse ^ screen->global_reverse; + intcell->pen.strike = cell->attrs.strike; + intcell->pen.font = cell->attrs.font; + + intcell->pen.fg = cell->fg; + intcell->pen.bg = cell->bg; + + if(cell->width == 2) + getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1; + + return 1; + } + + int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos) + { + /* This cell is EOL if this and every cell to the right is black */ + for(; pos.col < screen->cols; pos.col++) { + ScreenCell *cell = getcell(screen, pos.row, pos.col); + if(cell->chars[0] != 0) + return 0; + } + + return 1; + } + + VTermScreen *vterm_obtain_screen(VTerm *vt) + { + VTermScreen *screen; + if(vt->screen) + return vt->screen; + + screen = screen_new(vt); + vt->screen = screen; + + return screen; + } + + void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) + { + + if(!screen->buffers[1] && altscreen) { + int rows, cols; + vterm_get_size(screen->vt, &rows, &cols); + + screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols); + } + } + + void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user) + { + screen->callbacks = callbacks; + screen->cbdata = user; + } + + void *vterm_screen_get_cbdata(VTermScreen *screen) + { + return screen->cbdata; + } + + void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user) + { + vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user); + } + + void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen) + { + return vterm_state_get_unrecognised_fbdata(screen->state); + } + + void vterm_screen_flush_damage(VTermScreen *screen) + { + if(screen->pending_scrollrect.start_row != -1) { + vterm_scroll_rect(screen->pending_scrollrect, screen->pending_scroll_downward, screen->pending_scroll_rightward, + moverect_user, erase_user, screen); + + screen->pending_scrollrect.start_row = -1; + } + + if(screen->damaged.start_row != -1) { + if(screen->callbacks && screen->callbacks->damage) + (*screen->callbacks->damage)(screen->damaged, screen->cbdata); + + screen->damaged.start_row = -1; + } + } + + void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size) + { + vterm_screen_flush_damage(screen); + screen->damage_merge = size; + } + + static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b) + { + if((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold)) + return 1; + if((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline)) + return 1; + if((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic)) + return 1; + if((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink)) + return 1; + if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse)) + return 1; + if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike)) + return 1; + if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font)) + return 1; + if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_equal(a->pen.fg, b->pen.fg)) + return 1; + if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg)) + return 1; + + return 0; + } + + int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs) + { + int col; + + ScreenCell *target = getcell(screen, pos.row, pos.col); + + /* TODO: bounds check */ + extent->start_row = pos.row; + extent->end_row = pos.row + 1; + + if(extent->start_col < 0) + extent->start_col = 0; + if(extent->end_col < 0) + extent->end_col = screen->cols; + + for(col = pos.col - 1; col >= extent->start_col; col--) + if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) + break; + extent->start_col = col + 1; + + for(col = pos.col + 1; col < extent->end_col; col++) + if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) + break; + extent->end_col = col - 1; + + return 1; + } *** ../vim-8.0.0692/src/libvterm/src/state.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/state.c 2017-07-02 18:12:23.526978679 +0200 *************** *** 0 **** --- 1,1851 ---- + #include "vterm_internal.h" + + #include + #include + + #define strneq(a,b,n) (strncmp(a,b,n)==0) + + #if defined(DEBUG) && DEBUG > 1 + # define DEBUG_GLYPH_COMBINE + #endif + + /* Some convenient wrappers to make callback functions easier */ + + static void putglyph(VTermState *state, const uint32_t chars[], int width, VTermPos pos) + { + VTermGlyphInfo info; + info.chars = chars; + info.width = width; + info.protected_cell = state->protected_cell; + info.dwl = state->lineinfo[pos.row].doublewidth; + info.dhl = state->lineinfo[pos.row].doubleheight; + + if(state->callbacks && state->callbacks->putglyph) + if((*state->callbacks->putglyph)(&info, pos, state->cbdata)) + return; + + DEBUG_LOG3("libvterm: Unhandled putglyph U+%04x at (%d,%d)\n", chars[0], pos.col, pos.row); + } + + static void updatecursor(VTermState *state, VTermPos *oldpos, int cancel_phantom) + { + if(state->pos.col == oldpos->col && state->pos.row == oldpos->row) + return; + + if(cancel_phantom) + state->at_phantom = 0; + + if(state->callbacks && state->callbacks->movecursor) + if((*state->callbacks->movecursor)(state->pos, *oldpos, state->mode.cursor_visible, state->cbdata)) + return; + } + + static void erase(VTermState *state, VTermRect rect, int selective) + { + if(state->callbacks && state->callbacks->erase) + if((*state->callbacks->erase)(rect, selective, state->cbdata)) + return; + } + + static VTermState *vterm_state_new(VTerm *vt) + { + VTermState *state = vterm_allocator_malloc(vt, sizeof(VTermState)); + + state->vt = vt; + + state->rows = vt->rows; + state->cols = vt->cols; + + state->mouse_col = 0; + state->mouse_row = 0; + state->mouse_buttons = 0; + + state->mouse_protocol = MOUSE_X10; + + state->callbacks = NULL; + state->cbdata = NULL; + + vterm_state_newpen(state); + + state->bold_is_highbright = 0; + + return state; + } + + INTERNAL void vterm_state_free(VTermState *state) + { + vterm_allocator_free(state->vt, state->tabstops); + vterm_allocator_free(state->vt, state->lineinfo); + vterm_allocator_free(state->vt, state->combine_chars); + vterm_allocator_free(state->vt, state); + } + + static void scroll(VTermState *state, VTermRect rect, int downward, int rightward) + { + int rows; + int cols; + if(!downward && !rightward) + return; + + rows = rect.end_row - rect.start_row; + if(downward > rows) + downward = rows; + else if(downward < -rows) + downward = -rows; + + cols = rect.end_col - rect.start_col; + if(rightward > cols) + rightward = cols; + else if(rightward < -cols) + rightward = -cols; + + /* Update lineinfo if full line */ + if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) { + int height = rect.end_row - rect.start_row - abs(downward); + + if(downward > 0) + memmove(state->lineinfo + rect.start_row, + state->lineinfo + rect.start_row + downward, + height * sizeof(state->lineinfo[0])); + else + memmove(state->lineinfo + rect.start_row - downward, + state->lineinfo + rect.start_row, + height * sizeof(state->lineinfo[0])); + } + + if(state->callbacks && state->callbacks->scrollrect) + if((*state->callbacks->scrollrect)(rect, downward, rightward, state->cbdata)) + return; + + if(state->callbacks) + vterm_scroll_rect(rect, downward, rightward, + state->callbacks->moverect, state->callbacks->erase, state->cbdata); + } + + static void linefeed(VTermState *state) + { + if(state->pos.row == SCROLLREGION_BOTTOM(state) - 1) { + VTermRect rect; + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, 1, 0); + } + else if(state->pos.row < state->rows-1) + state->pos.row++; + } + + static void grow_combine_buffer(VTermState *state) + { + size_t new_size = state->combine_chars_size * 2; + uint32_t *new_chars = vterm_allocator_malloc(state->vt, new_size * sizeof(new_chars[0])); + + memcpy(new_chars, state->combine_chars, state->combine_chars_size * sizeof(new_chars[0])); + + vterm_allocator_free(state->vt, state->combine_chars); + + state->combine_chars = new_chars; + state->combine_chars_size = new_size; + } + + static void set_col_tabstop(VTermState *state, int col) + { + unsigned char mask = 1 << (col & 7); + state->tabstops[col >> 3] |= mask; + } + + static void clear_col_tabstop(VTermState *state, int col) + { + unsigned char mask = 1 << (col & 7); + state->tabstops[col >> 3] &= ~mask; + } + + static int is_col_tabstop(VTermState *state, int col) + { + unsigned char mask = 1 << (col & 7); + return state->tabstops[col >> 3] & mask; + } + + static int is_cursor_in_scrollregion(const VTermState *state) + { + if(state->pos.row < state->scrollregion_top || + state->pos.row >= SCROLLREGION_BOTTOM(state)) + return 0; + if(state->pos.col < SCROLLREGION_LEFT(state) || + state->pos.col >= SCROLLREGION_RIGHT(state)) + return 0; + + return 1; + } + + static void tab(VTermState *state, int count, int direction) + { + while(count > 0) { + if(direction > 0) { + if(state->pos.col >= THISROWWIDTH(state)-1) + return; + + state->pos.col++; + } + else if(direction < 0) { + if(state->pos.col < 1) + return; + + state->pos.col--; + } + + if(is_col_tabstop(state, state->pos.col)) + count--; + } + } + + #define NO_FORCE 0 + #define FORCE 1 + + #define DWL_OFF 0 + #define DWL_ON 1 + + #define DHL_OFF 0 + #define DHL_TOP 1 + #define DHL_BOTTOM 2 + + static void set_lineinfo(VTermState *state, int row, int force, int dwl, int dhl) + { + VTermLineInfo info = state->lineinfo[row]; + + if(dwl == DWL_OFF) + info.doublewidth = DWL_OFF; + else if(dwl == DWL_ON) + info.doublewidth = DWL_ON; + /* else -1 to ignore */ + + if(dhl == DHL_OFF) + info.doubleheight = DHL_OFF; + else if(dhl == DHL_TOP) + info.doubleheight = DHL_TOP; + else if(dhl == DHL_BOTTOM) + info.doubleheight = DHL_BOTTOM; + + if((state->callbacks && + state->callbacks->setlineinfo && + (*state->callbacks->setlineinfo)(row, &info, state->lineinfo + row, state->cbdata)) + || force) + state->lineinfo[row] = info; + } + + static int on_text(const char bytes[], size_t len, void *user) + { + VTermState *state = user; + uint32_t *codepoints; + int npoints = 0; + size_t eaten = 0; + VTermEncodingInstance *encoding; + int i = 0; + + VTermPos oldpos = state->pos; + + /* We'll have at most len codepoints */ + codepoints = vterm_allocator_malloc(state->vt, len * sizeof(uint32_t)); + + encoding = + state->gsingle_set ? &state->encoding[state->gsingle_set] : + !(bytes[eaten] & 0x80) ? &state->encoding[state->gl_set] : + state->vt->mode.utf8 ? &state->encoding_utf8 : + &state->encoding[state->gr_set]; + + (*encoding->enc->decode)(encoding->enc, encoding->data, + codepoints, &npoints, state->gsingle_set ? 1 : len, + bytes, &eaten, len); + + /* There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet + * for even a single codepoint + */ + if(!npoints) + { + vterm_allocator_free(state->vt, codepoints); + return 0; + } + + if(state->gsingle_set && npoints) + state->gsingle_set = 0; + + /* This is a combining char. that needs to be merged with the previous + * glyph output */ + if(vterm_unicode_is_combining(codepoints[i])) { + /* See if the cursor has moved since */ + if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) { + #ifdef DEBUG_GLYPH_COMBINE + int printpos; + printf("DEBUG: COMBINING SPLIT GLYPH of chars {"); + for(printpos = 0; state->combine_chars[printpos]; printpos++) + printf("U+%04x ", state->combine_chars[printpos]); + printf("} + {"); + #endif + + /* Find where we need to append these combining chars */ + int saved_i = 0; + while(state->combine_chars[saved_i]) + saved_i++; + + /* Add extra ones */ + while(i < npoints && vterm_unicode_is_combining(codepoints[i])) { + if(saved_i >= (int)state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[saved_i++] = codepoints[i++]; + } + if(saved_i >= (int)state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[saved_i] = 0; + + #ifdef DEBUG_GLYPH_COMBINE + for(; state->combine_chars[printpos]; printpos++) + printf("U+%04x ", state->combine_chars[printpos]); + printf("}\n"); + #endif + + /* Now render it */ + putglyph(state, state->combine_chars, state->combine_width, state->combine_pos); + } + else { + DEBUG_LOG("libvterm: TODO: Skip over split char+combining\n"); + } + } + + for(; i < npoints; i++) { + /* Try to find combining characters following this */ + int glyph_starts = i; + int glyph_ends; + int width = 0; + uint32_t *chars; + + for(glyph_ends = i + 1; glyph_ends < npoints; glyph_ends++) + if(!vterm_unicode_is_combining(codepoints[glyph_ends])) + break; + + chars = vterm_allocator_malloc(state->vt, (glyph_ends - glyph_starts + 1) * sizeof(uint32_t)); + + for( ; i < glyph_ends; i++) { + int this_width; + chars[i - glyph_starts] = codepoints[i]; + this_width = vterm_unicode_width(codepoints[i]); + #ifdef DEBUG + if(this_width < 0) { + fprintf(stderr, "Text with negative-width codepoint U+%04x\n", codepoints[i]); + abort(); + } + #endif + width += this_width; + } + + chars[glyph_ends - glyph_starts] = 0; + i--; + + #ifdef DEBUG_GLYPH_COMBINE + int printpos; + printf("DEBUG: COMBINED GLYPH of %d chars {", glyph_ends - glyph_starts); + for(printpos = 0; printpos < glyph_ends - glyph_starts; printpos++) + printf("U+%04x ", chars[printpos]); + printf("}, onscreen width %d\n", width); + #endif + + if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) { + linefeed(state); + state->pos.col = 0; + state->at_phantom = 0; + } + + if(state->mode.insert) { + /* TODO: This will be a little inefficient for large bodies of text, as + * it'll have to 'ICH' effectively before every glyph. We should scan + * ahead and ICH as many times as required + */ + VTermRect rect; + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + rect.end_col = THISROWWIDTH(state); + scroll(state, rect, 0, -1); + } + + putglyph(state, chars, width, state->pos); + + if(i == npoints - 1) { + /* End of the buffer. Save the chars in case we have to combine with + * more on the next call */ + int save_i; + for(save_i = 0; chars[save_i]; save_i++) { + if(save_i >= (int)state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[save_i] = chars[save_i]; + } + if(save_i >= (int)state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[save_i] = 0; + state->combine_width = width; + state->combine_pos = state->pos; + } + + if(state->pos.col + width >= THISROWWIDTH(state)) { + if(state->mode.autowrap) + state->at_phantom = 1; + } + else { + state->pos.col += width; + } + vterm_allocator_free(state->vt, chars); + } + + updatecursor(state, &oldpos, 0); + + #ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after text: (%d,%d)\n", + state->pos.row, state->pos.col); + abort(); + } + #endif + + vterm_allocator_free(state->vt, codepoints); + return eaten; + } + + static int on_control(unsigned char control, void *user) + { + VTermState *state = user; + + VTermPos oldpos = state->pos; + + switch(control) { + case 0x07: /* BEL - ECMA-48 8.3.3 */ + if(state->callbacks && state->callbacks->bell) + (*state->callbacks->bell)(state->cbdata); + break; + + case 0x08: /* BS - ECMA-48 8.3.5 */ + if(state->pos.col > 0) + state->pos.col--; + break; + + case 0x09: /* HT - ECMA-48 8.3.60 */ + tab(state, 1, +1); + break; + + case 0x0a: /* LF - ECMA-48 8.3.74 */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + linefeed(state); + if(state->mode.newline) + state->pos.col = 0; + break; + + case 0x0d: /* CR - ECMA-48 8.3.15 */ + state->pos.col = 0; + break; + + case 0x0e: /* LS1 - ECMA-48 8.3.76 */ + state->gl_set = 1; + break; + + case 0x0f: /* LS0 - ECMA-48 8.3.75 */ + state->gl_set = 0; + break; + + case 0x84: /* IND - DEPRECATED but implemented for completeness */ + linefeed(state); + break; + + case 0x85: /* NEL - ECMA-48 8.3.86 */ + linefeed(state); + state->pos.col = 0; + break; + + case 0x88: /* HTS - ECMA-48 8.3.62 */ + set_col_tabstop(state, state->pos.col); + break; + + case 0x8d: /* RI - ECMA-48 8.3.104 */ + if(state->pos.row == state->scrollregion_top) { + VTermRect rect; + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, -1, 0); + } + else if(state->pos.row > 0) + state->pos.row--; + break; + + case 0x8e: /* SS2 - ECMA-48 8.3.141 */ + state->gsingle_set = 2; + break; + + case 0x8f: /* SS3 - ECMA-48 8.3.142 */ + state->gsingle_set = 3; + break; + + default: + if(state->fallbacks && state->fallbacks->control) + if((*state->fallbacks->control)(control, state->fbdata)) + return 1; + + return 0; + } + + updatecursor(state, &oldpos, 1); + + #ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after Ctrl %02x: (%d,%d)\n", + control, state->pos.row, state->pos.col); + abort(); + } + #endif + + return 1; + } + + static int settermprop_bool(VTermState *state, VTermProp prop, int v) + { + VTermValue val; + val.boolean = v; + return vterm_state_set_termprop(state, prop, &val); + } + + static int settermprop_int(VTermState *state, VTermProp prop, int v) + { + VTermValue val; + val.number = v; + return vterm_state_set_termprop(state, prop, &val); + } + + static int settermprop_string(VTermState *state, VTermProp prop, const char *str, size_t len) + { + char *strvalue; + int r; + VTermValue val; + strvalue = vterm_allocator_malloc(state->vt, (len+1) * sizeof(char)); + strncpy(strvalue, str, len); + strvalue[len] = 0; + + val.string = strvalue; + r = vterm_state_set_termprop(state, prop, &val); + vterm_allocator_free(state->vt, strvalue); + return r; + } + + static void savecursor(VTermState *state, int save) + { + if(save) { + state->saved.pos = state->pos; + state->saved.mode.cursor_visible = state->mode.cursor_visible; + state->saved.mode.cursor_blink = state->mode.cursor_blink; + state->saved.mode.cursor_shape = state->mode.cursor_shape; + + vterm_state_savepen(state, 1); + } + else { + VTermPos oldpos = state->pos; + + state->pos = state->saved.pos; + + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, state->saved.mode.cursor_visible); + settermprop_bool(state, VTERM_PROP_CURSORBLINK, state->saved.mode.cursor_blink); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, state->saved.mode.cursor_shape); + + vterm_state_savepen(state, 0); + + updatecursor(state, &oldpos, 1); + } + } + + static int on_escape(const char *bytes, size_t len, void *user) + { + VTermState *state = user; + + /* Easier to decode this from the first byte, even though the final + * byte terminates it + */ + switch(bytes[0]) { + case ' ': + if(len != 2) + return 0; + + switch(bytes[1]) { + case 'F': /* S7C1T */ + state->vt->mode.ctrl8bit = 0; + break; + + case 'G': /* S8C1T */ + state->vt->mode.ctrl8bit = 1; + break; + + default: + return 0; + } + return 2; + + case '#': + if(len != 2) + return 0; + + switch(bytes[1]) { + case '3': /* DECDHL top */ + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_TOP); + break; + + case '4': /* DECDHL bottom */ + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_BOTTOM); + break; + + case '5': /* DECSWL */ + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_OFF, DHL_OFF); + break; + + case '6': /* DECDWL */ + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_OFF); + break; + + case '8': /* DECALN */ + { + VTermPos pos; + uint32_t E[] = { 'E', 0 }; + for(pos.row = 0; pos.row < state->rows; pos.row++) + for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++) + putglyph(state, E, 1, pos); + break; + } + + default: + return 0; + } + return 2; + + case '(': case ')': case '*': case '+': /* SCS */ + if(len != 2) + return 0; + + { + int setnum = bytes[0] - 0x28; + VTermEncoding *newenc = vterm_lookup_encoding(ENC_SINGLE_94, bytes[1]); + + if(newenc) { + state->encoding[setnum].enc = newenc; + + if(newenc->init) + (*newenc->init)(newenc, state->encoding[setnum].data); + } + } + + return 2; + + case '7': /* DECSC */ + savecursor(state, 1); + return 1; + + case '8': /* DECRC */ + savecursor(state, 0); + return 1; + + case '<': /* Ignored by VT100. Used in VT52 mode to switch up to VT100 */ + return 1; + + case '=': /* DECKPAM */ + state->mode.keypad = 1; + return 1; + + case '>': /* DECKPNM */ + state->mode.keypad = 0; + return 1; + + case 'c': /* RIS - ECMA-48 8.3.105 */ + { + VTermPos oldpos = state->pos; + vterm_state_reset(state, 1); + if(state->callbacks && state->callbacks->movecursor) + (*state->callbacks->movecursor)(state->pos, oldpos, state->mode.cursor_visible, state->cbdata); + return 1; + } + + case 'n': /* LS2 - ECMA-48 8.3.78 */ + state->gl_set = 2; + return 1; + + case 'o': /* LS3 - ECMA-48 8.3.80 */ + state->gl_set = 3; + return 1; + + case '~': /* LS1R - ECMA-48 8.3.77 */ + state->gr_set = 1; + return 1; + + case '}': /* LS2R - ECMA-48 8.3.79 */ + state->gr_set = 2; + return 1; + + case '|': /* LS3R - ECMA-48 8.3.81 */ + state->gr_set = 3; + return 1; + + default: + return 0; + } + } + + static void set_mode(VTermState *state, int num, int val) + { + switch(num) { + case 4: /* IRM - ECMA-48 7.2.10 */ + state->mode.insert = val; + break; + + case 20: /* LNM - ANSI X3.4-1977 */ + state->mode.newline = val; + break; + + default: + DEBUG_LOG1("libvterm: Unknown mode %d\n", num); + return; + } + } + + static void set_dec_mode(VTermState *state, int num, int val) + { + switch(num) { + case 1: + state->mode.cursor = val; + break; + + case 5: /* DECSCNM - screen mode */ + settermprop_bool(state, VTERM_PROP_REVERSE, val); + break; + + case 6: /* DECOM - origin mode */ + { + VTermPos oldpos = state->pos; + state->mode.origin = val; + state->pos.row = state->mode.origin ? state->scrollregion_top : 0; + state->pos.col = state->mode.origin ? SCROLLREGION_LEFT(state) : 0; + updatecursor(state, &oldpos, 1); + } + break; + + case 7: + state->mode.autowrap = val; + break; + + case 12: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, val); + break; + + case 25: + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, val); + break; + + case 69: /* DECVSSM - vertical split screen mode */ + /* DECLRMM - left/right margin mode */ + state->mode.leftrightmargin = val; + if(val) { + int row; + + /* Setting DECVSSM must clear doublewidth/doubleheight state of every line */ + for(row = 0; row < state->rows; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + } + + break; + + case 1000: + case 1002: + case 1003: + settermprop_int(state, VTERM_PROP_MOUSE, + !val ? VTERM_PROP_MOUSE_NONE : + (num == 1000) ? VTERM_PROP_MOUSE_CLICK : + (num == 1002) ? VTERM_PROP_MOUSE_DRAG : + VTERM_PROP_MOUSE_MOVE); + break; + + case 1005: + state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10; + break; + + case 1006: + state->mouse_protocol = val ? MOUSE_SGR : MOUSE_X10; + break; + + case 1015: + state->mouse_protocol = val ? MOUSE_RXVT : MOUSE_X10; + break; + + case 1047: + settermprop_bool(state, VTERM_PROP_ALTSCREEN, val); + break; + + case 1048: + savecursor(state, val); + break; + + case 1049: + settermprop_bool(state, VTERM_PROP_ALTSCREEN, val); + savecursor(state, val); + break; + + case 2004: + state->mode.bracketpaste = val; + break; + + default: + DEBUG_LOG1("libvterm: Unknown DEC mode %d\n", num); + return; + } + } + + static void request_dec_mode(VTermState *state, int num) + { + int reply; + + switch(num) { + case 1: + reply = state->mode.cursor; + break; + + case 5: + reply = state->mode.screen; + break; + + case 6: + reply = state->mode.origin; + break; + + case 7: + reply = state->mode.autowrap; + break; + + case 12: + reply = state->mode.cursor_blink; + break; + + case 25: + reply = state->mode.cursor_visible; + break; + + case 69: + reply = state->mode.leftrightmargin; + break; + + case 1000: + reply = state->mouse_flags == MOUSE_WANT_CLICK; + break; + + case 1002: + reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_DRAG); + break; + + case 1003: + reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE); + break; + + case 1005: + reply = state->mouse_protocol == MOUSE_UTF8; + break; + + case 1006: + reply = state->mouse_protocol == MOUSE_SGR; + break; + + case 1015: + reply = state->mouse_protocol == MOUSE_RXVT; + break; + + case 1047: + reply = state->mode.alt_screen; + break; + + case 2004: + reply = state->mode.bracketpaste; + + default: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, 0); + return; + } + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, reply ? 1 : 2); + } + + static int on_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) + { + VTermState *state = user; + int leader_byte = 0; + int intermed_byte = 0; + VTermPos oldpos = state->pos; + + /* Some temporaries for later code */ + int count, val; + int row, col; + VTermRect rect; + int selective; + + if(leader && leader[0]) { + if(leader[1]) /* longer than 1 char */ + return 0; + + switch(leader[0]) { + case '?': + case '>': + leader_byte = leader[0]; + break; + default: + return 0; + } + } + + if(intermed && intermed[0]) { + if(intermed[1]) /* longer than 1 char */ + return 0; + + switch(intermed[0]) { + case ' ': + case '"': + case '$': + case '\'': + intermed_byte = intermed[0]; + break; + default: + return 0; + } + } + + oldpos = state->pos; + + #define LBOUND(v,min) if((v) < (min)) (v) = (min) + #define UBOUND(v,max) if((v) > (max)) (v) = (max) + + #define LEADER(l,b) ((l << 8) | b) + #define INTERMED(i,b) ((i << 16) | b) + + switch(intermed_byte << 16 | leader_byte << 8 | command) { + case 0x40: /* ICH - ECMA-48 8.3.64 */ + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + if(state->mode.leftrightmargin) + rect.end_col = SCROLLREGION_RIGHT(state); + else + rect.end_col = THISROWWIDTH(state); + + scroll(state, rect, 0, -count); + + break; + + case 0x41: /* CUU - ECMA-48 8.3.22 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x42: /* CUD - ECMA-48 8.3.19 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x43: /* CUF - ECMA-48 8.3.20 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.col += count; + state->at_phantom = 0; + break; + + case 0x44: /* CUB - ECMA-48 8.3.18 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.col -= count; + state->at_phantom = 0; + break; + + case 0x45: /* CNL - ECMA-48 8.3.12 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.col = 0; + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x46: /* CPL - ECMA-48 8.3.13 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.col = 0; + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x47: /* CHA - ECMA-48 8.3.9 */ + val = CSI_ARG_OR(args[0], 1); + state->pos.col = val-1; + state->at_phantom = 0; + break; + + case 0x48: /* CUP - ECMA-48 8.3.21 */ + row = CSI_ARG_OR(args[0], 1); + col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); + /* zero-based */ + state->pos.row = row-1; + state->pos.col = col-1; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + state->at_phantom = 0; + break; + + case 0x49: /* CHT - ECMA-48 8.3.10 */ + count = CSI_ARG_COUNT(args[0]); + tab(state, count, +1); + break; + + case 0x4a: /* ED - ECMA-48 8.3.39 */ + case LEADER('?', 0x4a): /* DECSED - Selective Erase in Display */ + selective = (leader_byte == '?'); + switch(CSI_ARG(args[0])) { + case CSI_ARG_MISSING: + case 0: + rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; rect.end_col = state->cols; + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + rect.start_row = state->pos.row + 1; rect.end_row = state->rows; + rect.start_col = 0; + for(row = rect.start_row; row < rect.end_row; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + if(rect.end_row > rect.start_row) + erase(state, rect, selective); + break; + + case 1: + rect.start_row = 0; rect.end_row = state->pos.row; + rect.start_col = 0; rect.end_col = state->cols; + for(row = rect.start_row; row < rect.end_row; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1; + rect.end_col = state->pos.col + 1; + if(rect.end_row > rect.start_row) + erase(state, rect, selective); + break; + + case 2: + rect.start_row = 0; rect.end_row = state->rows; + rect.start_col = 0; rect.end_col = state->cols; + for(row = rect.start_row; row < rect.end_row; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + erase(state, rect, selective); + break; + } + break; + + case 0x4b: /* EL - ECMA-48 8.3.41 */ + case LEADER('?', 0x4b): /* DECSEL - Selective Erase in Line */ + selective = (leader_byte == '?'); + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + + switch(CSI_ARG(args[0])) { + case CSI_ARG_MISSING: + case 0: + rect.start_col = state->pos.col; rect.end_col = THISROWWIDTH(state); break; + case 1: + rect.start_col = 0; rect.end_col = state->pos.col + 1; break; + case 2: + rect.start_col = 0; rect.end_col = THISROWWIDTH(state); break; + default: + return 0; + } + + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + break; + + case 0x4c: /* IL - ECMA-48 8.3.67 */ + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, -count, 0); + + break; + + case 0x4d: /* DL - ECMA-48 8.3.32 */ + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, count, 0); + + break; + + case 0x50: /* DCH - ECMA-48 8.3.26 */ + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + if(state->mode.leftrightmargin) + rect.end_col = SCROLLREGION_RIGHT(state); + else + rect.end_col = THISROWWIDTH(state); + + scroll(state, rect, 0, count); + + break; + + case 0x53: /* SU - ECMA-48 8.3.147 */ + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, count, 0); + + break; + + case 0x54: /* SD - ECMA-48 8.3.113 */ + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, -count, 0); + + break; + + case 0x58: /* ECH - ECMA-48 8.3.38 */ + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + rect.end_col = state->pos.col + count; + UBOUND(rect.end_col, THISROWWIDTH(state)); + + erase(state, rect, 0); + break; + + case 0x5a: /* CBT - ECMA-48 8.3.7 */ + count = CSI_ARG_COUNT(args[0]); + tab(state, count, -1); + break; + + case 0x60: /* HPA - ECMA-48 8.3.57 */ + col = CSI_ARG_OR(args[0], 1); + state->pos.col = col-1; + state->at_phantom = 0; + break; + + case 0x61: /* HPR - ECMA-48 8.3.59 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.col += count; + state->at_phantom = 0; + break; + + case 0x63: /* DA - ECMA-48 8.3.24 */ + val = CSI_ARG_OR(args[0], 0); + if(val == 0) + /* DEC VT100 response */ + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?1;2c"); + break; + + case LEADER('>', 0x63): /* DEC secondary Device Attributes */ + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, ">%d;%d;%dc", 0, 100, 0); + break; + + case 0x64: /* VPA - ECMA-48 8.3.158 */ + row = CSI_ARG_OR(args[0], 1); + state->pos.row = row-1; + if(state->mode.origin) + state->pos.row += state->scrollregion_top; + state->at_phantom = 0; + break; + + case 0x65: /* VPR - ECMA-48 8.3.160 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x66: /* HVP - ECMA-48 8.3.63 */ + row = CSI_ARG_OR(args[0], 1); + col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); + /* zero-based */ + state->pos.row = row-1; + state->pos.col = col-1; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + state->at_phantom = 0; + break; + + case 0x67: /* TBC - ECMA-48 8.3.154 */ + val = CSI_ARG_OR(args[0], 0); + + switch(val) { + case 0: + clear_col_tabstop(state, state->pos.col); + break; + case 3: + case 5: + for(col = 0; col < state->cols; col++) + clear_col_tabstop(state, col); + break; + case 1: + case 2: + case 4: + break; + /* TODO: 1, 2 and 4 aren't meaningful yet without line tab stops */ + default: + return 0; + } + break; + + case 0x68: /* SM - ECMA-48 8.3.125 */ + if(!CSI_ARG_IS_MISSING(args[0])) + set_mode(state, CSI_ARG(args[0]), 1); + break; + + case LEADER('?', 0x68): /* DEC private mode set */ + if(!CSI_ARG_IS_MISSING(args[0])) + set_dec_mode(state, CSI_ARG(args[0]), 1); + break; + + case 0x6a: /* HPB - ECMA-48 8.3.58 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.col -= count; + state->at_phantom = 0; + break; + + case 0x6b: /* VPB - ECMA-48 8.3.159 */ + count = CSI_ARG_COUNT(args[0]); + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x6c: /* RM - ECMA-48 8.3.106 */ + if(!CSI_ARG_IS_MISSING(args[0])) + set_mode(state, CSI_ARG(args[0]), 0); + break; + + case LEADER('?', 0x6c): /* DEC private mode reset */ + if(!CSI_ARG_IS_MISSING(args[0])) + set_dec_mode(state, CSI_ARG(args[0]), 0); + break; + + case 0x6d: /* SGR - ECMA-48 8.3.117 */ + vterm_state_setpen(state, args, argcount); + break; + + case 0x6e: /* DSR - ECMA-48 8.3.35 */ + case LEADER('?', 0x6e): /* DECDSR */ + val = CSI_ARG_OR(args[0], 0); + + { + char *qmark = (leader_byte == '?') ? "?" : ""; + + switch(val) { + case 0: case 1: case 2: case 3: case 4: + /* ignore - these are replies */ + break; + case 5: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%s0n", qmark); + break; + case 6: /* CPR - cursor position report */ + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%s%d;%dR", qmark, state->pos.row + 1, state->pos.col + 1); + break; + } + } + break; + + + case LEADER('!', 0x70): /* DECSTR - DEC soft terminal reset */ + vterm_state_reset(state, 0); + break; + + case LEADER('?', INTERMED('$', 0x70)): + request_dec_mode(state, CSI_ARG(args[0])); + break; + + case INTERMED(' ', 0x71): /* DECSCUSR - DEC set cursor shape */ + val = CSI_ARG_OR(args[0], 1); + + switch(val) { + case 0: case 1: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + break; + case 2: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + break; + case 3: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE); + break; + case 4: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE); + break; + case 5: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT); + break; + case 6: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT); + break; + } + + break; + + case INTERMED('"', 0x71): /* DECSCA - DEC select character protection attribute */ + val = CSI_ARG_OR(args[0], 0); + + switch(val) { + case 0: case 2: + state->protected_cell = 0; + break; + case 1: + state->protected_cell = 1; + break; + } + + break; + + case 0x72: /* DECSTBM - DEC custom */ + state->scrollregion_top = CSI_ARG_OR(args[0], 1) - 1; + state->scrollregion_bottom = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]); + LBOUND(state->scrollregion_top, 0); + UBOUND(state->scrollregion_top, state->rows); + LBOUND(state->scrollregion_bottom, -1); + if(state->scrollregion_top == 0 && state->scrollregion_bottom == state->rows) + state->scrollregion_bottom = -1; + else + UBOUND(state->scrollregion_bottom, state->rows); + + if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) { + /* Invalid */ + state->scrollregion_top = 0; + state->scrollregion_bottom = -1; + } + + break; + + case 0x73: /* DECSLRM - DEC custom */ + /* Always allow setting these margins, just they won't take effect without DECVSSM */ + state->scrollregion_left = CSI_ARG_OR(args[0], 1) - 1; + state->scrollregion_right = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]); + LBOUND(state->scrollregion_left, 0); + UBOUND(state->scrollregion_left, state->cols); + LBOUND(state->scrollregion_right, -1); + if(state->scrollregion_left == 0 && state->scrollregion_right == state->cols) + state->scrollregion_right = -1; + else + UBOUND(state->scrollregion_right, state->cols); + + if(state->scrollregion_right > -1 && + state->scrollregion_right <= state->scrollregion_left) { + /* Invalid */ + state->scrollregion_left = 0; + state->scrollregion_right = -1; + } + + break; + + case INTERMED('\'', 0x7D): /* DECIC */ + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = state->pos.col; + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, 0, -count); + + break; + + case INTERMED('\'', 0x7E): /* DECDC */ + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = state->pos.col; + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, 0, count); + + break; + + default: + if(state->fallbacks && state->fallbacks->csi) + if((*state->fallbacks->csi)(leader, args, argcount, intermed, command, state->fbdata)) + return 1; + + return 0; + } + + if(state->mode.origin) { + LBOUND(state->pos.row, state->scrollregion_top); + UBOUND(state->pos.row, SCROLLREGION_BOTTOM(state)-1); + LBOUND(state->pos.col, SCROLLREGION_LEFT(state)); + UBOUND(state->pos.col, SCROLLREGION_RIGHT(state)-1); + } + else { + LBOUND(state->pos.row, 0); + UBOUND(state->pos.row, state->rows-1); + LBOUND(state->pos.col, 0); + UBOUND(state->pos.col, THISROWWIDTH(state)-1); + } + + updatecursor(state, &oldpos, 1); + + #ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after CSI %c: (%d,%d)\n", + command, state->pos.row, state->pos.col); + abort(); + } + + if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) { + fprintf(stderr, "Scroll region height out of bounds after CSI %c: %d <= %d\n", + command, SCROLLREGION_BOTTOM(state), state->scrollregion_top); + abort(); + } + + if(SCROLLREGION_RIGHT(state) <= SCROLLREGION_LEFT(state)) { + fprintf(stderr, "Scroll region width out of bounds after CSI %c: %d <= %d\n", + command, SCROLLREGION_RIGHT(state), SCROLLREGION_LEFT(state)); + abort(); + } + #endif + + return 1; + } + + static int on_osc(const char *command, size_t cmdlen, void *user) + { + VTermState *state = user; + + if(cmdlen < 2) + return 0; + + if(strneq(command, "0;", 2)) { + settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2); + settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2); + return 1; + } + else if(strneq(command, "1;", 2)) { + settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2); + return 1; + } + else if(strneq(command, "2;", 2)) { + settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2); + return 1; + } + else if(state->fallbacks && state->fallbacks->osc) + if((*state->fallbacks->osc)(command, cmdlen, state->fbdata)) + return 1; + + return 0; + } + + static void request_status_string(VTermState *state, const char *command, size_t cmdlen) + { + if(cmdlen == 1) + switch(command[0]) { + case 'm': /* Query SGR */ + { + long args[20]; + int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); + int argi; + vterm_push_output_sprintf_ctrl(state->vt, C1_DCS, "1$r"); + for(argi = 0; argi < argc; argi++) + vterm_push_output_sprintf(state->vt, + argi == argc - 1 ? "%d" : + CSI_ARG_HAS_MORE(args[argi]) ? "%d:" : + "%d;", + CSI_ARG(args[argi])); + vterm_push_output_sprintf(state->vt, "m"); + vterm_push_output_sprintf_ctrl(state->vt, C1_ST, ""); + } + return; + case 'r': /* Query DECSTBM */ + vterm_push_output_sprintf_dcs(state->vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); + return; + case 's': /* Query DECSLRM */ + vterm_push_output_sprintf_dcs(state->vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); + return; + } + + if(cmdlen == 2) { + if(strneq(command, " q", 2)) { + int reply; + switch(state->mode.cursor_shape) { + case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break; + case VTERM_PROP_CURSORSHAPE_UNDERLINE: reply = 4; break; + case VTERM_PROP_CURSORSHAPE_BAR_LEFT: reply = 6; break; + } + if(state->mode.cursor_blink) + reply--; + vterm_push_output_sprintf_dcs(state->vt, "1$r%d q", reply); + return; + } + else if(strneq(command, "\"q", 2)) { + vterm_push_output_sprintf_dcs(state->vt, "1$r%d\"q", state->protected_cell ? 1 : 2); + return; + } + } + + vterm_push_output_sprintf_dcs(state->vt, "0$r%.s", (int)cmdlen, command); + } + + static int on_dcs(const char *command, size_t cmdlen, void *user) + { + VTermState *state = user; + + if(cmdlen >= 2 && strneq(command, "$q", 2)) { + request_status_string(state, command+2, cmdlen-2); + return 1; + } + else if(state->fallbacks && state->fallbacks->dcs) + if((*state->fallbacks->dcs)(command, cmdlen, state->fbdata)) + return 1; + + return 0; + } + + static int on_resize(int rows, int cols, void *user) + { + VTermState *state = user; + VTermPos oldpos = state->pos; + VTermPos delta = { 0, 0 }; + + if(cols != state->cols) { + unsigned char *newtabstops = vterm_allocator_malloc(state->vt, (cols + 7) / 8); + + /* TODO: This can all be done much more efficiently bytewise */ + int col; + for(col = 0; col < state->cols && col < cols; col++) { + unsigned char mask = 1 << (col & 7); + if(state->tabstops[col >> 3] & mask) + newtabstops[col >> 3] |= mask; + else + newtabstops[col >> 3] &= ~mask; + } + + for( ; col < cols; col++) { + unsigned char mask = 1 << (col & 7); + if(col % 8 == 0) + newtabstops[col >> 3] |= mask; + else + newtabstops[col >> 3] &= ~mask; + } + + vterm_allocator_free(state->vt, state->tabstops); + state->tabstops = newtabstops; + } + + if(rows != state->rows) { + VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); + + int row; + for(row = 0; row < state->rows && row < rows; row++) { + newlineinfo[row] = state->lineinfo[row]; + } + + for( ; row < rows; row++) { + newlineinfo[row].doublewidth = 0; + newlineinfo[row].doubleheight = 0; + } + + vterm_allocator_free(state->vt, state->lineinfo); + state->lineinfo = newlineinfo; + } + + state->rows = rows; + state->cols = cols; + + if(state->scrollregion_bottom > -1) + UBOUND(state->scrollregion_bottom, state->rows); + if(state->scrollregion_right > -1) + UBOUND(state->scrollregion_right, state->cols); + + if(state->callbacks && state->callbacks->resize) + (*state->callbacks->resize)(rows, cols, &delta, state->cbdata); + + if(state->at_phantom && state->pos.col < cols-1) { + state->at_phantom = 0; + state->pos.col++; + } + + state->pos.row += delta.row; + state->pos.col += delta.col; + + if(state->pos.row >= rows) + state->pos.row = rows - 1; + if(state->pos.col >= cols) + state->pos.col = cols - 1; + + updatecursor(state, &oldpos, 1); + + return 1; + } + + static const VTermParserCallbacks parser_callbacks = { + on_text, /* text */ + on_control, /* control */ + on_escape, /* escape */ + on_csi, /* csi */ + on_osc, /* osc */ + on_dcs, /* dcs */ + on_resize /* resize */ + }; + + VTermState *vterm_obtain_state(VTerm *vt) + { + VTermState *state; + if(vt->state) + return vt->state; + + state = vterm_state_new(vt); + vt->state = state; + + state->combine_chars_size = 16; + state->combine_chars = vterm_allocator_malloc(state->vt, state->combine_chars_size * sizeof(state->combine_chars[0])); + + state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); + + state->lineinfo = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + + state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); + if(*state->encoding_utf8.enc->init) + (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data); + + vterm_parser_set_callbacks(vt, &parser_callbacks, state); + + return state; + } + + void vterm_state_reset(VTermState *state, int hard) + { + VTermEncoding *default_enc; + + state->scrollregion_top = 0; + state->scrollregion_bottom = -1; + state->scrollregion_left = 0; + state->scrollregion_right = -1; + + state->mode.keypad = 0; + state->mode.cursor = 0; + state->mode.autowrap = 1; + state->mode.insert = 0; + state->mode.newline = 0; + state->mode.alt_screen = 0; + state->mode.origin = 0; + state->mode.leftrightmargin = 0; + state->mode.bracketpaste = 0; + + state->vt->mode.ctrl8bit = 0; + + { + int col; + for(col = 0; col < state->cols; col++) + if(col % 8 == 0) + set_col_tabstop(state, col); + else + clear_col_tabstop(state, col); + } + + { + int row; + for(row = 0; row < state->rows; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + } + + if(state->callbacks && state->callbacks->initpen) + (*state->callbacks->initpen)(state->cbdata); + + vterm_state_resetpen(state); + + default_enc = state->vt->mode.utf8 ? + vterm_lookup_encoding(ENC_UTF8, 'u') : + vterm_lookup_encoding(ENC_SINGLE_94, 'B'); + + { + int i; + for(i = 0; i < 4; i++) { + state->encoding[i].enc = default_enc; + if(default_enc->init) + (*default_enc->init)(default_enc, state->encoding[i].data); + } + } + + state->gl_set = 0; + state->gr_set = 1; + state->gsingle_set = 0; + + state->protected_cell = 0; + + /* Initialise the props */ + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, 1); + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + + if(hard) { + VTermRect rect = { 0, 0, 0, 0 }; + + state->pos.row = 0; + state->pos.col = 0; + state->at_phantom = 0; + + rect.end_row = state->rows; + rect.end_col = state->cols; + erase(state, rect, 0); + } + } + + void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos) + { + *cursorpos = state->pos; + } + + void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user) + { + if(callbacks) { + state->callbacks = callbacks; + state->cbdata = user; + + if(state->callbacks && state->callbacks->initpen) + (*state->callbacks->initpen)(state->cbdata); + } + else { + state->callbacks = NULL; + state->cbdata = NULL; + } + } + + void *vterm_state_get_cbdata(VTermState *state) + { + return state->cbdata; + } + + void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user) + { + if(fallbacks) { + state->fallbacks = fallbacks; + state->fbdata = user; + } + else { + state->fallbacks = NULL; + state->fbdata = NULL; + } + } + + void *vterm_state_get_unrecognised_fbdata(VTermState *state) + { + return state->fbdata; + } + + int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val) + { + /* Only store the new value of the property if usercode said it was happy. + * This is especially important for altscreen switching */ + if(state->callbacks && state->callbacks->settermprop) + if(!(*state->callbacks->settermprop)(prop, val, state->cbdata)) + return 0; + + switch(prop) { + case VTERM_PROP_TITLE: + case VTERM_PROP_ICONNAME: + /* we don't store these, just transparently pass through */ + return 1; + case VTERM_PROP_CURSORVISIBLE: + state->mode.cursor_visible = val->boolean; + return 1; + case VTERM_PROP_CURSORBLINK: + state->mode.cursor_blink = val->boolean; + return 1; + case VTERM_PROP_CURSORSHAPE: + state->mode.cursor_shape = val->number; + return 1; + case VTERM_PROP_REVERSE: + state->mode.screen = val->boolean; + return 1; + case VTERM_PROP_ALTSCREEN: + state->mode.alt_screen = val->boolean; + if(state->mode.alt_screen) { + VTermRect rect = {0, 0, 0, 0}; + rect.end_row = state->rows; + rect.end_col = state->cols; + erase(state, rect, 0); + } + return 1; + case VTERM_PROP_MOUSE: + state->mouse_flags = 0; + if(val->number) + state->mouse_flags |= MOUSE_WANT_CLICK; + if(val->number == VTERM_PROP_MOUSE_DRAG) + state->mouse_flags |= MOUSE_WANT_DRAG; + if(val->number == VTERM_PROP_MOUSE_MOVE) + state->mouse_flags |= MOUSE_WANT_MOVE; + return 1; + } + + return 0; + } + + const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row) + { + return state->lineinfo + row; + } *** ../vim-8.0.0692/src/libvterm/src/unicode.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/unicode.c 2017-07-02 18:12:57.642730449 +0200 *************** *** 0 **** --- 1,331 ---- + #include "vterm_internal.h" + + /* ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + * With modifications: + * made functions static + * moved 'combining' table to file scope, so other functions can see it + * ################################################################### + */ + + /* + * This is an implementation of wcwidth() and wcswidth() (defined in + * IEEE Std 1002.1-2001) for Unicode. + * + * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html + * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html + * + * In fixed-width output devices, Latin characters all occupy a single + * "cell" position of equal width, whereas ideographic CJK characters + * occupy two such cells. Interoperability between terminal-line + * applications and (teletype-style) character terminals using the + * UTF-8 encoding requires agreement on which character should advance + * the cursor by how many cell positions. No established formal + * standards exist at present on which Unicode character shall occupy + * how many cell positions on character terminals. These routines are + * a first attempt of defining such behavior based on simple rules + * applied to data provided by the Unicode Consortium. + * + * For some graphical characters, the Unicode standard explicitly + * defines a character-cell width via the definition of the East Asian + * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. + * In all these cases, there is no ambiguity about which width a + * terminal shall use. For characters in the East Asian Ambiguous (A) + * class, the width choice depends purely on a preference of backward + * compatibility with either historic CJK or Western practice. + * Choosing single-width for these characters is easy to justify as + * the appropriate long-term solution, as the CJK practice of + * displaying these characters as double-width comes from historic + * implementation simplicity (8-bit encoded characters were displayed + * single-width and 16-bit ones double-width, even for Greek, + * Cyrillic, etc.) and not any typographic considerations. + * + * Much less clear is the choice of width for the Not East Asian + * (Neutral) class. Existing practice does not dictate a width for any + * of these characters. It would nevertheless make sense + * typographically to allocate two character cells to characters such + * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be + * represented adequately with a single-width glyph. The following + * routines at present merely assign a single-cell width to all + * neutral characters, in the interest of simplicity. This is not + * entirely satisfactory and should be reconsidered before + * establishing a formal standard in this area. At the moment, the + * decision which Not East Asian (Neutral) characters should be + * represented by double-width glyphs cannot yet be answered by + * applying a simple rule from the Unicode database content. Setting + * up a proper standard for the behavior of UTF-8 character terminals + * will require a careful analysis not only of each Unicode character, + * but also of each presentation form, something the author of these + * routines has avoided to do so far. + * + * http://www.unicode.org/unicode/reports/tr11/ + * + * Markus Kuhn -- 2007-05-26 (Unicode 5.0) + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted. The author + * disclaims all warranties with regard to this software. + * + * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + */ + + struct interval { + int first; + int last; + }; + + /* sorted list of non-overlapping intervals of non-spacing characters */ + /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ + static const struct interval combining[] = { + { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, + { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, + { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, + { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, + { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, + { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, + { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, + { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, + { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, + { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, + { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, + { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, + { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, + { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, + { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, + { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, + { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, + { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, + { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, + { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, + { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, + { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, + { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, + { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, + { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, + { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, + { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, + { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, + { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, + { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, + { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, + { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, + { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, + { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, + { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, + { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, + { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, + { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, + { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, + { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, + { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, + { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, + { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, + { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, + { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, + { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, + { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, + { 0xE0100, 0xE01EF } + }; + + + /* auxiliary function for binary search in interval table */ + static int bisearch(uint32_t ucs, const struct interval *table, int max) { + int min = 0; + int mid; + + if ((int)ucs < table[0].first || (int)ucs > table[max].last) + return 0; + while (max >= min) { + mid = (min + max) / 2; + if ((int)ucs > table[mid].last) + min = mid + 1; + else if ((int)ucs < table[mid].first) + max = mid - 1; + else + return 1; + } + + return 0; + } + + + /* The following two functions define the column width of an ISO 10646 + * character as follows: + * + * - The null character (U+0000) has a column width of 0. + * + * - Other C0/C1 control characters and DEL will lead to a return + * value of -1. + * + * - Non-spacing and enclosing combining characters (general + * category code Mn or Me in the Unicode database) have a + * column width of 0. + * + * - SOFT HYPHEN (U+00AD) has a column width of 1. + * + * - Other format characters (general category code Cf in the Unicode + * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. + * + * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) + * have a column width of 0. + * + * - Spacing characters in the East Asian Wide (W) or East Asian + * Full-width (F) category as defined in Unicode Technical + * Report #11 have a column width of 2. + * + * - All remaining characters (including all printable + * ISO 8859-1 and WGL4 characters, Unicode control characters, + * etc.) have a column width of 1. + * + * This implementation assumes that uint32_t characters are encoded + * in ISO 10646. + */ + + + static int mk_wcwidth(uint32_t ucs) + { + /* test for 8-bit control characters */ + if (ucs == 0) + return 0; + if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) + return -1; + + /* binary search in table of non-spacing characters */ + if (bisearch(ucs, combining, + sizeof(combining) / sizeof(struct interval) - 1)) + return 0; + + /* if we arrive here, ucs is not a combining or C0/C1 control character */ + + return 1 + + (ucs >= 0x1100 && + (ucs <= 0x115f || /* Hangul Jamo init. consonants */ + ucs == 0x2329 || ucs == 0x232a || + (ucs >= 0x2e80 && ucs <= 0xa4cf && + ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ + (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ + (ucs >= 0xffe0 && ucs <= 0xffe6) || + (ucs >= 0x20000 && ucs <= 0x2fffd) || + (ucs >= 0x30000 && ucs <= 0x3fffd))); + } + + #if 0 /* unused */ + static int mk_wcswidth(const uint32_t *pwcs, size_t n) + { + int w, width = 0; + + for (;*pwcs && n-- > 0; pwcs++) + if ((w = mk_wcwidth(*pwcs)) < 0) + return -1; + else + width += w; + + return width; + } + + + /* + * The following functions are the same as mk_wcwidth() and + * mk_wcswidth(), except that spacing characters in the East Asian + * Ambiguous (A) category as defined in Unicode Technical Report #11 + * have a column width of 2. This variant might be useful for users of + * CJK legacy encodings who want to migrate to UCS without changing + * the traditional terminal character-width behaviour. It is not + * otherwise recommended for general use. + */ + static int mk_wcwidth_cjk(uint32_t ucs) + { + /* sorted list of non-overlapping intervals of East Asian Ambiguous + * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ + static const struct interval ambiguous[] = { + { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, + { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, + { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, + { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, + { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, + { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, + { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, + { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, + { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, + { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, + { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, + { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, + { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, + { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, + { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, + { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, + { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, + { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, + { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, + { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, + { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, + { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, + { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, + { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, + { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, + { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, + { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, + { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, + { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, + { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, + { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, + { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, + { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, + { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, + { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, + { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, + { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, + { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, + { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, + { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, + { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, + { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, + { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, + { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, + { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, + { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, + { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, + { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, + { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, + { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, + { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, + { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } + }; + + /* binary search in table of non-spacing characters */ + if (bisearch(ucs, ambiguous, + sizeof(ambiguous) / sizeof(struct interval) - 1)) + return 2; + + return mk_wcwidth(ucs); + } + + static int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n) + { + int w, width = 0; + + for (;*pwcs && n-- > 0; pwcs++) + if ((w = mk_wcwidth_cjk(*pwcs)) < 0) + return -1; + else + width += w; + + return width; + } + #endif + + /* ################################ + * ### The rest added by Paul Evans */ + + INTERNAL int vterm_unicode_width(uint32_t codepoint) + { + return mk_wcwidth(codepoint); + } + + INTERNAL int vterm_unicode_is_combining(uint32_t codepoint) + { + return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1); + } *** ../vim-8.0.0692/src/libvterm/src/utf8.h 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/utf8.h 2017-07-02 18:18:18.320396918 +0200 *************** *** 0 **** --- 1,47 ---- + /* The following functions copied and adapted from libtermkey + * + * http://www.leonerd.org.uk/code/libtermkey/ + */ + unsigned int utf8_seqlen(long codepoint); + + #if defined(DEFINE_INLINES) || USE_INLINE + INLINE unsigned int utf8_seqlen(long codepoint) + { + if(codepoint < 0x0000080) return 1; + if(codepoint < 0x0000800) return 2; + if(codepoint < 0x0010000) return 3; + if(codepoint < 0x0200000) return 4; + if(codepoint < 0x4000000) return 5; + return 6; + } + #endif + + /* Does NOT NUL-terminate the buffer */ + int fill_utf8(long codepoint, char *str); + + #if defined(DEFINE_INLINES) || USE_INLINE + INLINE int fill_utf8(long codepoint, char *str) + { + int nbytes = utf8_seqlen(codepoint); + + /* This is easier done backwards */ + int b = nbytes; + while(b > 1) { + b--; + str[b] = 0x80 | (codepoint & 0x3f); + codepoint >>= 6; + } + + switch(nbytes) { + case 1: str[0] = (codepoint & 0x7f); break; + case 2: str[0] = 0xc0 | (codepoint & 0x1f); break; + case 3: str[0] = 0xe0 | (codepoint & 0x0f); break; + case 4: str[0] = 0xf0 | (codepoint & 0x07); break; + case 5: str[0] = 0xf8 | (codepoint & 0x03); break; + case 6: str[0] = 0xfc | (codepoint & 0x01); break; + } + + return nbytes; + } + #endif + /* end copy */ *** ../vim-8.0.0692/src/libvterm/src/vterm.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/vterm.c 2017-07-02 18:15:18.481705519 +0200 *************** *** 0 **** --- 1,385 ---- + #define DEFINE_INLINES + + #include "vterm_internal.h" + + #include + #include + #include + #include + + #include "utf8.h" + + /***************** + * API functions * + *****************/ + + static void *default_malloc(size_t size, void *allocdata UNUSED) + { + void *ptr = malloc(size); + if(ptr) + memset(ptr, 0, size); + return ptr; + } + + static void default_free(void *ptr, void *allocdata UNUSED) + { + free(ptr); + } + + static VTermAllocatorFunctions default_allocator = { + &default_malloc, /* malloc */ + &default_free /* free */ + }; + + VTerm *vterm_new(int rows, int cols) + { + return vterm_new_with_allocator(rows, cols, &default_allocator, NULL); + } + + VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata) + { + /* Need to bootstrap using the allocator function directly */ + VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata); + + vt->allocator = funcs; + vt->allocdata = allocdata; + + vt->rows = rows; + vt->cols = cols; + + vt->parser_state = NORMAL; + + vt->parser_callbacks = NULL; + vt->cbdata = NULL; + + vt->strbuffer_len = 64; + vt->strbuffer_cur = 0; + vt->strbuffer = vterm_allocator_malloc(vt, vt->strbuffer_len); + + vt->outbuffer_len = 64; + vt->outbuffer_cur = 0; + vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len); + + return vt; + } + + void vterm_free(VTerm *vt) + { + if(vt->screen) + vterm_screen_free(vt->screen); + + if(vt->state) + vterm_state_free(vt->state); + + vterm_allocator_free(vt, vt->strbuffer); + vterm_allocator_free(vt, vt->outbuffer); + + vterm_allocator_free(vt, vt); + } + + INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size) + { + return (*vt->allocator->malloc)(size, vt->allocdata); + } + + INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr) + { + (*vt->allocator->free)(ptr, vt->allocdata); + } + + void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp) + { + if(rowsp) + *rowsp = vt->rows; + if(colsp) + *colsp = vt->cols; + } + + void vterm_set_size(VTerm *vt, int rows, int cols) + { + vt->rows = rows; + vt->cols = cols; + + if(vt->parser_callbacks && vt->parser_callbacks->resize) + (*vt->parser_callbacks->resize)(rows, cols, vt->cbdata); + } + + int vterm_get_utf8(const VTerm *vt) + { + return vt->mode.utf8; + } + + void vterm_set_utf8(VTerm *vt, int is_utf8) + { + vt->mode.utf8 = is_utf8; + } + + INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) + { + if(len > vt->outbuffer_len - vt->outbuffer_cur) { + DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n"); + len = vt->outbuffer_len - vt->outbuffer_cur; + } + + memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len); + vt->outbuffer_cur += len; + } + + static int outbuffer_is_full(VTerm *vt) + { + return vt->outbuffer_cur >= vt->outbuffer_len - 1; + } + + INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) + { + int written; + char buffer[1024]; /* 1Kbyte is enough for everybody, right? */ + + if(outbuffer_is_full(vt)) { + DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n"); + return; + } + + written = vsprintf(buffer, format, args); + + if(written >= (int)(vt->outbuffer_len - vt->outbuffer_cur)) { + /* output was truncated */ + written = vt->outbuffer_len - vt->outbuffer_cur; + } + if (written > 0) + { + strncpy(vt->outbuffer + vt->outbuffer_cur, buffer, written + 1); + vt->outbuffer_cur += written; + } + } + + INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) + { + va_list args; + va_start(args, format); + vterm_push_output_vsprintf(vt, format, args); + va_end(args); + } + + INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) + { + size_t orig_cur = vt->outbuffer_cur; + va_list args; + + if(ctrl >= 0x80 && !vt->mode.ctrl8bit) + vterm_push_output_sprintf(vt, ESC_S "%c", ctrl - 0x40); + else + vterm_push_output_sprintf(vt, "%c", ctrl); + + va_start(args, fmt); + vterm_push_output_vsprintf(vt, fmt, args); + va_end(args); + + if(outbuffer_is_full(vt)) + vt->outbuffer_cur = orig_cur; + } + + INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) + { + size_t orig_cur = vt->outbuffer_cur; + va_list args; + + if(!vt->mode.ctrl8bit) + vterm_push_output_sprintf(vt, ESC_S "%c", C1_DCS - 0x40); + else + vterm_push_output_sprintf(vt, "%c", C1_DCS); + + va_start(args, fmt); + vterm_push_output_vsprintf(vt, fmt, args); + va_end(args); + + vterm_push_output_sprintf_ctrl(vt, C1_ST, ""); + + if(outbuffer_is_full(vt)) + vt->outbuffer_cur = orig_cur; + } + + size_t vterm_output_get_buffer_size(const VTerm *vt) + { + return vt->outbuffer_len; + } + + size_t vterm_output_get_buffer_current(const VTerm *vt) + { + return vt->outbuffer_cur; + } + + size_t vterm_output_get_buffer_remaining(const VTerm *vt) + { + return vt->outbuffer_len - vt->outbuffer_cur; + } + + size_t vterm_output_read(VTerm *vt, char *buffer, size_t len) + { + if(len > vt->outbuffer_cur) + len = vt->outbuffer_cur; + + memcpy(buffer, vt->outbuffer, len); + + if(len < vt->outbuffer_cur) + memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len); + + vt->outbuffer_cur -= len; + + return len; + } + + void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user) + { + vt->parser_callbacks = callbacks; + vt->cbdata = user; + } + + void *vterm_parser_get_cbdata(VTerm *vt) + { + return vt->cbdata; + } + + VTermValueType vterm_get_attr_type(VTermAttr attr) + { + switch(attr) { + case VTERM_ATTR_BOLD: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_UNDERLINE: return VTERM_VALUETYPE_INT; + case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT; + case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR; + case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR; + } + return 0; /* UNREACHABLE */ + } + + VTermValueType vterm_get_prop_type(VTermProp prop) + { + switch(prop) { + case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_CURSORBLINK: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_ALTSCREEN: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_TITLE: return VTERM_VALUETYPE_STRING; + case VTERM_PROP_ICONNAME: return VTERM_VALUETYPE_STRING; + case VTERM_PROP_REVERSE: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT; + case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT; + } + return 0; /* UNREACHABLE */ + } + + void vterm_scroll_rect(VTermRect rect, + int downward, + int rightward, + int (*moverect)(VTermRect src, VTermRect dest, void *user), + int (*eraserect)(VTermRect rect, int selective, void *user), + void *user) + { + VTermRect src; + VTermRect dest; + + if(abs(downward) >= rect.end_row - rect.start_row || + abs(rightward) >= rect.end_col - rect.start_col) { + /* Scroll more than area; just erase the lot */ + (*eraserect)(rect, 0, user); + return; + } + + if(rightward >= 0) { + /* rect: [XXX................] + * src: [----------------] + * dest: [----------------] + */ + dest.start_col = rect.start_col; + dest.end_col = rect.end_col - rightward; + src.start_col = rect.start_col + rightward; + src.end_col = rect.end_col; + } + else { + /* rect: [................XXX] + * src: [----------------] + * dest: [----------------] + */ + int leftward = -rightward; + dest.start_col = rect.start_col + leftward; + dest.end_col = rect.end_col; + src.start_col = rect.start_col; + src.end_col = rect.end_col - leftward; + } + + if(downward >= 0) { + dest.start_row = rect.start_row; + dest.end_row = rect.end_row - downward; + src.start_row = rect.start_row + downward; + src.end_row = rect.end_row; + } + else { + int upward = -downward; + dest.start_row = rect.start_row + upward; + dest.end_row = rect.end_row; + src.start_row = rect.start_row; + src.end_row = rect.end_row - upward; + } + + if(moverect) + (*moverect)(dest, src, user); + + if(downward > 0) + rect.start_row = rect.end_row - downward; + else if(downward < 0) + rect.end_row = rect.start_row - downward; + + if(rightward > 0) + rect.start_col = rect.end_col - rightward; + else if(rightward < 0) + rect.end_col = rect.start_col - rightward; + + (*eraserect)(rect, 0, user); + } + + void vterm_copy_cells(VTermRect dest, + VTermRect src, + void (*copycell)(VTermPos dest, VTermPos src, void *user), + void *user) + { + int downward = src.start_row - dest.start_row; + int rightward = src.start_col - dest.start_col; + + int init_row, test_row, init_col, test_col; + int inc_row, inc_col; + + VTermPos pos; + + if(downward < 0) { + init_row = dest.end_row - 1; + test_row = dest.start_row - 1; + inc_row = -1; + } + else /* downward >= 0 */ { + init_row = dest.start_row; + test_row = dest.end_row; + inc_row = +1; + } + + if(rightward < 0) { + init_col = dest.end_col - 1; + test_col = dest.start_col - 1; + inc_col = -1; + } + else /* rightward >= 0 */ { + init_col = dest.start_col; + test_col = dest.end_col; + inc_col = +1; + } + + for(pos.row = init_row; pos.row != test_row; pos.row += inc_row) + for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) { + VTermPos srcpos; + srcpos.row = pos.row + downward; + srcpos.col = pos.col + rightward; + (*copycell)(pos, srcpos, user); + } + } *** ../vim-8.0.0692/src/libvterm/src/vterm_internal.h 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/src/vterm_internal.h 2017-07-02 18:17:53.800575330 +0200 *************** *** 0 **** --- 1,237 ---- + #ifndef __VTERM_INTERNAL_H__ + #define __VTERM_INTERNAL_H__ + + #include "vterm.h" + + #include + + #if defined(__GNUC__) + # define INTERNAL __attribute__((visibility("internal"))) + # define UNUSED __attribute__((unused)) + #else + # define INTERNAL + # define UNUSED + #endif + + #ifdef DEBUG + # define DEBUG_LOG(s) fprintf(stderr, s) + # define DEBUG_LOG1(s, a) fprintf(stderr, s, a) + # define DEBUG_LOG2(s, a, b) fprintf(stderr, s, a, b) + # define DEBUG_LOG3(s, a, b, c) fprintf(stderr, s, a, b, c) + #else + # define DEBUG_LOG(s) + # define DEBUG_LOG1(s, a) + # define DEBUG_LOG2(s, a, b) + # define DEBUG_LOG3(s, a, b, c) + #endif + + #define ESC_S "\x1b" + + typedef struct VTermEncoding VTermEncoding; + + typedef struct { + VTermEncoding *enc; + + /* This size should be increased if required by other stateful encodings */ + char data[4*sizeof(uint32_t)]; + } VTermEncodingInstance; + + struct VTermPen + { + VTermColor fg; + VTermColor bg; + unsigned int bold:1; + unsigned int underline:2; + unsigned int italic:1; + unsigned int blink:1; + unsigned int reverse:1; + unsigned int strike:1; + unsigned int font:4; /* To store 0-9 */ + }; + + int vterm_color_equal(VTermColor a, VTermColor b); + + #if defined(DEFINE_INLINES) || USE_INLINE + INLINE int vterm_color_equal(VTermColor a, VTermColor b) + { + return a.red == b.red && a.green == b.green && a.blue == b.blue; + } + #endif + + struct VTermState + { + VTerm *vt; + + const VTermStateCallbacks *callbacks; + void *cbdata; + + const VTermParserCallbacks *fallbacks; + void *fbdata; + + int rows; + int cols; + + /* Current cursor position */ + VTermPos pos; + + int at_phantom; /* True if we're on the "81st" phantom column to defer a wraparound */ + + int scrollregion_top; + int scrollregion_bottom; /* -1 means unbounded */ + #define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows) + int scrollregion_left; + #define SCROLLREGION_LEFT(state) ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0) + int scrollregion_right; /* -1 means unbounded */ + #define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols) + + /* Bitvector of tab stops */ + unsigned char *tabstops; + + VTermLineInfo *lineinfo; + #define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols) + #define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row) + + /* Mouse state */ + int mouse_col, mouse_row; + int mouse_buttons; + int mouse_flags; + #define MOUSE_WANT_CLICK 0x01 + #define MOUSE_WANT_DRAG 0x02 + #define MOUSE_WANT_MOVE 0x04 + + enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol; + + /* Last glyph output, for Unicode recombining purposes */ + uint32_t *combine_chars; + size_t combine_chars_size; /* Number of ELEMENTS in the above */ + int combine_width; /* The width of the glyph above */ + VTermPos combine_pos; /* Position before movement */ + + struct { + unsigned int keypad:1; + unsigned int cursor:1; + unsigned int autowrap:1; + unsigned int insert:1; + unsigned int newline:1; + unsigned int cursor_visible:1; + unsigned int cursor_blink:1; + unsigned int cursor_shape:2; + unsigned int alt_screen:1; + unsigned int origin:1; + unsigned int screen:1; + unsigned int leftrightmargin:1; + unsigned int bracketpaste:1; + } mode; + + VTermEncodingInstance encoding[4], encoding_utf8; + int gl_set, gr_set, gsingle_set; + + struct VTermPen pen; + + VTermColor default_fg; + VTermColor default_bg; + VTermColor colors[16]; /* Store the 8 ANSI and the 8 ANSI high-brights only */ + + int fg_index; + int bg_index; + int bold_is_highbright; + + unsigned int protected_cell : 1; + + /* Saved state under DEC mode 1048/1049 */ + struct { + VTermPos pos; + struct VTermPen pen; + + struct { + int cursor_visible:1; + int cursor_blink:1; + unsigned int cursor_shape:2; + } mode; + } saved; + }; + + struct VTerm + { + VTermAllocatorFunctions *allocator; + void *allocdata; + + int rows; + int cols; + + struct { + unsigned int utf8:1; + unsigned int ctrl8bit:1; + } mode; + + enum VTermParserState { + NORMAL, + CSI, + OSC, + DCS, + ESC, + ESC_IN_OSC, + ESC_IN_DCS + } parser_state; + const VTermParserCallbacks *parser_callbacks; + void *cbdata; + + /* len == malloc()ed size; cur == number of valid bytes */ + char *strbuffer; + size_t strbuffer_len; + size_t strbuffer_cur; + + char *outbuffer; + size_t outbuffer_len; + size_t outbuffer_cur; + + VTermState *state; + VTermScreen *screen; + }; + + struct VTermEncoding { + void (*init) (VTermEncoding *enc, void *data); + void (*decode)(VTermEncoding *enc, void *data, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t len); + }; + + typedef enum { + ENC_UTF8, + ENC_SINGLE_94 + } VTermEncodingType; + + void *vterm_allocator_malloc(VTerm *vt, size_t size); + void vterm_allocator_free(VTerm *vt, void *ptr); + + void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len); + void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args); + void vterm_push_output_sprintf(VTerm *vt, const char *format, ...); + void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...); + void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...); + + void vterm_state_free(VTermState *state); + + void vterm_state_newpen(VTermState *state); + void vterm_state_resetpen(VTermState *state); + void vterm_state_setpen(VTermState *state, const long args[], int argcount); + int vterm_state_getpen(VTermState *state, long args[], int argcount); + void vterm_state_savepen(VTermState *state, int save); + + enum { + C1_SS3 = 0x8f, + C1_DCS = 0x90, + C1_CSI = 0x9b, + C1_ST = 0x9c + }; + + void vterm_state_push_output_sprintf_CSI(VTermState *vts, const char *format, ...); + + void vterm_screen_free(VTermScreen *screen); + + VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation); + + int vterm_unicode_width(uint32_t codepoint); + int vterm_unicode_is_combining(uint32_t codepoint); + + #endif *** ../vim-8.0.0692/src/libvterm/t/02parser.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/02parser.test 2017-06-24 16:44:02.176324952 +0200 *************** *** 0 **** --- 1,200 ---- + INIT + UTF8 0 + WANTPARSER + + !Basic text + PUSH "hello" + text 0x68, 0x65, 0x6c, 0x6c, 0x6f + + !C0 + PUSH "\x03" + control 3 + + PUSH "\x1f" + control 0x1f + + !C1 8bit + PUSH "\x83" + control 0x83 + + PUSH "\x9f" + control 0x9f + + !C1 7bit + PUSH "\e\x43" + control 0x83 + + PUSH "\e\x5f" + control 0x9f + + !High bytes + PUSH "\xa0\xcc\xfe" + text 0xa0, 0xcc, 0xfe + + !Mixed + PUSH "1\n2" + text 0x31 + control 10 + text 0x32 + + !Escape + PUSH "\e=" + escape "=" + + !Escape 2-byte + PUSH "\e(X" + escape "(X" + + !Split write Escape + PUSH "\e(" + PUSH "Y" + escape "(Y" + + !Escape cancels Escape, starts another + PUSH "\e(\e)Z" + escape ")Z" + + !CAN cancels Escape, returns to normal mode + PUSH "\e(\x{18}AB" + text 0x41, 0x42 + + !C0 in Escape interrupts and continues + PUSH "\e(\nX" + control 10 + escape "(X" + + !CSI 0 args + PUSH "\e[a" + csi 0x61 * + + !CSI 1 arg + PUSH "\e[9b" + csi 0x62 9 + + !CSI 2 args + PUSH "\e[3;4c" + csi 0x63 3,4 + + !CSI 1 arg 1 sub + PUSH "\e[1:2c" + csi 0x63 1+,2 + + !CSI many digits + PUSH "\e[678d" + csi 0x64 678 + + !CSI leading zero + PUSH "\e[007e" + csi 0x65 7 + + !CSI qmark + PUSH "\e[?2;7f" + csi 0x66 L=3f 2,7 + + !CSI greater + PUSH "\e[>c" + csi 0x63 L=3e * + + !CSI SP + PUSH "\e[12 q" + csi 0x71 12 I=20 + + !Mixed CSI + PUSH "A\e[8mB" + text 0x41 + csi 0x6d 8 + text 0x42 + + !Split write + PUSH "\e" + PUSH "[a" + csi 0x61 * + PUSH "foo\e[" + text 0x66, 0x6f, 0x6f + PUSH "4b" + csi 0x62 4 + PUSH "\e[12;" + PUSH "3c" + csi 0x63 12,3 + + !Escape cancels CSI, starts Escape + PUSH "\e[123\e9" + escape "9" + + !CAN cancels CSI, returns to normal mode + PUSH "\e[12\x{18}AB" + text 0x41, 0x42 + + !C0 in Escape interrupts and continues + PUSH "\e[12\n;3X" + control 10 + csi 0x58 12,3 + + !OSC BEL + PUSH "\e]1;Hello\x07" + osc "1;Hello" + + !OSC ST (7bit) + PUSH "\e]1;Hello\e\\" + osc "1;Hello" + + !OSC ST (8bit) + PUSH "\x{9d}1;Hello\x9c" + osc "1;Hello" + + !Escape cancels OSC, starts Escape + PUSH "\e]Something\e9" + escape "9" + + !CAN cancels OSC, returns to normal mode + PUSH "\e]12\x{18}AB" + text 0x41, 0x42 + + !C0 in OSC interrupts and continues + PUSH "\e]2;\nBye\x07" + control 10 + osc "2;Bye" + + !DCS BEL + PUSH "\ePHello\x07" + dcs "Hello" + + !DCS ST (7bit) + PUSH "\ePHello\e\\" + dcs "Hello" + + !DCS ST (8bit) + PUSH "\x{90}Hello\x9c" + dcs "Hello" + + !Escape cancels DCS, starts Escape + PUSH "\ePSomething\e9" + escape "9" + + !CAN cancels DCS, returns to normal mode + PUSH "\eP12\x{18}AB" + text 0x41, 0x42 + + !C0 in OSC interrupts and continues + PUSH "\ePBy\ne\x07" + control 10 + dcs "Bye" + + !NUL ignored + PUSH "\x{00}" + + !NUL ignored within CSI + PUSH "\e[12\x{00}3m" + csi 0x6d 123 + + !DEL ignored + PUSH "\x{7f}" + + !DEL ignored within CSI + PUSH "\e[12\x{7f}3m" + csi 0x6d 123 + + !DEL inside text" + PUSH "AB\x{7f}C" + text 0x41,0x42 + text 0x43 *** ../vim-8.0.0692/src/libvterm/t/03encoding_utf8.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/03encoding_utf8.test 2017-06-24 16:44:02.176324952 +0200 *************** *** 0 **** --- 1,122 ---- + INIT + WANTENCODING + + !Low + ENCIN "123" + encout 0x31,0x32,0x33 + + # We want to prove the UTF-8 parser correctly handles all the sequences. + # Easy way to do this is to check it does low/high boundary cases, as that + # leaves only two for each sequence length + # + # These ranges are therefore: + # + # Two bytes: + # U+0080 = 000 10000000 => 00010 000000 + # => 11000010 10000000 = C2 80 + # U+07FF = 111 11111111 => 11111 111111 + # => 11011111 10111111 = DF BF + # + # Three bytes: + # U+0800 = 00001000 00000000 => 0000 100000 000000 + # => 11100000 10100000 10000000 = E0 A0 80 + # U+FFFD = 11111111 11111101 => 1111 111111 111101 + # => 11101111 10111111 10111101 = EF BF BD + # (We avoid U+FFFE and U+FFFF as they're invalid codepoints) + # + # Four bytes: + # U+10000 = 00001 00000000 00000000 => 000 010000 000000 000000 + # => 11110000 10010000 10000000 10000000 = F0 90 80 80 + # U+1FFFFF = 11111 11111111 11111111 => 111 111111 111111 111111 + # => 11110111 10111111 10111111 10111111 = F7 BF BF BF + + !2 byte + ENCIN "\xC2\x80\xDF\xBF" + encout 0x0080, 0x07FF + + !3 byte + ENCIN "\xE0\xA0\x80\xEF\xBF\xBD" + encout 0x0800,0xFFFD + + !4 byte + ENCIN "\xF0\x90\x80\x80\xF7\xBF\xBF\xBF" + encout 0x10000,0x1fffff + + # Next up, we check some invalid sequences + # + Early termination (back to low bytes too soon) + # + Early restart (another sequence introduction before the previous one was finished) + + !Early termination + ENCIN "\xC2!" + encout 0xfffd,0x21 + + ENCIN "\xE0!\xE0\xA0!" + encout 0xfffd,0x21,0xfffd,0x21 + + ENCIN "\xF0!\xF0\x90!\xF0\x90\x80!" + encout 0xfffd,0x21,0xfffd,0x21,0xfffd,0x21 + + !Early restart + ENCIN "\xC2\xC2\x90" + encout 0xfffd,0x0090 + + ENCIN "\xE0\xC2\x90\xE0\xA0\xC2\x90" + encout 0xfffd,0x0090,0xfffd,0x0090 + + ENCIN "\xF0\xC2\x90\xF0\x90\xC2\x90\xF0\x90\x80\xC2\x90" + encout 0xfffd,0x0090,0xfffd,0x0090,0xfffd,0x0090 + + # Test the overlong sequences by giving an overlong encoding of U+0000 and + # an encoding of the highest codepoint still too short + # + # Two bytes: + # U+0000 = C0 80 + # U+007F = 000 01111111 => 00001 111111 => + # => 11000001 10111111 => C1 BF + # + # Three bytes: + # U+0000 = E0 80 80 + # U+07FF = 00000111 11111111 => 0000 011111 111111 + # => 11100000 10011111 10111111 = E0 9F BF + # + # Four bytes: + # U+0000 = F0 80 80 80 + # U+FFFF = 11111111 11111111 => 000 001111 111111 111111 + # => 11110000 10001111 10111111 10111111 = F0 8F BF BF + + !Overlong + ENCIN "\xC0\x80\xC1\xBF" + encout 0xfffd,0xfffd + + ENCIN "\xE0\x80\x80\xE0\x9F\xBF" + encout 0xfffd,0xfffd + + ENCIN "\xF0\x80\x80\x80\xF0\x8F\xBF\xBF" + encout 0xfffd,0xfffd + + # UTF-16 surrogates U+D800 and U+DFFF + !UTF-16 Surrogates + ENCIN "\xED\xA0\x80\xED\xBF\xBF" + encout 0xfffd,0xfffd + + !Split write + ENCIN "\xC2" + ENCIN "\xA0" + encout 0x000A0 + + ENCIN "\xE0" + ENCIN "\xA0\x80" + encout 0x00800 + ENCIN "\xE0\xA0" + ENCIN "\x80" + encout 0x00800 + + ENCIN "\xF0" + ENCIN "\x90\x80\x80" + encout 0x10000 + ENCIN "\xF0\x90" + ENCIN "\x80\x80" + encout 0x10000 + ENCIN "\xF0\x90\x80" + ENCIN "\x80" + encout 0x10000 *** ../vim-8.0.0692/src/libvterm/t/10state_putglyph.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/10state_putglyph.test 2017-06-24 16:44:02.176324952 +0200 *************** *** 0 **** --- 1,55 ---- + INIT + UTF8 1 + WANTSTATE g + + !Low + RESET + PUSH "ABC" + putglyph 0x41 1 0,0 + putglyph 0x42 1 0,1 + putglyph 0x43 1 0,2 + + !UTF-8 1 char + # U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE + # U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE + RESET + PUSH "\xC3\x81\xC3\xA9" + putglyph 0xc1 1 0,0 + putglyph 0xe9 1 0,1 + + !UTF-8 wide char + # U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO + RESET + PUSH "\xEF\xBC\x90 " + putglyph 0xff10 2 0,0 + putglyph 0x20 1 0,2 + + !UTF-8 combining chars + # U+0301 = 0xCC 0x81 name: COMBINING ACUTE + RESET + PUSH "e\xCC\x81Z" + putglyph 0x65,0x301 1 0,0 + putglyph 0x5a 1 0,1 + + !Combining across buffers + RESET + PUSH "e" + putglyph 0x65 1 0,0 + PUSH "\xCC\x81Z" + putglyph 0x65,0x301 1 0,0 + putglyph 0x5a 1 0,1 + + RESET + PUSH "e" + putglyph 0x65 1 0,0 + PUSH "\xCC\x81" + putglyph 0x65,0x301 1 0,0 + PUSH "\xCC\x82" + putglyph 0x65,0x301,0x302 1 0,0 + + !DECSCA protected + RESET + PUSH "A\e[1\"qB\e[2\"qC" + putglyph 0x41 1 0,0 + putglyph 0x42 1 0,1 prot + putglyph 0x43 1 0,2 *** ../vim-8.0.0692/src/libvterm/t/11state_movecursor.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/11state_movecursor.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,224 ---- + INIT + UTF8 1 + WANTSTATE + + !Implicit + PUSH "ABC" + ?cursor = 0,3 + !Backspace + PUSH "\b" + ?cursor = 0,2 + !Horizontal Tab + PUSH "\t" + ?cursor = 0,8 + !Carriage Return + PUSH "\r" + ?cursor = 0,0 + !Linefeed + PUSH "\n" + ?cursor = 1,0 + + !Backspace bounded by lefthand edge + PUSH "\e[4;2H" + ?cursor = 3,1 + PUSH "\b" + ?cursor = 3,0 + PUSH "\b" + ?cursor = 3,0 + + !Backspace cancels phantom + PUSH "\e[4;80H" + ?cursor = 3,79 + PUSH "X" + ?cursor = 3,79 + PUSH "\b" + ?cursor = 3,78 + + !HT bounded by righthand edge + PUSH "\e[1;78H" + ?cursor = 0,77 + PUSH "\t" + ?cursor = 0,79 + PUSH "\t" + ?cursor = 0,79 + + RESET + + !Index + PUSH "ABC\eD" + ?cursor = 1,3 + !Reverse Index + PUSH "\eM" + ?cursor = 0,3 + !Newline + PUSH "\eE" + ?cursor = 1,0 + + RESET + + !Cursor Forward + PUSH "\e[B" + ?cursor = 1,0 + PUSH "\e[3B" + ?cursor = 4,0 + PUSH "\e[0B" + ?cursor = 5,0 + + !Cursor Down + PUSH "\e[C" + ?cursor = 5,1 + PUSH "\e[3C" + ?cursor = 5,4 + PUSH "\e[0C" + ?cursor = 5,5 + + !Cursor Up + PUSH "\e[A" + ?cursor = 4,5 + PUSH "\e[3A" + ?cursor = 1,5 + PUSH "\e[0A" + ?cursor = 0,5 + + !Cursor Backward + PUSH "\e[D" + ?cursor = 0,4 + PUSH "\e[3D" + ?cursor = 0,1 + PUSH "\e[0D" + ?cursor = 0,0 + + !Cursor Next Line + PUSH " " + ?cursor = 0,3 + PUSH "\e[E" + ?cursor = 1,0 + PUSH " " + ?cursor = 1,3 + PUSH "\e[2E" + ?cursor = 3,0 + PUSH "\e[0E" + ?cursor = 4,0 + + !Cursor Previous Line + PUSH " " + ?cursor = 4,3 + PUSH "\e[F" + ?cursor = 3,0 + PUSH " " + ?cursor = 3,3 + PUSH "\e[2F" + ?cursor = 1,0 + PUSH "\e[0F" + ?cursor = 0,0 + + !Cursor Horizonal Absolute + PUSH "\n" + ?cursor = 1,0 + PUSH "\e[20G" + ?cursor = 1,19 + PUSH "\e[G" + ?cursor = 1,0 + + !Cursor Position + PUSH "\e[10;5H" + ?cursor = 9,4 + PUSH "\e[8H" + ?cursor = 7,0 + PUSH "\e[H" + ?cursor = 0,0 + + !Cursor Position cancels phantom + PUSH "\e[10;78H" + ?cursor = 9,77 + PUSH "ABC" + ?cursor = 9,79 + PUSH "\e[10;80H" + PUSH "C" + ?cursor = 9,79 + PUSH "X" + ?cursor = 10,1 + + RESET + + !Bounds Checking + PUSH "\e[A" + ?cursor = 0,0 + PUSH "\e[D" + ?cursor = 0,0 + PUSH "\e[25;80H" + ?cursor = 24,79 + PUSH "\e[B" + ?cursor = 24,79 + PUSH "\e[C" + ?cursor = 24,79 + PUSH "\e[E" + ?cursor = 24,0 + PUSH "\e[H" + ?cursor = 0,0 + PUSH "\e[F" + ?cursor = 0,0 + PUSH "\e[999G" + ?cursor = 0,79 + PUSH "\e[99;99H" + ?cursor = 24,79 + + RESET + + !Horizontal Position Absolute + PUSH "\e[5`" + ?cursor = 0,4 + + !Horizontal Position Relative + PUSH "\e[3a" + ?cursor = 0,7 + + !Horizontal Position Backward + PUSH "\e[3j" + ?cursor = 0,4 + + !Horizontal and Vertical Position + PUSH "\e[3;3f" + ?cursor = 2,2 + + !Vertical Position Absolute + PUSH "\e[5d" + ?cursor = 4,2 + + !Vertical Position Relative + PUSH "\e[2e" + ?cursor = 6,2 + + !Vertical Position Backward + PUSH "\e[2k" + ?cursor = 4,2 + + RESET + + !Horizontal Tab + PUSH "\t" + ?cursor = 0,8 + PUSH " " + ?cursor = 0,11 + PUSH "\t" + ?cursor = 0,16 + PUSH " " + ?cursor = 0,23 + PUSH "\t" + ?cursor = 0,24 + PUSH " " + ?cursor = 0,32 + PUSH "\t" + ?cursor = 0,40 + + !Cursor Horizontal Tab + PUSH "\e[I" + ?cursor = 0,48 + PUSH "\e[2I" + ?cursor = 0,64 + + !Cursor Backward Tab + PUSH "\e[Z" + ?cursor = 0,56 + PUSH "\e[2Z" + ?cursor = 0,40 *** ../vim-8.0.0692/src/libvterm/t/12state_scroll.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/12state_scroll.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,150 ---- + INIT + UTF8 1 + WANTSTATE s + + !Linefeed + PUSH "\n"x24 + ?cursor = 24,0 + PUSH "\n" + scrollrect 0..25,0..80 => +1,+0 + ?cursor = 24,0 + + RESET + + !Index + PUSH "\e[25H" + PUSH "\eD" + scrollrect 0..25,0..80 => +1,+0 + + RESET + + !Reverse Index + PUSH "\eM" + scrollrect 0..25,0..80 => -1,+0 + + RESET + + !Linefeed in DECSTBM + PUSH "\e[1;10r" + ?cursor = 0,0 + PUSH "\n"x9 + ?cursor = 9,0 + PUSH "\n" + scrollrect 0..10,0..80 => +1,+0 + ?cursor = 9,0 + + !Linefeed outside DECSTBM + PUSH "\e[20H" + ?cursor = 19,0 + PUSH "\n" + ?cursor = 20,0 + + !Index in DECSTBM + PUSH "\e[10H" + PUSH "\e[9;10r" + PUSH "\eM" + ?cursor = 8,0 + PUSH "\eM" + scrollrect 8..10,0..80 => -1,+0 + + !Reverse Index in DECSTBM + PUSH "\e[25H" + ?cursor = 24,0 + PUSH "\n" + # no scrollrect + ?cursor = 24,0 + + !Linefeed in DECSTBM+DECSLRM + PUSH "\e[?69h" + PUSH "\e[3;10r\e[10;40s" + PUSH "\e[10;10H\n" + scrollrect 2..10,9..40 => +1,+0 + + !IND/RI in DECSTBM+DECSLRM + PUSH "\eD" + scrollrect 2..10,9..40 => +1,+0 + PUSH "\e[3;10H\eM" + scrollrect 2..10,9..40 => -1,+0 + + !DECRQSS on DECSTBM + PUSH "\eP\$qr\e\\" + output "\eP1\$r3;10r\e\\" + + !DECRQSS on DECSLRM + PUSH "\eP\$qs\e\\" + output "\eP1\$r10;40s\e\\" + + !Setting invalid DECSLRM with !DECVSSM is still rejected + PUSH "\e[?69l\e[;0s\e[?69h" + + RESET + + !Scroll Down + PUSH "\e[S" + scrollrect 0..25,0..80 => +1,+0 + ?cursor = 0,0 + PUSH "\e[2S" + scrollrect 0..25,0..80 => +2,+0 + ?cursor = 0,0 + PUSH "\e[100S" + scrollrect 0..25,0..80 => +25,+0 + + !Scroll Up + PUSH "\e[T" + scrollrect 0..25,0..80 => -1,+0 + ?cursor = 0,0 + PUSH "\e[2T" + scrollrect 0..25,0..80 => -2,+0 + ?cursor = 0,0 + PUSH "\e[100T" + scrollrect 0..25,0..80 => -25,+0 + + !SD/SU in DECSTBM + PUSH "\e[5;20r" + PUSH "\e[S" + scrollrect 4..20,0..80 => +1,+0 + PUSH "\e[T" + scrollrect 4..20,0..80 => -1,+0 + + RESET + + !SD/SU in DECSTBM+DECSLRM + PUSH "\e[?69h" + PUSH "\e[3;10r\e[10;40s" + ?cursor = 0,0 + PUSH "\e[3;10H" + ?cursor = 2,9 + PUSH "\e[S" + scrollrect 2..10,9..40 => +1,+0 + PUSH "\e[?69l" + PUSH "\e[S" + scrollrect 2..10,0..80 => +1,+0 + + !Invalid boundaries + RESET + + PUSH "\e[100;105r\eD" + PUSH "\e[5;2r\eD" + + RESET + WANTSTATE -s+me + + !Scroll Down move+erase emulation + PUSH "\e[S" + moverect 1..25,0..80 -> 0..24,0..80 + erase 24..25,0..80 + ?cursor = 0,0 + PUSH "\e[2S" + moverect 2..25,0..80 -> 0..23,0..80 + erase 23..25,0..80 + ?cursor = 0,0 + + !Scroll Up move+erase emulation + PUSH "\e[T" + moverect 0..24,0..80 -> 1..25,0..80 + erase 0..1,0..80 + ?cursor = 0,0 + PUSH "\e[2T" + moverect 0..23,0..80 -> 2..25,0..80 + erase 0..2,0..80 + ?cursor = 0,0 *** ../vim-8.0.0692/src/libvterm/t/13state_edit.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/13state_edit.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,300 ---- + INIT + UTF8 1 + WANTSTATE se + + !ICH + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "ACD" + PUSH "\e[2D" + ?cursor = 0,1 + PUSH "\e[@" + scrollrect 0..1,1..80 => +0,-1 + ?cursor = 0,1 + PUSH "B" + ?cursor = 0,2 + PUSH "\e[3@" + scrollrect 0..1,2..80 => +0,-3 + + !ICH with DECSLRM + PUSH "\e[?69h" + PUSH "\e[;50s" + PUSH "\e[20G\e[@" + scrollrect 0..1,19..50 => +0,-1 + + !ICH outside DECSLRM + PUSH "\e[70G\e[@" + # nothing happens + + !DCH + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "ABBC" + PUSH "\e[3D" + ?cursor = 0,1 + PUSH "\e[P" + scrollrect 0..1,1..80 => +0,+1 + ?cursor = 0,1 + PUSH "\e[3P" + scrollrect 0..1,1..80 => +0,+3 + ?cursor = 0,1 + + !DCH with DECSLRM + PUSH "\e[?69h" + PUSH "\e[;50s" + PUSH "\e[20G\e[P" + scrollrect 0..1,19..50 => +0,+1 + + !DCH outside DECSLRM + PUSH "\e[70G\e[P" + # nothing happens + + !ECH + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "ABC" + PUSH "\e[2D" + ?cursor = 0,1 + PUSH "\e[X" + erase 0..1,1..2 + ?cursor = 0,1 + PUSH "\e[3X" + erase 0..1,1..4 + ?cursor = 0,1 + # ECH more columns than there are should be bounded + PUSH "\e[100X" + erase 0..1,1..80 + + !IL + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "A\r\nC" + ?cursor = 1,1 + PUSH "\e[L" + scrollrect 1..25,0..80 => -1,+0 + # TODO: ECMA-48 says we should move to line home, but neither xterm nor + # xfce4-terminal do this + ?cursor = 1,1 + PUSH "\rB" + ?cursor = 1,1 + PUSH "\e[3L" + scrollrect 1..25,0..80 => -3,+0 + + !IL with DECSTBM + PUSH "\e[5;15r" + PUSH "\e[5H\e[L" + scrollrect 4..15,0..80 => -1,+0 + + !IL outside DECSTBM + PUSH "\e[20H\e[L" + # nothing happens + + !IL with DECSTBM+DECSLRM + PUSH "\e[?69h" + PUSH "\e[10;50s" + PUSH "\e[5;10H\e[L" + scrollrect 4..15,9..50 => -1,+0 + + !DL + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "A\r\nB\r\nB\r\nC" + ?cursor = 3,1 + PUSH "\e[2H" + ?cursor = 1,0 + PUSH "\e[M" + scrollrect 1..25,0..80 => +1,+0 + ?cursor = 1,0 + PUSH "\e[3M" + scrollrect 1..25,0..80 => +3,+0 + ?cursor = 1,0 + + !DL with DECSTBM + PUSH "\e[5;15r" + PUSH "\e[5H\e[M" + scrollrect 4..15,0..80 => +1,+0 + + !DL outside DECSTBM + PUSH "\e[20H\e[M" + # nothing happens + + !DL with DECSTBM+DECSLRM + PUSH "\e[?69h" + PUSH "\e[10;50s" + PUSH "\e[5;10H\e[M" + scrollrect 4..15,9..50 => +1,+0 + + !DECIC + RESET + erase 0..25,0..80 + PUSH "\e[20G\e[5'}" + scrollrect 0..25,19..80 => +0,-5 + + !DECIC with DECSTBM+DECSLRM + PUSH "\e[?69h" + PUSH "\e[4;20r\e[20;60s" + PUSH "\e[4;20H\e[3'}" + scrollrect 3..20,19..60 => +0,-3 + + !DECIC outside DECSLRM + PUSH "\e[70G\e['}" + # nothing happens + + !DECDC + RESET + erase 0..25,0..80 + PUSH "\e[20G\e[5'~" + scrollrect 0..25,19..80 => +0,+5 + + !DECDC with DECSTBM+DECSLRM + PUSH "\e[?69h" + PUSH "\e[4;20r\e[20;60s" + PUSH "\e[4;20H\e[3'~" + scrollrect 3..20,19..60 => +0,+3 + + !DECDC outside DECSLRM + PUSH "\e[70G\e['~" + # nothing happens + + !EL 0 + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "ABCDE" + PUSH "\e[3D" + ?cursor = 0,2 + PUSH "\e[0K" + erase 0..1,2..80 + ?cursor = 0,2 + + !EL 1 + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "ABCDE" + PUSH "\e[3D" + ?cursor = 0,2 + PUSH "\e[1K" + erase 0..1,0..3 + ?cursor = 0,2 + + !EL 2 + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "ABCDE" + PUSH "\e[3D" + ?cursor = 0,2 + PUSH "\e[2K" + erase 0..1,0..80 + ?cursor = 0,2 + + !SEL + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "\e[11G" + ?cursor = 0,10 + PUSH "\e[?0K" + erase 0..1,10..80 selective + ?cursor = 0,10 + PUSH "\e[?1K" + erase 0..1,0..11 selective + ?cursor = 0,10 + PUSH "\e[?2K" + erase 0..1,0..80 selective + ?cursor = 0,10 + + !ED 0 + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "\e[2;2H" + ?cursor = 1,1 + PUSH "\e[0J" + erase 1..2,1..80 + erase 2..25,0..80 + ?cursor = 1,1 + + !ED 1 + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "\e[2;2H" + ?cursor = 1,1 + PUSH "\e[1J" + erase 0..1,0..80 + erase 1..2,0..2 + ?cursor = 1,1 + + !ED 2 + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "\e[2;2H" + ?cursor = 1,1 + PUSH "\e[2J" + erase 0..25,0..80 + ?cursor = 1,1 + + !SED + RESET + erase 0..25,0..80 + PUSH "\e[5;5H" + ?cursor = 4,4 + PUSH "\e[?0J" + erase 4..5,4..80 selective + erase 5..25,0..80 selective + ?cursor = 4,4 + PUSH "\e[?1J" + erase 0..4,0..80 selective + erase 4..5,0..5 selective + ?cursor = 4,4 + PUSH "\e[?2J" + erase 0..25,0..80 selective + ?cursor = 4,4 + + !DECRQSS on DECSCA + PUSH "\e[2\"q" + PUSH "\eP\$q\"q\e\\" + output "\eP1\$r2\"q\e\\" + + WANTSTATE -s+m + + !ICH move+erase emuation + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "ACD" + PUSH "\e[2D" + ?cursor = 0,1 + PUSH "\e[@" + moverect 0..1,1..79 -> 0..1,2..80 + erase 0..1,1..2 + ?cursor = 0,1 + PUSH "B" + ?cursor = 0,2 + PUSH "\e[3@" + moverect 0..1,2..77 -> 0..1,5..80 + erase 0..1,2..5 + + !DCH move+erase emulation + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "ABBC" + PUSH "\e[3D" + ?cursor = 0,1 + PUSH "\e[P" + moverect 0..1,2..80 -> 0..1,1..79 + erase 0..1,79..80 + ?cursor = 0,1 + PUSH "\e[3P" + moverect 0..1,4..80 -> 0..1,1..77 + erase 0..1,77..80 + ?cursor = 0,1 *** ../vim-8.0.0692/src/libvterm/t/14state_encoding.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/14state_encoding.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,105 ---- + INIT + WANTSTATE g + + !Default + RESET + PUSH "#" + putglyph 0x23 1 0,0 + + !Designate G0=UK + RESET + PUSH "\e(A" + PUSH "#" + putglyph 0x00a3 1 0,0 + + !Designate G0=DEC drawing + RESET + PUSH "\e(0" + PUSH "a" + putglyph 0x2592 1 0,0 + + !Designate G1 + LS1 + RESET + PUSH "\e)0" + PUSH "a" + putglyph 0x61 1 0,0 + PUSH "\x0e" + PUSH "a" + putglyph 0x2592 1 0,1 + !LS0 + PUSH "\x0f" + PUSH "a" + putglyph 0x61 1 0,2 + + !Designate G2 + LS2 + PUSH "\e*0" + PUSH "a" + putglyph 0x61 1 0,3 + PUSH "\en" + PUSH "a" + putglyph 0x2592 1 0,4 + PUSH "\x0f" + PUSH "a" + putglyph 0x61 1 0,5 + + !Designate G3 + LS3 + PUSH "\e+0" + PUSH "a" + putglyph 0x61 1 0,6 + PUSH "\eo" + PUSH "a" + putglyph 0x2592 1 0,7 + PUSH "\x0f" + PUSH "a" + putglyph 0x61 1 0,8 + + !SS2 + PUSH "a\x{8e}aa" + putglyph 0x61 1 0,9 + putglyph 0x2592 1 0,10 + putglyph 0x61 1 0,11 + + !SS3 + PUSH "a\x{8f}aa" + putglyph 0x61 1 0,12 + putglyph 0x2592 1 0,13 + putglyph 0x61 1 0,14 + + !LS1R + RESET + PUSH "\e~" + PUSH "\xe1" + putglyph 0x61 1 0,0 + PUSH "\e)0" + PUSH "\xe1" + putglyph 0x2592 1 0,1 + + !LS2R + RESET + PUSH "\e}" + PUSH "\xe1" + putglyph 0x61 1 0,0 + PUSH "\e*0" + PUSH "\xe1" + putglyph 0x2592 1 0,1 + + !LS3R + RESET + PUSH "\e|" + PUSH "\xe1" + putglyph 0x61 1 0,0 + PUSH "\e+0" + PUSH "\xe1" + putglyph 0x2592 1 0,1 + + UTF8 1 + + !Mixed US-ASCII and UTF-8 + # U+0108 == 0xc4 0x88 + RESET + PUSH "\e(B" + PUSH "AB\xc4\x88D" + putglyph 0x0041 1 0,0 + putglyph 0x0042 1 0,1 + putglyph 0x0108 1 0,2 + putglyph 0x0044 1 0,3 *** ../vim-8.0.0692/src/libvterm/t/15state_mode.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/15state_mode.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,86 ---- + INIT + UTF8 1 + WANTSTATE gme + + !Insert/Replace Mode + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "AC\e[DB" + putglyph 0x41 1 0,0 + putglyph 0x43 1 0,1 + putglyph 0x42 1 0,1 + PUSH "\e[4h" + PUSH "\e[G" + PUSH "AC\e[DB" + moverect 0..1,0..79 -> 0..1,1..80 + erase 0..1,0..1 + putglyph 0x41 1 0,0 + moverect 0..1,1..79 -> 0..1,2..80 + erase 0..1,1..2 + putglyph 0x43 1 0,1 + moverect 0..1,1..79 -> 0..1,2..80 + erase 0..1,1..2 + putglyph 0x42 1 0,1 + + !Insert mode only happens once for UTF-8 combining + PUSH "e" + moverect 0..1,2..79 -> 0..1,3..80 + erase 0..1,2..3 + putglyph 0x65 1 0,2 + PUSH "\xCC\x81" + putglyph 0x65,0x301 1 0,2 + + !Newline/Linefeed mode + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "\e[5G\n" + ?cursor = 1,4 + PUSH "\e[20h" + PUSH "\e[5G\n" + ?cursor = 2,0 + + !DEC origin mode + RESET + erase 0..25,0..80 + ?cursor = 0,0 + PUSH "\e[5;15r" + PUSH "\e[H" + ?cursor = 0,0 + PUSH "\e[3;3H" + ?cursor = 2,2 + PUSH "\e[?6h" + PUSH "\e[H" + ?cursor = 4,0 + PUSH "\e[3;3H" + ?cursor = 6,2 + + !DECRQM on DECOM + PUSH "\e[?6h" + PUSH "\e[?6\$p" + output "\e[?6;1\$y" + PUSH "\e[?6l" + PUSH "\e[?6\$p" + output "\e[?6;2\$y" + + !Origin mode with DECSLRM + PUSH "\e[?6h" + PUSH "\e[?69h" + PUSH "\e[20;60s" + PUSH "\e[H" + ?cursor = 4,19 + + PUSH "\e[?69l" + + !Origin mode bounds cursor to scrolling region + PUSH "\e[H" + PUSH "\e[10A" + ?cursor = 4,0 + PUSH "\e[20B" + ?cursor = 14,0 + + !Origin mode without scroll region + PUSH "\e[?6l" + PUSH "\e[r\e[?6h" + ?cursor = 0,0 *** ../vim-8.0.0692/src/libvterm/t/16state_resize.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/16state_resize.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,48 ---- + INIT + WANTSTATE g + + !Placement + RESET + PUSH "AB\e[79GCDE" + putglyph 0x41 1 0,0 + putglyph 0x42 1 0,1 + putglyph 0x43 1 0,78 + putglyph 0x44 1 0,79 + putglyph 0x45 1 1,0 + + !Resize + RESET + RESIZE 27,85 + PUSH "AB\e[79GCDE" + putglyph 0x41 1 0,0 + putglyph 0x42 1 0,1 + putglyph 0x43 1 0,78 + putglyph 0x44 1 0,79 + putglyph 0x45 1 0,80 + ?cursor = 0,81 + + !Resize without reset + RESIZE 28,90 + ?cursor = 0,81 + PUSH "FGHI" + putglyph 0x46 1 0,81 + putglyph 0x47 1 0,82 + putglyph 0x48 1 0,83 + putglyph 0x49 1 0,84 + ?cursor = 0,85 + + !Resize shrink moves cursor + RESIZE 25,80 + ?cursor = 0,79 + + !Resize grow doesn't cancel phantom + RESET + PUSH "\e[79GAB" + putglyph 0x41 1 0,78 + putglyph 0x42 1 0,79 + ?cursor = 0,79 + RESIZE 30,100 + ?cursor = 0,80 + PUSH "C" + putglyph 0x43 1 0,80 + ?cursor = 0,81 *** ../vim-8.0.0692/src/libvterm/t/17state_mouse.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/17state_mouse.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,172 ---- + INIT + WANTSTATE p + + !DECRQM on with mouse off + PUSH "\e[?1000\$p" + output "\e[?1000;2\$y" + PUSH "\e[?1002\$p" + output "\e[?1002;2\$y" + PUSH "\e[?1003\$p" + output "\e[?1003;2\$y" + + !Mouse in simple button report mode + RESET + settermprop 1 true + settermprop 2 true + settermprop 7 1 + PUSH "\e[?1000h" + settermprop 8 1 + + !Press 1 + MOUSEMOVE 0,0 0 + MOUSEBTN d 1 0 + output "\e[M\x20\x21\x21" + + !Release 1 + MOUSEBTN u 1 0 + output "\e[M\x23\x21\x21" + + !Ctrl-Press 1 + MOUSEBTN d 1 C + output "\e[M\x30\x21\x21" + MOUSEBTN u 1 C + output "\e[M\x33\x21\x21" + + !Button 2 + MOUSEBTN d 2 0 + output "\e[M\x21\x21\x21" + MOUSEBTN u 2 0 + output "\e[M\x23\x21\x21" + + !Position + MOUSEMOVE 10,20 0 + MOUSEBTN d 1 0 + output "\e[M\x20\x35\x2b" + + MOUSEBTN u 1 0 + output "\e[M\x23\x35\x2b" + MOUSEMOVE 10,21 0 + # no output + + !Wheel events + MOUSEBTN d 4 0 + output "\e[M\x60\x36\x2b" + MOUSEBTN d 4 0 + output "\e[M\x60\x36\x2b" + MOUSEBTN d 5 0 + output "\e[M\x61\x36\x2b" + + !DECRQM on mouse button mode + PUSH "\e[?1000\$p" + output "\e[?1000;1\$y" + PUSH "\e[?1002\$p" + output "\e[?1002;2\$y" + PUSH "\e[?1003\$p" + output "\e[?1003;2\$y" + + !Drag events + RESET + settermprop 1 true + settermprop 2 true + settermprop 7 1 + PUSH "\e[?1002h" + settermprop 8 2 + + MOUSEMOVE 5,5 0 + MOUSEBTN d 1 0 + output "\e[M\x20\x26\x26" + MOUSEMOVE 5,6 0 + output "\e[M\x40\x27\x26" + MOUSEMOVE 6,6 0 + output "\e[M\x40\x27\x27" + MOUSEMOVE 6,6 0 + # no output + MOUSEBTN u 1 0 + output "\e[M\x23\x27\x27" + MOUSEMOVE 6,7 + # no output + + !DECRQM on mouse drag mode + PUSH "\e[?1000\$p" + output "\e[?1000;2\$y" + PUSH "\e[?1002\$p" + output "\e[?1002;1\$y" + PUSH "\e[?1003\$p" + output "\e[?1003;2\$y" + + !Non-drag motion events + PUSH "\e[?1003h" + settermprop 8 3 + + MOUSEMOVE 6,8 0 + output "\e[M\x43\x29\x27" + + !DECRQM on mouse motion mode + PUSH "\e[?1000\$p" + output "\e[?1000;2\$y" + PUSH "\e[?1002\$p" + output "\e[?1002;2\$y" + PUSH "\e[?1003\$p" + output "\e[?1003;1\$y" + + !Bounds checking + MOUSEMOVE 300,300 0 + output "\e[M\x43\xff\xff" + MOUSEBTN d 1 0 + output "\e[M\x20\xff\xff" + MOUSEBTN u 1 0 + output "\e[M\x23\xff\xff" + + !DECRQM on standard encoding mode + PUSH "\e[?1005\$p" + output "\e[?1005;2\$y" + PUSH "\e[?1006\$p" + output "\e[?1006;2\$y" + PUSH "\e[?1015\$p" + output "\e[?1015;2\$y" + + !UTF-8 extended encoding mode + # 300 + 32 + 1 = 333 = U+014d = \xc5\x8d + PUSH "\e[?1005h" + MOUSEBTN d 1 0 + output "\e[M\x20\xc5\x8d\xc5\x8d" + MOUSEBTN u 1 0 + output "\e[M\x23\xc5\x8d\xc5\x8d" + + !DECRQM on UTF-8 extended encoding mode + PUSH "\e[?1005\$p" + output "\e[?1005;1\$y" + PUSH "\e[?1006\$p" + output "\e[?1006;2\$y" + PUSH "\e[?1015\$p" + output "\e[?1015;2\$y" + + !SGR extended encoding mode + PUSH "\e[?1006h" + MOUSEBTN d 1 0 + output "\e[<0;301;301M" + MOUSEBTN u 1 0 + output "\e[<0;301;301m" + + !DECRQM on SGR extended encoding mode + PUSH "\e[?1005\$p" + output "\e[?1005;2\$y" + PUSH "\e[?1006\$p" + output "\e[?1006;1\$y" + PUSH "\e[?1015\$p" + output "\e[?1015;2\$y" + + !rxvt extended encoding mode + PUSH "\e[?1015h" + MOUSEBTN d 1 0 + output "\e[0;301;301M" + MOUSEBTN u 1 0 + output "\e[3;301;301M" + + !DECRQM on rxvt extended encoding mode + PUSH "\e[?1005\$p" + output "\e[?1005;2\$y" + PUSH "\e[?1006\$p" + output "\e[?1006;2\$y" + PUSH "\e[?1015\$p" + output "\e[?1015;1\$y" *** ../vim-8.0.0692/src/libvterm/t/18state_termprops.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/18state_termprops.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,36 ---- + INIT + WANTSTATE p + + RESET + settermprop 1 true + settermprop 2 true + settermprop 7 1 + + !Cursor visibility + PUSH "\e[?25h" + settermprop 1 true + PUSH "\e[?25\$p" + output "\e[?25;1\$y" + PUSH "\e[?25l" + settermprop 1 false + PUSH "\e[?25\$p" + output "\e[?25;2\$y" + + !Cursor blink + PUSH "\e[?12h" + settermprop 2 true + PUSH "\e[?12\$p" + output "\e[?12;1\$y" + PUSH "\e[?12l" + settermprop 2 false + PUSH "\e[?12\$p" + output "\e[?12;2\$y" + + !Cursor shape + PUSH "\e[3 q" + settermprop 2 true + settermprop 7 2 + + !Title + PUSH "\e]2;Here is my title\a" + settermprop 4 "Here is my title" *** ../vim-8.0.0692/src/libvterm/t/20state_wrapping.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/20state_wrapping.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,69 ---- + INIT + UTF8 1 + WANTSTATE gm + + !79th Column + PUSH "\e[75G" + PUSH "A"x5 + putglyph 0x41 1 0,74 + putglyph 0x41 1 0,75 + putglyph 0x41 1 0,76 + putglyph 0x41 1 0,77 + putglyph 0x41 1 0,78 + ?cursor = 0,79 + + !80th Column Phantom + PUSH "A" + putglyph 0x41 1 0,79 + ?cursor = 0,79 + + !Line Wraparound + PUSH "B" + putglyph 0x42 1 1,0 + ?cursor = 1,1 + + !Line Wraparound during combined write + PUSH "\e[78G" + PUSH "BBBCC" + putglyph 0x42 1 1,77 + putglyph 0x42 1 1,78 + putglyph 0x42 1 1,79 + putglyph 0x43 1 2,0 + putglyph 0x43 1 2,1 + ?cursor = 2,2 + + !DEC Auto Wrap Mode + RESET + PUSH "\e[?7l" + PUSH "\e[75G" + PUSH "D"x6 + putglyph 0x44 1 0,74 + putglyph 0x44 1 0,75 + putglyph 0x44 1 0,76 + putglyph 0x44 1 0,77 + putglyph 0x44 1 0,78 + putglyph 0x44 1 0,79 + ?cursor = 0,79 + PUSH "D" + putglyph 0x44 1 0,79 + ?cursor = 0,79 + PUSH "\e[?7h" + + !80th column causes linefeed on wraparound + PUSH "\e[25;78HABC" + putglyph 0x41 1 24,77 + putglyph 0x42 1 24,78 + putglyph 0x43 1 24,79 + ?cursor = 24,79 + PUSH "D" + moverect 1..25,0..80 -> 0..24,0..80 + putglyph 0x44 1 24,0 + + !80th column phantom linefeed phantom cancelled by explicit cursor move + PUSH "\e[25;78HABC" + putglyph 0x41 1 24,77 + putglyph 0x42 1 24,78 + putglyph 0x43 1 24,79 + ?cursor = 24,79 + PUSH "\e[25;1HD" + putglyph 0x44 1 24,0 *** ../vim-8.0.0692/src/libvterm/t/21state_tabstops.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/21state_tabstops.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,60 ---- + INIT + WANTSTATE g + + !Initial + RESET + PUSH "\tX" + putglyph 0x58 1 0,8 + PUSH "\tX" + putglyph 0x58 1 0,16 + ?cursor = 0,17 + + !HTS + PUSH "\e[5G\eH" + PUSH "\e[G\tX" + putglyph 0x58 1 0,4 + ?cursor = 0,5 + + !TBC 0 + PUSH "\e[9G\e[g" + PUSH "\e[G\tX\tX" + putglyph 0x58 1 0,4 + putglyph 0x58 1 0,16 + ?cursor = 0,17 + + !TBC 3 + PUSH "\e[3g\e[50G\eH\e[G" + ?cursor = 0,0 + PUSH "\tX" + putglyph 0x58 1 0,49 + ?cursor = 0,50 + + !Tabstops after resize + RESET + RESIZE 30,100 + # Should be 100/8 = 12 tabstops + PUSH "\tX" + putglyph 0x58 1 0,8 + PUSH "\tX" + putglyph 0x58 1 0,16 + PUSH "\tX" + putglyph 0x58 1 0,24 + PUSH "\tX" + putglyph 0x58 1 0,32 + PUSH "\tX" + putglyph 0x58 1 0,40 + PUSH "\tX" + putglyph 0x58 1 0,48 + PUSH "\tX" + putglyph 0x58 1 0,56 + PUSH "\tX" + putglyph 0x58 1 0,64 + PUSH "\tX" + putglyph 0x58 1 0,72 + PUSH "\tX" + putglyph 0x58 1 0,80 + PUSH "\tX" + putglyph 0x58 1 0,88 + PUSH "\tX" + putglyph 0x58 1 0,96 + ?cursor = 0,97 *** ../vim-8.0.0692/src/libvterm/t/22state_save.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/22state_save.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,64 ---- + INIT + WANTSTATE p + + RESET + settermprop 1 true + settermprop 2 true + settermprop 7 1 + + !Set up state + PUSH "\e[2;2H" + ?cursor = 1,1 + PUSH "\e[1m" + ?pen bold = on + + !Save + PUSH "\e[?1048h" + + !Change state + PUSH "\e[5;5H" + ?cursor = 4,4 + PUSH "\e[4 q" + settermprop 2 false + settermprop 7 2 + PUSH "\e[22;4m" + ?pen bold = off + ?pen underline = 1 + + !Restore + PUSH "\e[?1048l" + settermprop 1 true + settermprop 2 true + settermprop 7 1 + ?cursor = 1,1 + ?pen bold = on + ?pen underline = 0 + + !Save/restore using DECSC/DECRC + PUSH "\e[2;2H\e7" + ?cursor = 1,1 + + PUSH "\e[5;5H" + ?cursor = 4,4 + PUSH "\e8" + settermprop 1 true + settermprop 2 true + settermprop 7 1 + ?cursor = 1,1 + + !Save twice, restore twice happens on both edge transitions + PUSH "\e[2;10H\e[?1048h\e[6;10H\e[?1048h" + PUSH "\e[H" + ?cursor = 0,0 + PUSH "\e[?1048l" + settermprop 1 true + settermprop 2 true + settermprop 7 1 + ?cursor = 5,9 + PUSH "\e[H" + ?cursor = 0,0 + PUSH "\e[?1048l" + settermprop 1 true + settermprop 2 true + settermprop 7 1 + ?cursor = 5,9 *** ../vim-8.0.0692/src/libvterm/t/25state_input.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/25state_input.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,132 ---- + INIT + WANTSTATE + + !Unmodified ASCII + INCHAR 0 41 + output "A" + INCHAR 0 61 + output "a" + + !Ctrl modifier on ASCII letters + INCHAR C 41 + output "\e[65;5u" + INCHAR C 61 + output "\x01" + + !Alt modifier on ASCII letters + INCHAR A 41 + output "\eA" + INCHAR A 61 + output "\ea" + + !Ctrl-Alt modifier on ASCII letters + INCHAR CA 41 + output "\e[65;7u" + INCHAR CA 61 + output "\e\x01" + + !Special handling of Ctrl-I + INCHAR 0 49 + output "I" + INCHAR 0 69 + output "i" + INCHAR C 49 + output "\e[73;5u" + INCHAR C 69 + output "\e[105;5u" + INCHAR A 49 + output "\eI" + INCHAR A 69 + output "\ei" + INCHAR CA 49 + output "\e[73;7u" + INCHAR CA 69 + output "\e[105;7u" + + !Special handling of Space + INCHAR 0 20 + output " " + INCHAR S 20 + output "\e[32;2u" + INCHAR C 20 + output "\0" + INCHAR SC 20 + output "\e[32;6u" + INCHAR A 20 + output "\e " + INCHAR SA 20 + output "\e[32;4u" + INCHAR CA 20 + output "\e\0" + INCHAR SCA 20 + output "\e[32;8u" + + !Cursor keys in reset (cursor) mode + INKEY 0 Up + output "\e[A" + INKEY S Up + output "\e[1;2A" + INKEY C Up + output "\e[1;5A" + INKEY SC Up + output "\e[1;6A" + INKEY A Up + output "\e[1;3A" + INKEY SA Up + output "\e[1;4A" + INKEY CA Up + output "\e[1;7A" + INKEY SCA Up + output "\e[1;8A" + + !Cursor keys in application mode + PUSH "\e[?1h" + # Plain "Up" should be SS3 A now + INKEY 0 Up + output "\eOA" + # Modified keys should still use CSI + INKEY S Up + output "\e[1;2A" + INKEY C Up + output "\e[1;5A" + + !Shift-Tab should be different + INKEY 0 Tab + output "\x09" + INKEY S Tab + output "\e[Z" + INKEY C Tab + output "\e[9;5u" + INKEY A Tab + output "\e\x09" + INKEY CA Tab + output "\e[9;7u" + + !Enter in linefeed mode + INKEY 0 Enter + output "\x0d" + + !Enter in newline mode + PUSH "\e[20h" + INKEY 0 Enter + output "\x0d\x0a" + + !Keypad in DECKPNM + INKEY 0 KP0 + output "0" + + !Keypad in DECKPAM + PUSH "\e=" + INKEY 0 KP0 + output "\eOp" + + !Bracketed paste mode off + PASTE START + PASTE END + + !Bracketed paste mode on + PUSH "\e[?2004h" + PASTE START + output "\e[200~" + PASTE END + output "\e[201~" *** ../vim-8.0.0692/src/libvterm/t/26state_query.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/26state_query.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,62 ---- + INIT + WANTSTATE + + !DA + RESET + PUSH "\e[c" + output "\e[?1;2c" + + !DSR + RESET + PUSH "\e[5n" + output "\e[0n" + + !CPR + PUSH "\e[6n" + output "\e[1;1R" + PUSH "\e[10;10H\e[6n" + output "\e[10;10R" + + !DECCPR + PUSH "\e[?6n" + output "\e[?10;10R" + + !DECRQSS on DECSCUSR + PUSH "\e[3 q" + PUSH "\eP\$q q\e\\" + output "\eP1\$r3 q\e\\" + + !DECRQSS on SGR + PUSH "\e[1;5;7m" + PUSH "\eP\$qm\e\\" + output "\eP1\$r1;5;7m\e\\" + + !DECRQSS on SGR ANSI colours + PUSH "\e[0;31;42m" + PUSH "\eP\$qm\e\\" + output "\eP1\$r31;42m\e\\" + + !DECRQSS on SGR ANSI hi-bright colours + PUSH "\e[0;93;104m" + PUSH "\eP\$qm\e\\" + output "\eP1\$r93;104m\e\\" + + !DECRQSS on SGR 256-palette colours + PUSH "\e[0;38:5:56;48:5:78m" + PUSH "\eP\$qm\e\\" + output "\eP1\$r38:5:56;48:5:78m\e\\" + + !DECRQSS on SGR RGB8 colours + PUSH "\e[0;38:2:24:68:112;48:2:13:57:101m" + PUSH "\eP\$qm\e\\" + output "\eP1\$r38:2:24:68:112;48:2:13:57:101m\e\\" + + !S8C1T on DSR + PUSH "\e G" + PUSH "\e[5n" + output "\x{9b}0n" + PUSH "\e F" + + !Truncation on attempted buffer overflow + PUSH "\e[6n" x 20 + output "\e[10;10R" x 7 *** ../vim-8.0.0692/src/libvterm/t/27state_reset.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/27state_reset.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,32 ---- + INIT + WANTSTATE + + RESET + + !RIS homes cursor + PUSH "\e[5;5H" + ?cursor = 4,4 + WANTSTATE +m + PUSH "\ec" + ?cursor = 0,0 + WANTSTATE -m + + !RIS cancels scrolling region + PUSH "\e[5;10r" + WANTSTATE +s + PUSH "\ec\e[25H\n" + scrollrect 0..25,0..80 => +1,+0 + WANTSTATE -s + + !RIS erases screen + PUSH "ABCDE" + WANTSTATE +e + PUSH "\ec" + erase 0..25,0..80 + WANTSTATE -e + + !RIS clears tabstops + PUSH "\e[5G\eH\e[G\t" + ?cursor = 0,4 + PUSH "\ec\t" + ?cursor = 0,8 *** ../vim-8.0.0692/src/libvterm/t/28state_dbl_wh.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/28state_dbl_wh.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,61 ---- + INIT + WANTSTATE g + + !Single Width, Single Height + RESET + PUSH "\e#5" + PUSH "Hello" + putglyph 0x48 1 0,0 + putglyph 0x65 1 0,1 + putglyph 0x6c 1 0,2 + putglyph 0x6c 1 0,3 + putglyph 0x6f 1 0,4 + + !Double Width, Single Height + RESET + PUSH "\e#6" + PUSH "Hello" + putglyph 0x48 1 0,0 dwl + putglyph 0x65 1 0,1 dwl + putglyph 0x6c 1 0,2 dwl + putglyph 0x6c 1 0,3 dwl + putglyph 0x6f 1 0,4 dwl + ?cursor = 0,5 + PUSH "\e[40GAB" + putglyph 0x41 1 0,39 dwl + putglyph 0x42 1 1,0 + ?cursor = 1,1 + + !Double Height + RESET + PUSH "\e#3" + PUSH "Hello" + putglyph 0x48 1 0,0 dwl dhl-top + putglyph 0x65 1 0,1 dwl dhl-top + putglyph 0x6c 1 0,2 dwl dhl-top + putglyph 0x6c 1 0,3 dwl dhl-top + putglyph 0x6f 1 0,4 dwl dhl-top + ?cursor = 0,5 + PUSH "\r\n\e#4" + PUSH "Hello" + putglyph 0x48 1 1,0 dwl dhl-bottom + putglyph 0x65 1 1,1 dwl dhl-bottom + putglyph 0x6c 1 1,2 dwl dhl-bottom + putglyph 0x6c 1 1,3 dwl dhl-bottom + putglyph 0x6f 1 1,4 dwl dhl-bottom + ?cursor = 1,5 + + !Double Width scrolling + RESET + PUSH "\e[20H\e#6ABC" + putglyph 0x41 1 19,0 dwl + putglyph 0x42 1 19,1 dwl + putglyph 0x43 1 19,2 dwl + PUSH "\e[25H\n" + PUSH "\e[19;4HDE" + putglyph 0x44 1 18,3 dwl + putglyph 0x45 1 18,4 dwl + PUSH "\e[H\eM" + PUSH "\e[20;6HFG" + putglyph 0x46 1 19,5 dwl + putglyph 0x47 1 19,6 dwl *** ../vim-8.0.0692/src/libvterm/t/29state_fallback.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/29state_fallback.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,19 ---- + INIT + WANTSTATE f + RESET + + !Unrecognised control + PUSH "\x03" + control 03 + + !Unrecognised CSI + PUSH "\e[?15;2z" + csi 0x7a L=3f 15,2 + + !Unrecognised OSC + PUSH "\e]27;Something\e\\" + osc "27;Something" + + !Unrecognised DCS + PUSH "\ePz123\e\\" + dcs "z123" *** ../vim-8.0.0692/src/libvterm/t/30pen.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/30pen.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,106 ---- + INIT + UTF8 1 + WANTSTATE + + !Reset + PUSH "\e[m" + ?pen bold = off + ?pen underline = 0 + ?pen italic = off + ?pen blink = off + ?pen reverse = off + ?pen font = 0 + ?pen foreground = rgb(240,240,240) + ?pen background = rgb(0,0,0) + + !Bold + PUSH "\e[1m" + ?pen bold = on + PUSH "\e[22m" + ?pen bold = off + PUSH "\e[1m\e[m" + ?pen bold = off + + !Underline + PUSH "\e[4m" + ?pen underline = 1 + PUSH "\e[21m" + ?pen underline = 2 + PUSH "\e[24m" + ?pen underline = 0 + PUSH "\e[4m\e[m" + ?pen underline = 0 + + !Italic + PUSH "\e[3m" + ?pen italic = on + PUSH "\e[23m" + ?pen italic = off + PUSH "\e[3m\e[m" + ?pen italic = off + + !Blink + PUSH "\e[5m" + ?pen blink = on + PUSH "\e[25m" + ?pen blink = off + PUSH "\e[5m\e[m" + ?pen blink = off + + !Reverse + PUSH "\e[7m" + ?pen reverse = on + PUSH "\e[27m" + ?pen reverse = off + PUSH "\e[7m\e[m" + ?pen reverse = off + + !Font Selection + PUSH "\e[11m" + ?pen font = 1 + PUSH "\e[19m" + ?pen font = 9 + PUSH "\e[10m" + ?pen font = 0 + PUSH "\e[11m\e[m" + ?pen font = 0 + + !Foreground + PUSH "\e[31m" + ?pen foreground = rgb(224,0,0) + PUSH "\e[32m" + ?pen foreground = rgb(0,224,0) + PUSH "\e[34m" + ?pen foreground = rgb(0,0,224) + PUSH "\e[91m" + ?pen foreground = rgb(255,64,64) + PUSH "\e[38:2:10:20:30m" + ?pen foreground = rgb(10,20,30) + PUSH "\e[38:5:1m" + ?pen foreground = rgb(224,0,0) + PUSH "\e[39m" + ?pen foreground = rgb(240,240,240) + + !Background + PUSH "\e[41m" + ?pen background = rgb(224,0,0) + PUSH "\e[42m" + ?pen background = rgb(0,224,0) + PUSH "\e[44m" + ?pen background = rgb(0,0,224) + PUSH "\e[101m" + ?pen background = rgb(255,64,64) + PUSH "\e[48:2:10:20:30m" + ?pen background = rgb(10,20,30) + PUSH "\e[48:5:1m" + ?pen background = rgb(224,0,0) + PUSH "\e[49m" + ?pen background = rgb(0,0,0) + + !Bold+ANSI colour == highbright + PUSH "\e[m\e[1;37m" + ?pen bold = on + ?pen foreground = rgb(255,255,255) + PUSH "\e[m\e[37;1m" + ?pen bold = on + ?pen foreground = rgb(255,255,255) *** ../vim-8.0.0692/src/libvterm/t/40screen_ascii.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/40screen_ascii.test 2017-06-30 22:14:57.139900837 +0200 *************** *** 0 **** --- 1,69 ---- + INIT + WANTSCREEN c + + !Get + RESET + PUSH "ABC" + movecursor 0,3 + ?screen_chars 0,0,1,3 = 0x41,0x42,0x43 + ?screen_chars 0,0,1,80 = 0x41,0x42,0x43 + ?screen_text 0,0,1,3 = 0x41,0x42,0x43 + ?screen_text 0,0,1,80 = 0x41,0x42,0x43 + ?screen_cell 0,0 = {0x41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_cell 0,1 = {0x42} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_cell 0,2 = {0x43} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_row 0 = "ABC" + ?screen_eol 0,0 = 0 + ?screen_eol 0,2 = 0 + ?screen_eol 0,3 = 1 + PUSH "\e[H" + movecursor 0,0 + ?screen_chars 0,0,1,80 = 0x41,0x42,0x43 + ?screen_text 0,0,1,80 = 0x41,0x42,0x43 + PUSH "E" + movecursor 0,1 + ?screen_chars 0,0,1,80 = 0x45,0x42,0x43 + ?screen_text 0,0,1,80 = 0x45,0x42,0x43 + + WANTSCREEN -c + + !Erase + RESET + PUSH "ABCDE\e[H\e[K" + ?screen_chars 0,0,1,80 = + ?screen_text 0,0,1,80 = + + !Copycell + RESET + PUSH "ABC\e[H\e[@" + PUSH "1" + ?screen_chars 0,0,1,80 = 0x31,0x41,0x42,0x43 + + RESET + PUSH "ABC\e[H\e[P" + ?screen_chars 0,0,1,1 = 0x42 + ?screen_chars 0,1,1,2 = 0x43 + ?screen_chars 0,0,1,80 = 0x42,0x43 + + !Space padding + RESET + PUSH "Hello\e[CWorld" + ?screen_chars 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64 + ?screen_text 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64 + + !Linefeed padding + RESET + PUSH "Hello\r\nWorld" + ?screen_chars 0,0,2,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x0a,0x57,0x6f,0x72,0x6c,0x64 + ?screen_text 0,0,2,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x0a,0x57,0x6f,0x72,0x6c,0x64 + + !Altscreen + RESET + PUSH "P" + ?screen_chars 0,0,1,80 = 0x50 + PUSH "\e[?1049h" + ?screen_chars 0,0,1,80 = + PUSH "\e[2K\e[HA" + ?screen_chars 0,0,1,80 = 0x41 + PUSH "\e[?1049l" + ?screen_chars 0,0,1,80 = 0x50 *** ../vim-8.0.0692/src/libvterm/t/41screen_unicode.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/41screen_unicode.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,47 ---- + INIT + UTF8 1 + WANTSCREEN + + !Single width UTF-8 + # U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE + # U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE + RESET + PUSH "\xC3\x81\xC3\xA9" + ?screen_chars 0,0,1,80 = 0xc1,0xe9 + ?screen_text 0,0,1,80 = 0xc3,0x81,0xc3,0xa9 + ?screen_cell 0,0 = {0xc1} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Wide char + # U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO + RESET + PUSH "0123\e[H" + PUSH "\xEF\xBC\x90" + ?screen_chars 0,0,1,80 = 0xff10,0x32,0x33 + ?screen_text 0,0,1,80 = 0xef,0xbc,0x90,0x32,0x33 + ?screen_cell 0,0 = {0xff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Combining char + # U+0301 = 0xCC 0x81 name: COMBINING ACUTE + RESET + PUSH "0123\e[H" + PUSH "e\xCC\x81" + ?screen_chars 0,0,1,80 = 0x65,0x301,0x31,0x32,0x33 + ?screen_text 0,0,1,80 = 0x65,0xcc,0x81,0x31,0x32,0x33 + ?screen_cell 0,0 = {0x65,0x301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !10 combining accents should not crash + RESET + PUSH "e\xCC\x81\xCC\x82\xCC\x83\xCC\x84\xCC\x85\xCC\x86\xCC\x87\xCC\x88\xCC\x89\xCC\x8A" + ?screen_cell 0,0 = {0x65,0x301,0x302,0x303,0x304,0x305} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !40 combining accents in two split writes of 20 should not crash + RESET + PUSH "e\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81" + PUSH "\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81" + ?screen_cell 0,0 = {0x65,0x301,0x301,0x301,0x301,0x301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Outputing CJK doublewidth in 80th column should wraparound to next line and not crash" + RESET + PUSH "\e[80G\xEF\xBC\x90" + ?screen_cell 0,79 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_cell 1,0 = {0xff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) *** ../vim-8.0.0692/src/libvterm/t/42screen_damage.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/42screen_damage.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,155 ---- + INIT + WANTSCREEN Db + + !Putglyph + RESET + damage 0..25,0..80 + PUSH "123" + damage 0..1,0..1 = 0<31> + damage 0..1,1..2 = 0<32> + damage 0..1,2..3 = 0<33> + + !Erase + PUSH "\e[H" + PUSH "\e[3X" + damage 0..1,0..3 + + !Scroll damages entire line in two chunks + PUSH "\e[H\e[5@" + damage 0..1,5..80 + damage 0..1,0..5 + + !Scroll down damages entire screen in two chunks + PUSH "\e[T" + damage 1..25,0..80 + damage 0..1,0..80 + + !Altscreen damages entire area + PUSH "\e[?1049h" + damage 0..25,0..80 + PUSH "\e[?1049l" + damage 0..25,0..80 + + WANTSCREEN m + + !Scroll invokes moverect but not damage + PUSH "\e[5@" + moverect 0..1,0..75 -> 0..1,5..80 + damage 0..1,0..5 + + WANTSCREEN -m + + !Merge to cells + RESET + damage 0..25,0..80 + DAMAGEMERGE CELL + + PUSH "A" + damage 0..1,0..1 = 0<41> + PUSH "B" + damage 0..1,1..2 = 0<42> + PUSH "C" + damage 0..1,2..3 = 0<43> + + !Merge entire rows + RESET + damage 0..25,0..80 + DAMAGEMERGE ROW + + PUSH "ABCDE\r\nEFGH" + damage 0..1,0..5 = 0<41 42 43 44 45> + DAMAGEFLUSH + damage 1..2,0..4 = 1<45 46 47 48> + PUSH "\e[3;6r\e[6H\eD" + damage 2..5,0..80 + DAMAGEFLUSH + damage 5..6,0..80 + + !Merge entire screen + RESET + damage 0..25,0..80 + DAMAGEMERGE SCREEN + + PUSH "ABCDE\r\nEFGH" + DAMAGEFLUSH + damage 0..2,0..5 = 0<41 42 43 44 45> 1<45 46 47 48> + PUSH "\e[3;6r\e[6H\eD" + DAMAGEFLUSH + damage 2..6,0..80 + + !Merge entire screen with moverect + WANTSCREEN m + + RESET + damage 0..25,0..80 + DAMAGEMERGE SCREEN + + PUSH "ABCDE\r\nEFGH" + PUSH "\e[3;6r\e[6H\eD" + damage 0..2,0..5 = 0<41 42 43 44 45> 1<45 46 47 48> + moverect 3..6,0..80 -> 2..5,0..80 + DAMAGEFLUSH + damage 5..6,0..80 + + !Merge scroll + RESET + damage 0..25,0..80 + DAMAGEMERGE SCROLL + + PUSH "\e[H1\r\n2\r\n3" + PUSH "\e[25H\n\n\n" + sb_pushline 80 = 31 + sb_pushline 80 = 32 + sb_pushline 80 = 33 + DAMAGEFLUSH + moverect 3..25,0..80 -> 0..22,0..80 + damage 0..25,0..80 + + !Merge scroll with damage + PUSH "\e[25H" + PUSH "ABCDE\r\nEFGH\r\n" + sb_pushline 80 = + sb_pushline 80 = + DAMAGEFLUSH + moverect 2..25,0..80 -> 0..23,0..80 + damage 22..25,0..80 = 22<41 42 43 44 45> 23<45 46 47 48> + + !Merge scroll with damage past region + PUSH "\e[3;6r\e[6H1\r\n2\r\n3\r\n4\r\n5" + DAMAGEFLUSH + damage 2..6,0..80 = 2<32> 3<33> 4<34> 5<35> + + !Damage entirely outside scroll region + PUSH "\e[HABC\e[3;6r\e[6H\r\n6" + damage 0..1,0..3 = 0<41 42 43> + DAMAGEFLUSH + moverect 3..6,0..80 -> 2..5,0..80 + damage 5..6,0..80 = 5<36> + + !Damage overlapping scroll region + PUSH "\e[H\e[2J" + DAMAGEFLUSH + damage 0..25,0..80 + + PUSH "\e[HABCD\r\nEFGH\r\nIJKL\e[2;5r\e[5H\r\nMNOP" + DAMAGEFLUSH + moverect 2..5,0..80 -> 1..4,0..80 + damage 0..5,0..80 = 0<41 42 43 44> 1<49 4A 4B 4C> + ## TODO: is this right? + + !Merge scroll*2 with damage + RESET + damage 0..25,0..80 + DAMAGEMERGE SCROLL + + PUSH "\e[25H\r\nABCDE\b\b\b\e[2P\r\n" + sb_pushline 80 = + moverect 1..25,0..80 -> 0..24,0..80 + damage 24..25,0..80 = 24<41 42 43 44 45> + moverect 24..25,4..80 -> 24..25,2..78 + damage 24..25,78..80 + sb_pushline 80 = + DAMAGEFLUSH + moverect 1..25,0..80 -> 0..24,0..80 + damage 24..25,0..80 + ?screen_chars 23,0,24,5 = 0x41,0x42,0x45 *** ../vim-8.0.0692/src/libvterm/t/43screen_resize.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/43screen_resize.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,90 ---- + INIT + WANTSTATE + WANTSCREEN + + !Resize wider preserves cells + RESET + RESIZE 25,80 + PUSH "AB\r\nCD" + ?screen_chars 0,0,1,80 = 0x41,0x42 + ?screen_chars 1,0,2,80 = 0x43,0x44 + RESIZE 25,100 + ?screen_chars 0,0,1,100 = 0x41,0x42 + ?screen_chars 1,0,2,100 = 0x43,0x44 + + !Resize wider allows print in new area + RESET + RESIZE 25,80 + PUSH "AB\e[79GCD" + ?screen_chars 0,0,1,2 = 0x41,0x42 + ?screen_chars 0,78,1,80 = 0x43,0x44 + RESIZE 25,100 + ?screen_chars 0,0,1,2 = 0x41,0x42 + ?screen_chars 0,78,1,80 = 0x43,0x44 + PUSH "E" + ?screen_chars 0,78,1,81 = 0x43,0x44,0x45 + + !Resize shorter with blanks just truncates + RESET + RESIZE 25,80 + PUSH "Top\e[10HLine 10" + ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70 + ?screen_chars 9,0,10,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31,0x30 + ?cursor = 9,7 + RESIZE 20,80 + ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70 + ?screen_chars 9,0,10,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31,0x30 + ?cursor = 9,7 + + !Resize shorter with content must scroll + RESET + RESIZE 25,80 + PUSH "Top\e[25HLine 25\e[15H" + ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70 + ?screen_chars 24,0,25,80 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?cursor = 14,0 + WANTSCREEN b + RESIZE 20,80 + sb_pushline 80 = 54 6F 70 + sb_pushline 80 = + sb_pushline 80 = + sb_pushline 80 = + sb_pushline 80 = + ?screen_chars 0,0,1,80 = + ?screen_chars 19,0,20,80 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?cursor = 9,0 + + !Resize shorter does not lose line with cursor + # See also https://github.com/neovim/libvterm/commit/1b745d29d45623aa8d22a7b9288c7b0e331c7088 + RESET + WANTSCREEN -b + RESIZE 25,80 + WANTSCREEN b + PUSH "\e[24HLine 24\r\nLine 25\r\n" + sb_pushline 80 = + ?screen_chars 23,0,24,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?cursor = 24,0 + RESIZE 24,80 + sb_pushline 80 = + ?screen_chars 22,0,23,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?cursor = 23,0 + + !Resize taller attempts to pop scrollback + RESET + WANTSCREEN -b + RESIZE 25,80 + PUSH "Line 1\e[25HBottom\e[15H" + ?screen_chars 0,0,1,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31 + ?screen_chars 24,0,25,80 = 0x42,0x6f,0x74,0x74,0x6f,0x6d + ?cursor = 14,0 + WANTSCREEN b + RESIZE 30,80 + sb_popline 80 + sb_popline 80 + sb_popline 80 + sb_popline 80 + sb_popline 80 + ?screen_chars 0,0,1,80 = 0x41,0x42,0x43,0x44,0x45 + ?screen_chars 5,0,6,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31 + ?screen_chars 29,0,30,80 = 0x42,0x6f,0x74,0x74,0x6f,0x6d + ?cursor = 19,0 *** ../vim-8.0.0692/src/libvterm/t/44screen_pen.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/44screen_pen.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,55 ---- + INIT + WANTSCREEN + + RESET + + !Plain + PUSH "A" + ?screen_cell 0,0 = {0x41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Bold + PUSH "\e[1mB" + ?screen_cell 0,1 = {0x42} width=1 attrs={B} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Italic + PUSH "\e[3mC" + ?screen_cell 0,2 = {0x43} width=1 attrs={BI} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Underline + PUSH "\e[4mD" + ?screen_cell 0,3 = {0x44} width=1 attrs={BU1I} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Reset + PUSH "\e[mE" + ?screen_cell 0,4 = {0x45} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Font + PUSH "\e[11mF\e[m" + ?screen_cell 0,5 = {0x46} width=1 attrs={F1} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Foreground + PUSH "\e[31mG\e[m" + ?screen_cell 0,6 = {0x47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0) + + !Background + PUSH "\e[42mH\e[m" + ?screen_cell 0,7 = {0x48} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,224,0) + + !EL sets reverse and colours to end of line + PUSH "\e[H\e[7;33;44m\e[K" + ?screen_cell 0,0 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224) + ?screen_cell 0,79 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224) + + !DECSCNM xors reverse for entire screen + PUSH "\e[?5h" + ?screen_cell 0,0 = {} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224) + ?screen_cell 0,79 = {} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224) + ?screen_cell 1,0 = {} width=1 attrs={R} fg=rgb(240,240,240) bg=rgb(0,0,0) + PUSH "\e[?5\$p" + output "\e[?5;1\$y" + PUSH "\e[?5l" + ?screen_cell 0,0 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224) + ?screen_cell 0,79 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224) + ?screen_cell 1,0 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + PUSH "\e[?5\$p" + output "\e[?5;2\$y" *** ../vim-8.0.0692/src/libvterm/t/45screen_protect.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/45screen_protect.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,16 ---- + INIT + WANTSCREEN + + !Selective erase + RESET + PUSH "A\e[1\"qB\e[\"qC" + ?screen_chars 0,0,1,3 = 0x41,0x42,0x43 + PUSH "\e[G\e[?J" + ?screen_chars 0,0,1,3 = 0x20,0x42 + + !Non-selective erase + RESET + PUSH "A\e[1\"qB\e[\"qC" + ?screen_chars 0,0,1,3 = 0x41,0x42,0x43 + PUSH "\e[G\e[J" + ?screen_chars 0,0,1,3 = *** ../vim-8.0.0692/src/libvterm/t/46screen_extent.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/46screen_extent.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,11 ---- + INIT + WANTSCREEN + + !Bold extent + RESET + PUSH "AB\e[1mCD\e[mE" + ?screen_attrs_extent 0,0 = 0,0-1,1 + ?screen_attrs_extent 0,1 = 0,0-1,1 + ?screen_attrs_extent 0,2 = 0,2-1,3 + ?screen_attrs_extent 0,3 = 0,2-1,3 + ?screen_attrs_extent 0,4 = 0,4-1,79 *** ../vim-8.0.0692/src/libvterm/t/47screen_dbl_wh.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/47screen_dbl_wh.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,32 ---- + INIT + WANTSCREEN + + RESET + + !Single Width, Single Height + RESET + PUSH "\e#5" + PUSH "abcde" + ?screen_cell 0,0 = {0x61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Double Width, Single Height + RESET + PUSH "\e#6" + PUSH "abcde" + ?screen_cell 0,0 = {0x61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Double Height + RESET + PUSH "\e#3" + PUSH "abcde" + PUSH "\r\n\e#4" + PUSH "abcde" + ?screen_cell 0,0 = {0x61} width=1 attrs={} dwl dhl-top fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_cell 1,0 = {0x61} width=1 attrs={} dwl dhl-bottom fg=rgb(240,240,240) bg=rgb(0,0,0) + + !Late change + RESET + PUSH "abcde" + ?screen_cell 0,0 = {0x61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + PUSH "\e#6" + ?screen_cell 0,0 = {0x61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0) *** ../vim-8.0.0692/src/libvterm/t/48screen_termprops.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/48screen_termprops.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,17 ---- + INIT + WANTSCREEN p + + RESET + settermprop 1 true + settermprop 2 true + settermprop 7 1 + + !Cursor visibility + PUSH "\e[?25h" + settermprop 1 true + PUSH "\e[?25l" + settermprop 1 false + + !Title + PUSH "\e]2;Here is my title\a" + settermprop 4 "Here is my title" *** ../vim-8.0.0692/src/libvterm/t/90vttest_01-movement-1.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/90vttest_01-movement-1.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,87 ---- + INIT + WANTSTATE + WANTSCREEN + + RESET + + PUSH "\e#8" + + PUSH "\e[9;10H\e[1J" + PUSH "\e[18;60H\e[0J\e[1K" + PUSH "\e[9;71H\e[0K" + + $SEQ 10 16: PUSH "\e[\#;10H\e[1K\e[\#;71H\e[0K" + + PUSH "\e[17;30H\e[2K" + + $SEQ 1 80: PUSH "\e[24;\#f*\e[1;\#f*" + + PUSH "\e[2;2H" + + $REP 22: PUSH "+\e[1D\eD" + + PUSH "\e[23;79H" + $REP 22: PUSH "+\e[1D\eM" + + PUSH "\e[2;1H" + $SEQ 2 23: PUSH "*\e[\#;80H*\e[10D\eE" + + PUSH "\e[2;10H\e[42D\e[2C" + $REP 76: PUSH "+\e[0C\e[2D\e[1C" + + PUSH "\e[23;70H\e[42C\e[2D" + + $REP 76: PUSH "+\e[1D\e[1C\e[0D\b" + + PUSH "\e[1;1H" + PUSH "\e[10A" + PUSH "\e[1A" + PUSH "\e[0A" + PUSH "\e[24;80H" + PUSH "\e[10B" + PUSH "\e[1B" + PUSH "\e[0B" + PUSH "\e[10;12H" + + $REP 58: PUSH " " + PUSH "\e[1B\e[58D" + + $REP 58: PUSH " " + PUSH "\e[1B\e[58D" + + $REP 58: PUSH " " + PUSH "\e[1B\e[58D" + + $REP 58: PUSH " " + PUSH "\e[1B\e[58D" + + $REP 58: PUSH " " + PUSH "\e[1B\e[58D" + + $REP 58: PUSH " " + PUSH "\e[1B\e[58D" + + PUSH "\e[5A\e[1CThe screen should be cleared, and have an unbroken bor-" + PUSH "\e[12;13Hder of *'s and +'s around the edge, and exactly in the" + PUSH "\e[13;13Hmiddle there should be a frame of E's around this text" + PUSH "\e[14;13Hwith one (1) free position around it. Push " + + # And the result is... + + !Output + ?screen_row 0 = "********************************************************************************" + ?screen_row 1 = "*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*" + $SEQ 2 7: ?screen_row \# = "*+ +*" + ?screen_row 8 = "*+ EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +*" + ?screen_row 9 = "*+ E E +*" + ?screen_row 10 = "*+ E The screen should be cleared, and have an unbroken bor- E +*" + ?screen_row 11 = "*+ E der of *'s and +'s around the edge, and exactly in the E +*" + ?screen_row 12 = "*+ E middle there should be a frame of E's around this text E +*" + ?screen_row 13 = "*+ E with one (1) free position around it. Push E +*" + ?screen_row 14 = "*+ E E +*" + ?screen_row 15 = "*+ EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +*" + $SEQ 16 21: ?screen_row \# = "*+ +*" + ?screen_row 22 = "*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*" + ?screen_row 23 = "********************************************************************************" + + ?cursor = 13,67 *** ../vim-8.0.0692/src/libvterm/t/90vttest_01-movement-2.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/90vttest_01-movement-2.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,40 ---- + INIT + WANTSTATE + WANTSCREEN + + RESET + + PUSH "\e[3;21r" + PUSH "\e[?6h" + + PUSH "\e[19;1HA\e[19;80Ha\x0a\e[18;80HaB\e[19;80HB\b b\x0a\e[19;80HC\b\b\t\tc\e[19;2H\bC\x0a\e[19;80H\x0a\e[18;1HD\e[18;80Hd" + PUSH "\e[19;1HE\e[19;80He\x0a\e[18;80HeF\e[19;80HF\b f\x0a\e[19;80HG\b\b\t\tg\e[19;2H\bG\x0a\e[19;80H\x0a\e[18;1HH\e[18;80Hh" + PUSH "\e[19;1HI\e[19;80Hi\x0a\e[18;80HiJ\e[19;80HJ\b j\x0a\e[19;80HK\b\b\t\tk\e[19;2H\bK\x0a\e[19;80H\x0a\e[18;1HL\e[18;80Hl" + PUSH "\e[19;1HM\e[19;80Hm\x0a\e[18;80HmN\e[19;80HN\b n\x0a\e[19;80HO\b\b\t\to\e[19;2H\bO\x0a\e[19;80H\x0a\e[18;1HP\e[18;80Hp" + PUSH "\e[19;1HQ\e[19;80Hq\x0a\e[18;80HqR\e[19;80HR\b r\x0a\e[19;80HS\b\b\t\ts\e[19;2H\bS\x0a\e[19;80H\x0a\e[18;1HT\e[18;80Ht" + PUSH "\e[19;1HU\e[19;80Hu\x0a\e[18;80HuV\e[19;80HV\b v\x0a\e[19;80HW\b\b\t\tw\e[19;2H\bW\x0a\e[19;80H\x0a\e[18;1HX\e[18;80Hx" + PUSH "\e[19;1HY\e[19;80Hy\x0a\e[18;80HyZ\e[19;80HZ\b z\x0a" + + !Output + + ?screen_row 2 = "I i" + ?screen_row 3 = "J j" + ?screen_row 4 = "K k" + ?screen_row 5 = "L l" + ?screen_row 6 = "M m" + ?screen_row 7 = "N n" + ?screen_row 8 = "O o" + ?screen_row 9 = "P p" + ?screen_row 10 = "Q q" + ?screen_row 11 = "R r" + ?screen_row 12 = "S s" + ?screen_row 13 = "T t" + ?screen_row 14 = "U u" + ?screen_row 15 = "V v" + ?screen_row 16 = "W w" + ?screen_row 17 = "X x" + ?screen_row 18 = "Y y" + ?screen_row 19 = "Z z" + ?screen_row 20 = "" + + ?cursor = 20,79 *** ../vim-8.0.0692/src/libvterm/t/90vttest_01-movement-3.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/90vttest_01-movement-3.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,21 ---- + # Test of cursor-control characters inside ESC sequences + INIT + WANTSTATE + WANTSCREEN + + RESET + + PUSH "A B C D E F G H I" + PUSH "\x0d\x0a" + PUSH "A\e[2\bCB\e[2\bCC\e[2\bCD\e[2\bCE\e[2\bCF\e[2\bCG\e[2\bCH\e[2\bCI" + PUSH "\x0d\x0a" + PUSH "A \e[\x0d2CB\e[\x0d4CC\e[\x0d6CD\e[\x0d8CE\e[\x0d10CF\e[\x0d12CG\e[\x0d14CH\e[\x0d16CI" + PUSH "\x0d\x0a" + PUSH "A \e[1\x0bAB \e[1\x0bAC \e[1\x0bAD \e[1\x0bAE \e[1\x0bAF \e[1\x0bAG \e[1\x0bAH \e[1\x0bAI \e[1\x0bA" + + !Output + + $SEQ 0 2: ?screen_row \# = "A B C D E F G H I" + ?screen_row 3 = "A B C D E F G H I " + + ?cursor = 3,18 *** ../vim-8.0.0692/src/libvterm/t/90vttest_01-movement-4.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/90vttest_01-movement-4.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,36 ---- + # Test of leading zeroes in ESC sequences + INIT + WANTSCREEN + + RESET + + PUSH "\e[00000000004;000000001HT" + PUSH "\e[00000000004;000000002Hh" + PUSH "\e[00000000004;000000003Hi" + PUSH "\e[00000000004;000000004Hs" + PUSH "\e[00000000004;000000005H " + PUSH "\e[00000000004;000000006Hi" + PUSH "\e[00000000004;000000007Hs" + PUSH "\e[00000000004;000000008H " + PUSH "\e[00000000004;000000009Ha" + PUSH "\e[00000000004;0000000010H " + PUSH "\e[00000000004;0000000011Hc" + PUSH "\e[00000000004;0000000012Ho" + PUSH "\e[00000000004;0000000013Hr" + PUSH "\e[00000000004;0000000014Hr" + PUSH "\e[00000000004;0000000015He" + PUSH "\e[00000000004;0000000016Hc" + PUSH "\e[00000000004;0000000017Ht" + PUSH "\e[00000000004;0000000018H " + PUSH "\e[00000000004;0000000019Hs" + PUSH "\e[00000000004;0000000020He" + PUSH "\e[00000000004;0000000021Hn" + PUSH "\e[00000000004;0000000022Ht" + PUSH "\e[00000000004;0000000023He" + PUSH "\e[00000000004;0000000024Hn" + PUSH "\e[00000000004;0000000025Hc" + PUSH "\e[00000000004;0000000026He" + + !Output + + ?screen_row 3 = "This is a correct sentence" *** ../vim-8.0.0692/src/libvterm/t/90vttest_02-screen-1.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/90vttest_02-screen-1.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,18 ---- + # Test of WRAP AROUND mode setting. + INIT + WANTSCREEN + + RESET + + PUSH "\e[?7h" + $REP 170: PUSH "*" + + PUSH "\e[?7l\e[3;1H" + $REP 177: PUSH "*" + + PUSH "\e[?7h\e[5;1HOK" + + !Output + $SEQ 0 2: ?screen_row \# = "********************************************************************************" + ?screen_row 3 = "" + ?screen_row 4 = "OK" *** ../vim-8.0.0692/src/libvterm/t/90vttest_02-screen-2.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/90vttest_02-screen-2.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,29 ---- + # TAB setting/resetting + INIT + WANTSTATE + WANTSCREEN + + RESET + + PUSH "\e[2J\e[3g" + + PUSH "\e[1;1H" + $REP 26: PUSH "\e[3C\eH" + + PUSH "\e[1;4H" + $REP 13: PUSH "\e[0g\e[6C" + + PUSH "\e[1;7H" + PUSH "\e[1g\e[2g" + + PUSH "\e[1;1H" + $REP 13: PUSH "\t*" + + PUSH "\e[2;2H" + $REP 13: PUSH " *" + + !Output + ?screen_row 0 = " * * * * * * * * * * * * *" + ?screen_row 1 = " * * * * * * * * * * * * *" + + ?cursor = 1,79 *** ../vim-8.0.0692/src/libvterm/t/90vttest_02-screen-3.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/90vttest_02-screen-3.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,16 ---- + # Origin mode + INIT + WANTSCREEN + + RESET + + PUSH "\e[?6h" + PUSH "\e[23;24r" + PUSH "\n" + PUSH "Bottom" + PUSH "\e[1;1H" + PUSH "Above" + + !Output + ?screen_row 22 = "Above" + ?screen_row 23 = "Bottom" *** ../vim-8.0.0692/src/libvterm/t/90vttest_02-screen-4.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/90vttest_02-screen-4.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,17 ---- + # Origin mode (2) + INIT + WANTSCREEN + + RESET + + PUSH "\e[?6l" + PUSH "\e[23;24r" + PUSH "\e[24;1H" + PUSH "Bottom" + PUSH "\e[1;1H" + PUSH "Top" + + !Output + ?screen_row 23 = "Bottom" + ?screen_row 0 = "Top" + *** ../vim-8.0.0692/src/libvterm/t/92lp1640917.test 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/92lp1640917.test 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,13 ---- + INIT + WANTSTATE + + !Mouse reporting should not break by idempotent DECSM 1002 + PUSH "\e[?1002h" + MOUSEMOVE 0,0 0 + MOUSEBTN d 1 0 + output "\e[M\x20\x21\x21" + MOUSEMOVE 1,0 0 + output "\e[M\x40\x21\x22" + PUSH "\e[?1002h" + MOUSEMOVE 2,0 0 + output "\e[M\x40\x21\x23" *** ../vim-8.0.0692/src/libvterm/t/harness.c 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/harness.c 2017-06-30 22:17:16.266818196 +0200 *************** *** 0 **** --- 1,929 ---- + #include "vterm.h" + #include "../src/vterm_internal.h" /* We pull in some internal bits too */ + + #include + #include + + #define streq(a,b) (!strcmp(a,b)) + #define strstartswith(a,b) (!strncmp(a,b,strlen(b))) + + static size_t inplace_hex2bytes(char *s) + { + char *inpos = s, *outpos = s; + + while(*inpos) { + unsigned int ch; + sscanf(inpos, "%2x", &ch); + *outpos = ch; + outpos += 1; inpos += 2; + } + + return outpos - s; + } + + static VTermModifier strpe_modifiers(char **strp) + { + VTermModifier state = 0; + + while((*strp)[0]) { + switch(((*strp)++)[0]) { + case 'S': state |= VTERM_MOD_SHIFT; break; + case 'C': state |= VTERM_MOD_CTRL; break; + case 'A': state |= VTERM_MOD_ALT; break; + default: return state; + } + } + + return state; + } + + static VTermKey strp_key(char *str) + { + static struct { + char *name; + VTermKey key; + } keys[] = { + { "Up", VTERM_KEY_UP }, + { "Tab", VTERM_KEY_TAB }, + { "Enter", VTERM_KEY_ENTER }, + { "KP0", VTERM_KEY_KP_0 }, + { NULL, VTERM_KEY_NONE }, + }; + int i; + + for(i = 0; keys[i].name; i++) { + if(streq(str, keys[i].name)) + return keys[i].key; + } + + return VTERM_KEY_NONE; + } + + static VTerm *vt; + static VTermState *state; + static VTermScreen *screen; + + static VTermEncodingInstance encoding; + + static int parser_text(const char bytes[], size_t len, void *user) + { + int i; + + printf("text "); + for(i = 0; i < len; i++) { + unsigned char b = bytes[i]; + if(b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0)) + break; + printf(i ? ",%x" : "%x", b); + } + printf("\n"); + + return i; + } + + static int parser_control(unsigned char control, void *user) + { + printf("control %02x\n", control); + + return 1; + } + + static int parser_escape(const char bytes[], size_t len, void *user) + { + int i; + + if(bytes[0] >= 0x20 && bytes[0] < 0x30) { + if(len < 2) + return -1; + len = 2; + } + else { + len = 1; + } + + printf("escape "); + for(i = 0; i < len; i++) + printf("%02x", bytes[i]); + printf("\n"); + + return len; + } + + static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) + { + int i; + printf("csi %02x", command); + + if(leader && leader[0]) { + printf(" L="); + for(i = 0; leader[i]; i++) + printf("%02x", leader[i]); + } + + for(i = 0; i < argcount; i++) { + char sep = i ? ',' : ' '; + + if(args[i] == CSI_ARG_MISSING) + printf("%c*", sep); + else + printf("%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : ""); + } + + if(intermed && intermed[0]) { + printf(" I="); + for(i = 0; intermed[i]; i++) + printf("%02x", intermed[i]); + } + + printf("\n"); + + return 1; + } + + static int parser_osc(const char *command, size_t cmdlen, void *user) + { + int i; + printf("osc "); + for(i = 0; i < cmdlen; i++) + printf("%02x", command[i]); + printf("\n"); + + return 1; + } + + static int parser_dcs(const char *command, size_t cmdlen, void *user) + { + int i; + printf("dcs "); + for(i = 0; i < cmdlen; i++) + printf("%02x", command[i]); + printf("\n"); + + return 1; + } + + static VTermParserCallbacks parser_cbs = { + parser_text, /* text */ + parser_control, /* control */ + parser_escape, /* escape */ + parser_csi, /* csi */ + parser_osc, /* osc */ + parser_dcs, /* dcs */ + NULL /* resize */ + }; + + /* These callbacks are shared by State and Screen */ + + static int want_movecursor = 0; + static VTermPos state_pos; + static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) + { + state_pos = pos; + + if(want_movecursor) + printf("movecursor %d,%d\n", pos.row, pos.col); + + return 1; + } + + static int want_scrollrect = 0; + static int scrollrect(VTermRect rect, int downward, int rightward, void *user) + { + if(!want_scrollrect) + return 0; + + printf("scrollrect %d..%d,%d..%d => %+d,%+d\n", + rect.start_row, rect.end_row, rect.start_col, rect.end_col, + downward, rightward); + + return 1; + } + + static int want_moverect = 0; + static int moverect(VTermRect dest, VTermRect src, void *user) + { + if(!want_moverect) + return 0; + + printf("moverect %d..%d,%d..%d -> %d..%d,%d..%d\n", + src.start_row, src.end_row, src.start_col, src.end_col, + dest.start_row, dest.end_row, dest.start_col, dest.end_col); + + return 1; + } + + static int want_settermprop = 0; + static int settermprop(VTermProp prop, VTermValue *val, void *user) + { + VTermValueType type; + if(!want_settermprop) + return 1; + + type = vterm_get_prop_type(prop); + switch(type) { + case VTERM_VALUETYPE_BOOL: + printf("settermprop %d %s\n", prop, val->boolean ? "true" : "false"); + return 1; + case VTERM_VALUETYPE_INT: + printf("settermprop %d %d\n", prop, val->number); + return 1; + case VTERM_VALUETYPE_STRING: + printf("settermprop %d \"%s\"\n", prop, val->string); + return 1; + case VTERM_VALUETYPE_COLOR: + printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue); + return 1; + } + + return 0; + } + + /* These callbacks are for State */ + + static int want_state_putglyph = 0; + static int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) + { + int i; + if(!want_state_putglyph) + return 1; + + printf("putglyph "); + for(i = 0; info->chars[i]; i++) + printf(i ? ",%x" : "%x", info->chars[i]); + printf(" %d %d,%d", info->width, pos.row, pos.col); + if(info->protected_cell) + printf(" prot"); + if(info->dwl) + printf(" dwl"); + if(info->dhl) + printf(" dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?" ); + printf("\n"); + + return 1; + } + + static int want_state_erase = 0; + static int state_erase(VTermRect rect, int selective, void *user) + { + if(!want_state_erase) + return 1; + + printf("erase %d..%d,%d..%d%s\n", + rect.start_row, rect.end_row, rect.start_col, rect.end_col, + selective ? " selective" : ""); + + return 1; + } + + static struct { + int bold; + int underline; + int italic; + int blink; + int reverse; + int strike; + int font; + VTermColor foreground; + VTermColor background; + } state_pen; + static int state_setpenattr(VTermAttr attr, VTermValue *val, void *user) + { + switch(attr) { + case VTERM_ATTR_BOLD: + state_pen.bold = val->boolean; + break; + case VTERM_ATTR_UNDERLINE: + state_pen.underline = val->number; + break; + case VTERM_ATTR_ITALIC: + state_pen.italic = val->boolean; + break; + case VTERM_ATTR_BLINK: + state_pen.blink = val->boolean; + break; + case VTERM_ATTR_REVERSE: + state_pen.reverse = val->boolean; + break; + case VTERM_ATTR_STRIKE: + state_pen.strike = val->boolean; + break; + case VTERM_ATTR_FONT: + state_pen.font = val->number; + break; + case VTERM_ATTR_FOREGROUND: + state_pen.foreground = val->color; + break; + case VTERM_ATTR_BACKGROUND: + state_pen.background = val->color; + break; + } + + return 1; + } + + static int state_setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) + { + return 1; + } + + VTermStateCallbacks state_cbs = { + state_putglyph, /* putglyph */ + movecursor, /* movecursor */ + scrollrect, /* scrollrect */ + moverect, /* moverect */ + state_erase, /* erase */ + NULL, /* initpen */ + state_setpenattr, /* setpenattr */ + settermprop, /* settermprop */ + NULL, /* bell */ + NULL, /* resize */ + state_setlineinfo, /* setlineinfo */ + }; + + static int want_screen_damage = 0; + static int want_screen_damage_cells = 0; + static int screen_damage(VTermRect rect, void *user) + { + if(!want_screen_damage) + return 1; + + printf("damage %d..%d,%d..%d", + rect.start_row, rect.end_row, rect.start_col, rect.end_col); + + if(want_screen_damage_cells) { + bool equals = false; + int row; + int col; + + for(row = rect.start_row; row < rect.end_row; row++) { + int eol = rect.end_col; + while(eol > rect.start_col) { + VTermScreenCell cell; + VTermPos pos; + pos.row = row; + pos.col = eol-1; + vterm_screen_get_cell(screen, pos, &cell); + if(cell.chars[0]) + break; + + eol--; + } + + if(eol == rect.start_col) + break; + + if(!equals) + printf(" ="), equals = true; + + printf(" %d<", row); + for(col = rect.start_col; col < eol; col++) { + VTermScreenCell cell; + VTermPos pos; + pos.row = row; + pos.col = col; + vterm_screen_get_cell(screen, pos, &cell); + printf(col == rect.start_col ? "%02X" : " %02X", cell.chars[0]); + } + printf(">"); + } + } + + printf("\n"); + + return 1; + } + + static int want_screen_scrollback = 0; + static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user) + { + int eol; + int c; + + if(!want_screen_scrollback) + return 1; + + eol = cols; + while(eol && !cells[eol-1].chars[0]) + eol--; + + printf("sb_pushline %d =", cols); + for(c = 0; c < eol; c++) + printf(" %02X", cells[c].chars[0]); + printf("\n"); + + return 1; + } + + static int screen_sb_popline(int cols, VTermScreenCell *cells, void *user) + { + int col; + + if(!want_screen_scrollback) + return 0; + + /* All lines of scrollback contain "ABCDE" */ + for(col = 0; col < cols; col++) { + if(col < 5) + cells[col].chars[0] = 'A' + col; + else + cells[col].chars[0] = 0; + + cells[col].width = 1; + } + + printf("sb_popline %d\n", cols); + return 1; + } + + VTermScreenCallbacks screen_cbs = { + screen_damage, /* damage */ + moverect, /* moverect */ + movecursor, /* movecursor */ + settermprop, /* settermprop */ + NULL, /* bell */ + NULL, /* resize */ + screen_sb_pushline, /* sb_pushline */ + screen_sb_popline /* sb_popline */ + }; + + int main(int argc, char **argv) + { + char line[1024] = {0}; + int flag; + + int err; + + setvbuf(stdout, NULL, _IONBF, 0); + + while(fgets(line, sizeof line, stdin)) { + char *nl; + size_t outlen; + err = 0; + + if((nl = strchr(line, '\n'))) + *nl = '\0'; + + if(streq(line, "INIT")) { + if(!vt) + vt = vterm_new(25, 80); + } + + else if(streq(line, "WANTPARSER")) { + vterm_parser_set_callbacks(vt, &parser_cbs, NULL); + } + + else if(strstartswith(line, "WANTSTATE") && (line[9] == '\0' || line[9] == ' ')) { + int i = 9; + int sense = 1; + if(!state) { + state = vterm_obtain_state(vt); + vterm_state_set_callbacks(state, &state_cbs, NULL); + vterm_state_set_bold_highbright(state, 1); + vterm_state_reset(state, 1); + } + + while(line[i] == ' ') + i++; + for( ; line[i]; i++) + switch(line[i]) { + case '+': + sense = 1; + break; + case '-': + sense = 0; + break; + case 'g': + want_state_putglyph = sense; + break; + case 's': + want_scrollrect = sense; + break; + case 'm': + want_moverect = sense; + break; + case 'e': + want_state_erase = sense; + break; + case 'p': + want_settermprop = sense; + break; + case 'f': + vterm_state_set_unrecognised_fallbacks(state, sense ? &parser_cbs : NULL, NULL); + break; + default: + fprintf(stderr, "Unrecognised WANTSTATE flag '%c'\n", line[i]); + } + } + + else if(strstartswith(line, "WANTSCREEN") && (line[10] == '\0' || line[10] == ' ')) { + int i = 10; + int sense = 1; + if(!screen) + screen = vterm_obtain_screen(vt); + vterm_screen_enable_altscreen(screen, 1); + vterm_screen_set_callbacks(screen, &screen_cbs, NULL); + + while(line[i] == ' ') + i++; + for( ; line[i]; i++) + switch(line[i]) { + case '-': + sense = 0; + break; + case 'd': + want_screen_damage = sense; + break; + case 'D': + want_screen_damage = sense; + want_screen_damage_cells = sense; + break; + case 'm': + want_moverect = sense; + break; + case 'c': + want_movecursor = sense; + break; + case 'p': + want_settermprop = 1; + break; + case 'b': + want_screen_scrollback = sense; + break; + default: + fprintf(stderr, "Unrecognised WANTSCREEN flag '%c'\n", line[i]); + } + } + + else if(sscanf(line, "UTF8 %d", &flag)) { + vterm_set_utf8(vt, flag); + } + + else if(streq(line, "RESET")) { + if(state) { + vterm_state_reset(state, 1); + vterm_state_get_cursorpos(state, &state_pos); + } + if(screen) { + vterm_screen_reset(screen, 1); + } + } + + else if(strstartswith(line, "RESIZE ")) { + int rows, cols; + char *linep = line + 7; + while(linep[0] == ' ') + linep++; + sscanf(linep, "%d, %d", &rows, &cols); + vterm_set_size(vt, rows, cols); + } + + else if(strstartswith(line, "PUSH ")) { + char *bytes = line + 5; + size_t len = inplace_hex2bytes(bytes); + size_t written = vterm_input_write(vt, bytes, len); + if(written < len) + fprintf(stderr, "! short write\n"); + } + + else if(streq(line, "WANTENCODING")) { + /* This isn't really external API but it's hard to get this out any + * other way + */ + encoding.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); + if(encoding.enc->init) + (*encoding.enc->init)(encoding.enc, encoding.data); + } + + else if(strstartswith(line, "ENCIN ")) { + char *bytes = line + 6; + size_t len = inplace_hex2bytes(bytes); + + uint32_t cp[1024]; + int cpi = 0; + size_t pos = 0; + + (*encoding.enc->decode)(encoding.enc, encoding.data, + cp, &cpi, len, bytes, &pos, len); + + if(cpi > 0) { + int i; + printf("encout "); + for(i = 0; i < cpi; i++) { + printf(i ? ",%x" : "%x", cp[i]); + } + printf("\n"); + } + } + + else if(strstartswith(line, "INCHAR ")) { + char *linep = line + 7; + unsigned int c = 0; + VTermModifier mod; + while(linep[0] == ' ') + linep++; + mod = strpe_modifiers(&linep); + sscanf(linep, " %x", &c); + + vterm_keyboard_unichar(vt, c, mod); + } + + else if(strstartswith(line, "INKEY ")) { + VTermModifier mod; + VTermKey key; + char *linep = line + 6; + while(linep[0] == ' ') + linep++; + mod = strpe_modifiers(&linep); + while(linep[0] == ' ') + linep++; + key = strp_key(linep); + + vterm_keyboard_key(vt, key, mod); + } + + else if(strstartswith(line, "PASTE ")) { + char *linep = line + 6; + if(streq(linep, "START")) + vterm_keyboard_start_paste(vt); + else if(streq(linep, "END")) + vterm_keyboard_end_paste(vt); + else + goto abort_line; + } + + else if(strstartswith(line, "MOUSEMOVE ")) { + char *linep = line + 10; + int row, col, len; + VTermModifier mod; + while(linep[0] == ' ') + linep++; + sscanf(linep, "%d,%d%n", &row, &col, &len); + linep += len; + while(linep[0] == ' ') + linep++; + mod = strpe_modifiers(&linep); + vterm_mouse_move(vt, row, col, mod); + } + + else if(strstartswith(line, "MOUSEBTN ")) { + char *linep = line + 9; + char press; + int button, len; + VTermModifier mod; + while(linep[0] == ' ') + linep++; + sscanf(linep, "%c %d%n", &press, &button, &len); + linep += len; + while(linep[0] == ' ') + linep++; + mod = strpe_modifiers(&linep); + vterm_mouse_button(vt, button, (press == 'd' || press == 'D'), mod); + } + + else if(strstartswith(line, "DAMAGEMERGE ")) { + char *linep = line + 12; + while(linep[0] == ' ') + linep++; + if(streq(linep, "CELL")) + vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_CELL); + else if(streq(linep, "ROW")) + vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_ROW); + else if(streq(linep, "SCREEN")) + vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_SCREEN); + else if(streq(linep, "SCROLL")) + vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_SCROLL); + } + + else if(strstartswith(line, "DAMAGEFLUSH")) { + vterm_screen_flush_damage(screen); + } + + else if(line[0] == '?') { + if(streq(line, "?cursor")) { + VTermPos pos; + vterm_state_get_cursorpos(state, &pos); + if(pos.row != state_pos.row) + printf("! row mismatch: state=%d,%d event=%d,%d\n", + pos.row, pos.col, state_pos.row, state_pos.col); + else if(pos.col != state_pos.col) + printf("! col mismatch: state=%d,%d event=%d,%d\n", + pos.row, pos.col, state_pos.row, state_pos.col); + else + printf("%d,%d\n", state_pos.row, state_pos.col); + } + else if(strstartswith(line, "?pen ")) { + VTermValue val; + char *linep = line + 5; + while(linep[0] == ' ') + linep++; + + #define BOOLSTR(v) ((v) ? "on" : "off") + + if(streq(linep, "bold")) { + vterm_state_get_penattr(state, VTERM_ATTR_BOLD, &val); + if(val.boolean != state_pen.bold) + printf("! pen bold mismatch; state=%s, event=%s\n", + BOOLSTR(val.boolean), BOOLSTR(state_pen.bold)); + else + printf("%s\n", BOOLSTR(state_pen.bold)); + } + else if(streq(linep, "underline")) { + vterm_state_get_penattr(state, VTERM_ATTR_UNDERLINE, &val); + if(val.boolean != state_pen.underline) + printf("! pen underline mismatch; state=%d, event=%d\n", + val.boolean, state_pen.underline); + else + printf("%d\n", state_pen.underline); + } + else if(streq(linep, "italic")) { + vterm_state_get_penattr(state, VTERM_ATTR_ITALIC, &val); + if(val.boolean != state_pen.italic) + printf("! pen italic mismatch; state=%s, event=%s\n", + BOOLSTR(val.boolean), BOOLSTR(state_pen.italic)); + else + printf("%s\n", BOOLSTR(state_pen.italic)); + } + else if(streq(linep, "blink")) { + vterm_state_get_penattr(state, VTERM_ATTR_BLINK, &val); + if(val.boolean != state_pen.blink) + printf("! pen blink mismatch; state=%s, event=%s\n", + BOOLSTR(val.boolean), BOOLSTR(state_pen.blink)); + else + printf("%s\n", BOOLSTR(state_pen.blink)); + } + else if(streq(linep, "reverse")) { + vterm_state_get_penattr(state, VTERM_ATTR_REVERSE, &val); + if(val.boolean != state_pen.reverse) + printf("! pen reverse mismatch; state=%s, event=%s\n", + BOOLSTR(val.boolean), BOOLSTR(state_pen.reverse)); + else + printf("%s\n", BOOLSTR(state_pen.reverse)); + } + else if(streq(linep, "font")) { + vterm_state_get_penattr(state, VTERM_ATTR_FONT, &val); + if(val.boolean != state_pen.font) + printf("! pen font mismatch; state=%d, event=%d\n", + val.boolean, state_pen.font); + else + printf("%d\n", state_pen.font); + } + else if(streq(linep, "foreground")) { + printf("rgb(%d,%d,%d)\n", state_pen.foreground.red, state_pen.foreground.green, state_pen.foreground.blue); + } + else if(streq(linep, "background")) { + printf("rgb(%d,%d,%d)\n", state_pen.background.red, state_pen.background.green, state_pen.background.blue); + } + else + printf("?\n"); + } + else if(strstartswith(line, "?screen_chars ")) { + char *linep = line + 13; + VTermRect rect; + size_t len; + while(linep[0] == ' ') + linep++; + if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) { + printf("! screen_chars unrecognised input\n"); + goto abort_line; + } + len = vterm_screen_get_chars(screen, NULL, 0, rect); + if(len == (size_t)-1) + printf("! screen_chars error\n"); + else if(len == 0) + printf("\n"); + else { + uint32_t *chars = malloc(sizeof(uint32_t) * len); + size_t i; + vterm_screen_get_chars(screen, chars, len, rect); + for(i = 0; i < len; i++) { + printf("0x%02x%s", chars[i], i < len-1 ? "," : "\n"); + } + free(chars); + } + } + else if(strstartswith(line, "?screen_text ")) { + char *linep = line + 12; + VTermRect rect; + size_t len; + while(linep[0] == ' ') + linep++; + if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) { + printf("! screen_text unrecognised input\n"); + goto abort_line; + } + len = vterm_screen_get_text(screen, NULL, 0, rect); + if(len == (size_t)-1) + printf("! screen_text error\n"); + else if(len == 0) + printf("\n"); + else { + /* Put an overwrite guard at both ends of the buffer */ + unsigned char *buffer = malloc(len + 4); + unsigned char *text = buffer + 2; + text[-2] = 0x55; text[-1] = 0xAA; + text[len] = 0x55; text[len+1] = 0xAA; + + vterm_screen_get_text(screen, (char *)text, len, rect); + + if(text[-2] != 0x55 || text[-1] != 0xAA) + printf("! screen_get_text buffer overrun left [%02x,%02x]\n", text[-2], text[-1]); + else if(text[len] != 0x55 || text[len+1] != 0xAA) + printf("! screen_get_text buffer overrun right [%02x,%02x]\n", text[len], text[len+1]); + else + { + size_t i; + for(i = 0; i < len; i++) { + printf("0x%02x%s", text[i], i < len-1 ? "," : "\n"); + } + } + + free(buffer); + } + } + else if(strstartswith(line, "?screen_cell ")) { + char *linep = line + 12; + int i; + VTermPos pos; + VTermScreenCell cell; + while(linep[0] == ' ') + linep++; + if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) { + printf("! screen_cell unrecognised input\n"); + goto abort_line; + } + if(!vterm_screen_get_cell(screen, pos, &cell)) + goto abort_line; + printf("{"); + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell.chars[i]; i++) { + printf("%s0x%x", i ? "," : "", cell.chars[i]); + } + printf("} width=%d attrs={", cell.width); + if(cell.attrs.bold) printf("B"); + if(cell.attrs.underline) printf("U%d", cell.attrs.underline); + if(cell.attrs.italic) printf("I"); + if(cell.attrs.blink) printf("K"); + if(cell.attrs.reverse) printf("R"); + if(cell.attrs.font) printf("F%d", cell.attrs.font); + printf("} "); + if(cell.attrs.dwl) printf("dwl "); + if(cell.attrs.dhl) printf("dhl-%s ", cell.attrs.dhl == 2 ? "bottom" : "top"); + printf("fg=rgb(%d,%d,%d) ", cell.fg.red, cell.fg.green, cell.fg.blue); + printf("bg=rgb(%d,%d,%d)\n", cell.bg.red, cell.bg.green, cell.bg.blue); + } + else if(strstartswith(line, "?screen_eol ")) { + VTermPos pos; + char *linep = line + 12; + while(linep[0] == ' ') + linep++; + if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) { + printf("! screen_eol unrecognised input\n"); + goto abort_line; + } + printf("%d\n", vterm_screen_is_eol(screen, pos)); + } + else if(strstartswith(line, "?screen_attrs_extent ")) { + VTermPos pos; + VTermRect rect; + char *linep = line + 21; + while(linep[0] == ' ') + linep++; + if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) { + printf("! screen_attrs_extent unrecognised input\n"); + goto abort_line; + } + rect.start_col = 0; + rect.end_col = -1; + if(!vterm_screen_get_attrs_extent(screen, &rect, pos, ~0)) { + printf("! screen_attrs_extent failed\n"); + goto abort_line; + } + printf("%d,%d-%d,%d\n", rect.start_row, rect.start_col, rect.end_row, rect.end_col); + } + else + printf("?\n"); + + memset(line, 0, sizeof line); + continue; + } + + else + abort_line: err = 1; + + outlen = vterm_output_get_buffer_current(vt); + if(outlen > 0) { + int i; + char outbuff[1024]; + vterm_output_read(vt, outbuff, outlen); + + printf("output "); + for(i = 0; i < outlen; i++) + printf("%x%s", (unsigned char)outbuff[i], i < outlen-1 ? "," : "\n"); + } + + printf(err ? "?\n" : "DONE\n"); + } + + vterm_free(vt); + + return 0; + } *** ../vim-8.0.0692/src/libvterm/t/run-test.pl 1970-01-01 01:00:00.000000000 +0100 --- src/libvterm/t/run-test.pl 2017-06-24 16:44:02.180324920 +0200 *************** *** 0 **** --- 1,196 ---- + #!/usr/bin/perl + + use strict; + use warnings; + use Getopt::Long; + use IO::Handle; + use IPC::Open2 qw( open2 ); + use POSIX qw( WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG ); + + my $VALGRIND = 0; + GetOptions( + 'valgrind|v+' => \$VALGRIND, + ) or exit 1; + + my ( $hin, $hout, $hpid ); + { + local $ENV{LD_LIBRARY_PATH} = ".libs"; + my @command = "t/.libs/harness"; + unshift @command, "valgrind", "--quiet", "--error-exitcode=126" if $VALGRIND; + + $hpid = open2 $hout, $hin, @command or die "Cannot open2 harness - $!"; + } + + my $exitcode = 0; + + my $command; + my @expect; + + sub do_onetest + { + $hin->print( "$command\n" ); + undef $command; + + my $fail_printed = 0; + + while( my $outline = <$hout> ) { + last if $outline eq "DONE\n" or $outline eq "?\n"; + + chomp $outline; + + if( !@expect ) { + print "# Test failed\n" unless $fail_printed++; + print "# expected nothing more\n" . + "# Actual: $outline\n"; + next; + } + + my $expectation = shift @expect; + + next if $expectation eq $outline; + + print "# Test failed\n" unless $fail_printed++; + print "# Expected: $expectation\n" . + "# Actual: $outline\n"; + } + + if( @expect ) { + print "# Test failed\n" unless $fail_printed++; + print "# Expected: $_\n" . + "# didn't happen\n" for @expect; + } + + $exitcode = 1 if $fail_printed; + } + + sub do_line + { + my ( $line ) = @_; + + if( $line =~ m/^!(.*)/ ) { + do_onetest if defined $command; + print "> $1\n"; + } + + # Commands have capitals + elsif( $line =~ m/^([A-Z]+)/ ) { + # Some convenience formatting + if( $line =~ m/^(PUSH|ENCIN) (.*)$/ ) { + # we're evil + my $string = eval($2); + $line = "$1 " . unpack "H*", $string; + } + + do_onetest if defined $command; + + $command = $line; + undef @expect; + } + # Expectations have lowercase + elsif( $line =~ m/^([a-z]+)/ ) { + # Convenience formatting + if( $line =~ m/^(text|encout) (.*)$/ ) { + $line = "$1 " . join ",", map sprintf("%x", $_), eval($2); + } + elsif( $line =~ m/^(output) (.*)$/ ) { + $line = "$1 " . join ",", map sprintf("%x", $_), unpack "C*", eval($2); + } + elsif( $line =~ m/^control (.*)$/ ) { + $line = sprintf "control %02x", eval($1); + } + elsif( $line =~ m/^csi (\S+) (.*)$/ ) { + $line = sprintf "csi %02x %s", eval($1), $2; # TODO + } + elsif( $line =~ m/^(escape|osc|dcs) (.*)$/ ) { + $line = "$1 " . join "", map sprintf("%02x", $_), unpack "C*", eval($2); + } + elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) { + $line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2"; + } + elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc) / ) { + # no conversion + } + else { + warn "Unrecognised test expectation '$line'\n"; + } + + push @expect, $line; + } + # ?screen_row assertion is emulated here + elsif( $line =~ s/^\?screen_row\s+(\d+)\s*=\s*// ) { + my $row = $1; + my $row1 = $row + 1; + my $want = eval($line); + + do_onetest if defined $command; + + # TODO: may not be 80 + $hin->print( "\?screen_chars $row,0,$row1,80\n" ); + my $response = <$hout>; + chomp $response; + + $response = pack "C*", map hex, split m/,/, $response; + if( $response ne $want ) { + print "# Assert ?screen_row $row failed:\n" . + "# Expected: $want\n" . + "# Actual: $response\n"; + $exitcode = 1; + } + } + # Assertions start with '?' + elsif( $line =~ s/^\?([a-z]+.*?=)\s+// ) { + do_onetest if defined $command; + + my ( $assertion ) = $1 =~ m/^(.*)\s+=/; + + $hin->print( "\?$assertion\n" ); + my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n"; + chomp $response; + + if( $response ne $line ) { + print "# Assert $assertion failed:\n" . + "# Expected: $line\n" . + "# Actual: $response\n"; + $exitcode = 1; + } + } + # Test controls start with '$' + elsif( $line =~ s/\$SEQ\s+(\d+)\s+(\d+):\s*// ) { + my ( $low, $high ) = ( $1, $2 ); + foreach my $val ( $low .. $high ) { + ( my $inner = $line ) =~ s/\\#/$val/g; + do_line( $inner ); + } + } + elsif( $line =~ s/\$REP\s+(\d+):\s*// ) { + my $count = $1; + do_line( $line ) for 1 .. $count; + } + else { + die "Unrecognised TEST line $line\n"; + } + } + + open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!"; + + while( my $line = <$test> ) { + $line =~ s/^\s+//; + next if $line =~ m/^(?:#|$)/; + + chomp $line; + do_line( $line ); + } + + do_onetest if defined $command; + + close $hin; + close $hout; + + waitpid $hpid, 0; + if( $? ) { + printf STDERR "Harness exited %d\n", WEXITSTATUS($?) if WIFEXITED($?); + printf STDERR "Harness exit signal %d\n", WTERMSIG($?) if WIFSIGNALED($?); + $exitcode = WIFEXITED($?) ? WEXITSTATUS($?) : 125; + } + + exit $exitcode; *** ../vim-8.0.0692/src/version.c 2017-07-01 23:11:11.127835714 +0200 --- src/version.c 2017-07-07 11:49:30.685718455 +0200 *************** *** 766,767 **** --- 766,769 ---- { /* Add new patch number below this line */ + /**/ + 693, /**/ -- hundred-and-one symptoms of being an internet addict: 116. You are living with your boyfriend who networks your respective computers so you can sit in separate rooms and email each other /// 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 ///