forked from aniani/vim
		
	patch 8.1.2027: MS-Windows: problem with ambiwidth characters
Problem:    MS-Windows: problem with ambiwidth characters.
Solution:   handle ambiguous width characters in ConPTY on Windows 10 (1903).
            (Nobuhiro Takasaki, closes #4411)
			
			
This commit is contained in:
		| @@ -1192,7 +1192,8 @@ $(OUTDIR)/pathdef.o:	$(PATHDEF_SRC) $(INCL) | |||||||
| CCCTERM = $(CC) -c $(CFLAGS) -Ilibvterm/include -DINLINE="" \ | CCCTERM = $(CC) -c $(CFLAGS) -Ilibvterm/include -DINLINE="" \ | ||||||
| 	  -DVSNPRINTF=vim_vsnprintf \ | 	  -DVSNPRINTF=vim_vsnprintf \ | ||||||
| 	  -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ | 	  -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ | ||||||
| 	  -DWCWIDTH_FUNCTION=utf_uint2cells | 	  -DWCWIDTH_FUNCTION=utf_uint2cells \ | ||||||
|  | 	  -DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type | ||||||
|  |  | ||||||
| $(OUTDIR)/%.o : libvterm/src/%.c $(TERM_DEPS) | $(OUTDIR)/%.o : libvterm/src/%.c $(TERM_DEPS) | ||||||
| 	$(CCCTERM) $< -o $@ | 	$(CCCTERM) $< -o $@ | ||||||
|   | |||||||
| @@ -1716,6 +1716,7 @@ CCCTERM = $(CC) $(CFLAGS) -Ilibvterm/include -DINLINE="" \ | |||||||
| 	-DVSNPRINTF=vim_vsnprintf \ | 	-DVSNPRINTF=vim_vsnprintf \ | ||||||
| 	-DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ | 	-DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ | ||||||
| 	-DWCWIDTH_FUNCTION=utf_uint2cells \ | 	-DWCWIDTH_FUNCTION=utf_uint2cells \ | ||||||
|  | 	-DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type \ | ||||||
| 	-D_CRT_SECURE_NO_WARNINGS | 	-D_CRT_SECURE_NO_WARNINGS | ||||||
|  |  | ||||||
| # Create a default rule for libvterm. | # Create a default rule for libvterm. | ||||||
|   | |||||||
| @@ -127,6 +127,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) | |||||||
|   size_t pos = 0; |   size_t pos = 0; | ||||||
|   const char *string_start = NULL;  // init to avoid gcc warning |   const char *string_start = NULL;  // init to avoid gcc warning | ||||||
|  |  | ||||||
|  |   vt->in_backspace = 0;		    // Count down with BS key and activate when | ||||||
|  | 				    // it reaches 1 | ||||||
|  |  | ||||||
|   switch(vt->parser.state) { |   switch(vt->parser.state) { | ||||||
|   case NORMAL: |   case NORMAL: | ||||||
|   case CSI_LEADER: |   case CSI_LEADER: | ||||||
| @@ -172,6 +175,13 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) | |||||||
|       // fallthrough |       // fallthrough | ||||||
|     } |     } | ||||||
|     else if(c < 0x20) { // other C0 |     else if(c < 0x20) { // other C0 | ||||||
|  |       if(vterm_get_special_pty_type() == 2) { | ||||||
|  |         if(c == 0x08) // BS | ||||||
|  |           // Set the trick for BS output after a sequence, to delay backspace | ||||||
|  |           // activation | ||||||
|  |           if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08) | ||||||
|  |             vt->in_backspace = 2; // Trigger when count down to 1 | ||||||
|  |       } | ||||||
|       if(vt->parser.state >= STRING) |       if(vt->parser.state >= STRING) | ||||||
|         more_string(vt, string_start, bytes + pos - string_start); |         more_string(vt, string_start, bytes + pos - string_start); | ||||||
|       do_control(vt, c); |       do_control(vt, c); | ||||||
|   | |||||||
| @@ -336,6 +336,11 @@ static int on_text(const char bytes[], size_t len, void *user) | |||||||
|  |  | ||||||
|     for( ; i < glyph_ends; i++) { |     for( ; i < glyph_ends; i++) { | ||||||
|       int this_width; |       int this_width; | ||||||
|  |       if(vterm_get_special_pty_type() == 2) { | ||||||
|  |         state->vt->in_backspace -= (state->vt->in_backspace > 0) ? 1 : 0; | ||||||
|  |         if(state->vt->in_backspace == 1) | ||||||
|  |           codepoints[i] = 0; // codepoints under this condition must be 0 | ||||||
|  |       } | ||||||
|       chars[i - glyph_starts] = codepoints[i]; |       chars[i - glyph_starts] = codepoints[i]; | ||||||
|       this_width = vterm_unicode_width(codepoints[i]); |       this_width = vterm_unicode_width(codepoints[i]); | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
| @@ -425,6 +430,12 @@ static int on_control(unsigned char control, void *user) | |||||||
|  |  | ||||||
|   VTermPos oldpos = state->pos; |   VTermPos oldpos = state->pos; | ||||||
|  |  | ||||||
|  |   VTermScreenCell cell; | ||||||
|  |  | ||||||
|  |   // Preparing to see the leading byte | ||||||
|  |   VTermPos leadpos = state->pos; | ||||||
|  |   leadpos.col -= (leadpos.col >= 2 ? 2 : 0); | ||||||
|  |  | ||||||
|   switch(control) { |   switch(control) { | ||||||
|   case 0x07: // BEL - ECMA-48 8.3.3 |   case 0x07: // BEL - ECMA-48 8.3.3 | ||||||
|     if(state->callbacks && state->callbacks->bell) |     if(state->callbacks && state->callbacks->bell) | ||||||
| @@ -434,6 +445,12 @@ static int on_control(unsigned char control, void *user) | |||||||
|   case 0x08: // BS - ECMA-48 8.3.5 |   case 0x08: // BS - ECMA-48 8.3.5 | ||||||
|     if(state->pos.col > 0) |     if(state->pos.col > 0) | ||||||
|       state->pos.col--; |       state->pos.col--; | ||||||
|  |     if(vterm_get_special_pty_type() == 2) { | ||||||
|  |       // In 2 cell letters, go back 2 cells | ||||||
|  |       vterm_screen_get_cell(state->vt->screen, leadpos, &cell); | ||||||
|  |       if(vterm_unicode_width(cell.chars[0]) == 2) | ||||||
|  |         state->pos.col--; | ||||||
|  |     } | ||||||
|     break; |     break; | ||||||
|  |  | ||||||
|   case 0x09: // HT - ECMA-48 8.3.60 |   case 0x09: // HT - ECMA-48 8.3.60 | ||||||
| @@ -1019,6 +1036,26 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha | |||||||
|     row = CSI_ARG_OR(args[0], 1); |     row = CSI_ARG_OR(args[0], 1); | ||||||
|     col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); |     col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); | ||||||
|     // zero-based |     // zero-based | ||||||
|  |     if(vterm_get_special_pty_type() == 2) { | ||||||
|  |       // Fix a sequence that is not correct right now | ||||||
|  |       if(state->pos.row == row - 1) { | ||||||
|  |         int cnt, ptr = 0; | ||||||
|  |         for(cnt = 0; cnt < col - 1; ++cnt) { | ||||||
|  | 	  VTermPos p; | ||||||
|  | 	  VTermScreenCell c0, c1; | ||||||
|  | 	  p.row = row - 1; | ||||||
|  | 	  p.col = ptr; | ||||||
|  | 	  vterm_screen_get_cell(state->vt->screen, p, &c0); | ||||||
|  | 	  p.col++; | ||||||
|  | 	  vterm_screen_get_cell(state->vt->screen, p, &c1); | ||||||
|  | 	  ptr += (c1.chars[0] == (uint32_t)-1)		    // double cell? | ||||||
|  | 	     ? (vterm_unicode_is_ambiguous(c0.chars[0]))    // is ambiguous? | ||||||
|  | 	     ? vterm_unicode_width(0x00a1) : 1		    // &ambiwidth | ||||||
|  | 	     : 1;					    // not ambiguous | ||||||
|  |         } | ||||||
|  |         col = ptr + 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|     state->pos.row = row-1; |     state->pos.row = row-1; | ||||||
|     state->pos.col = col-1; |     state->pos.col = col-1; | ||||||
|     if(state->mode.origin) { |     if(state->mode.origin) { | ||||||
|   | |||||||
| @@ -770,11 +770,28 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe | |||||||
|   cell->fg = intcell->pen.fg; |   cell->fg = intcell->pen.fg; | ||||||
|   cell->bg = intcell->pen.bg; |   cell->bg = intcell->pen.bg; | ||||||
|  |  | ||||||
|  |   if(vterm_get_special_pty_type() == 2) { | ||||||
|  |     /* Get correct cell width from cell information contained in line buffer */ | ||||||
|  |     if(pos.col < (screen->cols - 1) && | ||||||
|  |        getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1) { | ||||||
|  |       if(getcell(screen, pos.row, pos.col)->chars[0] == 0x20) { | ||||||
|  |         getcell(screen, pos.row, pos.col)->chars[0] = 0; | ||||||
|  |         cell->width = 2; | ||||||
|  |       } else if(getcell(screen, pos.row, pos.col)->chars[0] == 0) { | ||||||
|  |         getcell(screen, pos.row, pos.col + 1)->chars[0] = 0; | ||||||
|  |         cell->width = 1; | ||||||
|  |       } else { | ||||||
|  |         cell->width = 2; | ||||||
|  |       } | ||||||
|  |     } else | ||||||
|  |       cell->width = 1; | ||||||
|  |   } else { | ||||||
|     if(pos.col < (screen->cols - 1) && |     if(pos.col < (screen->cols - 1) && | ||||||
|        getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1) |        getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1) | ||||||
|       cell->width = 2; |       cell->width = 2; | ||||||
|     else |     else | ||||||
|       cell->width = 1; |       cell->width = 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   return 1; |   return 1; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -68,12 +68,13 @@ | |||||||
|  * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c |  * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #if !defined(IS_COMBINING_FUNCTION) || !defined(WCWIDTH_FUNCTION) |  | ||||||
| struct interval { | struct interval { | ||||||
|   int first; |   int first; | ||||||
|   int last; |   int last; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #if !defined(WCWIDTH_FUNCTION) || !defined(IS_COMBINING_FUNCTION) | ||||||
|  |  | ||||||
| // sorted list of non-overlapping intervals of non-spacing characters | // sorted list of non-overlapping intervals of non-spacing characters | ||||||
| // generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" | // generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" | ||||||
| // Replaced by the combining table from Vim. | // Replaced by the combining table from Vim. | ||||||
| @@ -359,6 +360,7 @@ static const struct interval combining[] = { | |||||||
| 	{0X1E944, 0X1E94A}, | 	{0X1E944, 0X1E94A}, | ||||||
| 	{0XE0100, 0XE01EF} | 	{0XE0100, 0XE01EF} | ||||||
| }; | }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
| // auxiliary function for binary search in interval table | // auxiliary function for binary search in interval table | ||||||
| static int bisearch(uint32_t ucs, const struct interval *table, int max) { | static int bisearch(uint32_t ucs, const struct interval *table, int max) { | ||||||
| @@ -379,8 +381,6 @@ static int bisearch(uint32_t ucs, const struct interval *table, int max) { | |||||||
|  |  | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* The following two functions define the column width of an ISO 10646 | /* The following two functions define the column width of an ISO 10646 | ||||||
|  * character as follows: |  * character as follows: | ||||||
| @@ -478,6 +478,7 @@ static int mk_wcswidth(const uint32_t *pwcs, size_t n) | |||||||
|  */ |  */ | ||||||
| static int mk_wcwidth_cjk(uint32_t ucs) | static int mk_wcwidth_cjk(uint32_t ucs) | ||||||
| { | { | ||||||
|  | #endif | ||||||
|   /* sorted list of non-overlapping intervals of East Asian Ambiguous |   /* sorted list of non-overlapping intervals of East Asian Ambiguous | ||||||
|    * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ |    * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ | ||||||
|   static const struct interval ambiguous[] = { |   static const struct interval ambiguous[] = { | ||||||
| @@ -534,6 +535,7 @@ static int mk_wcwidth_cjk(uint32_t ucs) | |||||||
|     { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, |     { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, | ||||||
|     { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } |     { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } | ||||||
|   }; |   }; | ||||||
|  | #if 0 | ||||||
|  |  | ||||||
|   // binary search in table of non-spacing characters |   // binary search in table of non-spacing characters | ||||||
|   if (bisearch(ucs, ambiguous, |   if (bisearch(ucs, ambiguous, | ||||||
| @@ -557,6 +559,12 @@ static int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n) | |||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | INTERNAL int vterm_unicode_is_ambiguous(uint32_t codepoint) | ||||||
|  | { | ||||||
|  |   return (bisearch(codepoint, ambiguous, | ||||||
|  |                sizeof(ambiguous) / sizeof(struct interval) - 1)) ? 1 : 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| #ifdef IS_COMBINING_FUNCTION | #ifdef IS_COMBINING_FUNCTION | ||||||
| // Use a provided is_combining() function. | // Use a provided is_combining() function. | ||||||
| int IS_COMBINING_FUNCTION(uint32_t codepoint); | int IS_COMBINING_FUNCTION(uint32_t codepoint); | ||||||
| @@ -569,6 +577,17 @@ vterm_is_combining(uint32_t codepoint) | |||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef GET_SPECIAL_PTY_TYPE_FUNCTION | ||||||
|  | int GET_SPECIAL_PTY_TYPE_FUNCTION(void); | ||||||
|  | #else | ||||||
|  | # define GET_SPECIAL_PTY_TYPE_FUNCTION vterm_get_special_pty_type_placeholder | ||||||
|  | 	static int | ||||||
|  | vterm_get_special_pty_type_placeholder(void) | ||||||
|  | { | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| // ################################ | // ################################ | ||||||
| // ### The rest added by Paul Evans | // ### The rest added by Paul Evans | ||||||
|  |  | ||||||
| @@ -581,3 +600,8 @@ INTERNAL int vterm_unicode_is_combining(uint32_t codepoint) | |||||||
| { | { | ||||||
|   return IS_COMBINING_FUNCTION(codepoint); |   return IS_COMBINING_FUNCTION(codepoint); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | INTERNAL int vterm_get_special_pty_type(void) | ||||||
|  | { | ||||||
|  |   return GET_SPECIAL_PTY_TYPE_FUNCTION(); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -212,6 +212,8 @@ struct VTerm | |||||||
|  |  | ||||||
|   VTermState *state; |   VTermState *state; | ||||||
|   VTermScreen *screen; |   VTermScreen *screen; | ||||||
|  |  | ||||||
|  |   int in_backspace; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct VTermEncoding { | struct VTermEncoding { | ||||||
| @@ -259,5 +261,7 @@ VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation); | |||||||
|  |  | ||||||
| int vterm_unicode_width(uint32_t codepoint); | int vterm_unicode_width(uint32_t codepoint); | ||||||
| int vterm_unicode_is_combining(uint32_t codepoint); | int vterm_unicode_is_combining(uint32_t codepoint); | ||||||
|  | int vterm_unicode_is_ambiguous(uint32_t codepoint); | ||||||
|  | int vterm_get_special_pty_type(void); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								src/misc2.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/misc2.c
									
									
									
									
									
								
							| @@ -4601,3 +4601,22 @@ build_argv_from_list(list_T *l, char ***argv, int *argc) | |||||||
| } | } | ||||||
| # endif | # endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Change the behavior of vterm. | ||||||
|  |  * 0: As usual. | ||||||
|  |  * 1: Windows 10 version 1809 | ||||||
|  |  *      The bug causes unstable handling of ambiguous width character. | ||||||
|  |  * 2: Windows 10 version 1903 | ||||||
|  |  *      Use the wrong result because each result is different. | ||||||
|  |  * 3: Windows 10 insider preview (current latest logic) | ||||||
|  |  */ | ||||||
|  |     int | ||||||
|  | get_special_pty_type(void) | ||||||
|  | { | ||||||
|  | #ifdef MSWIN | ||||||
|  |     return get_conpty_type(); | ||||||
|  | #else | ||||||
|  |     return 0; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|   | |||||||
| @@ -186,6 +186,7 @@ static int win32_setattrs(char_u *name, int attrs); | |||||||
| static int win32_set_archive(char_u *name); | static int win32_set_archive(char_u *name); | ||||||
|  |  | ||||||
| static int conpty_working = 0; | static int conpty_working = 0; | ||||||
|  | static int conpty_type = 0; | ||||||
| static int conpty_stable = 0; | static int conpty_stable = 0; | ||||||
| static void vtp_flag_init(); | static void vtp_flag_init(); | ||||||
|  |  | ||||||
| @@ -7249,9 +7250,25 @@ mch_setenv(char *var, char *value, int x) | |||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Support for pseudo-console (ConPTY) was added in windows 10 |  * Support for pseudo-console (ConPTY) was added in windows 10 | ||||||
|  * version 1809 (October 2018 update).  However, that version is unstable. |  * version 1809 (October 2018 update). | ||||||
|  */ |  */ | ||||||
| #define CONPTY_FIRST_SUPPORT_BUILD  MAKE_VER(10, 0, 17763) | #define CONPTY_FIRST_SUPPORT_BUILD  MAKE_VER(10, 0, 17763) | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * ConPTY differences between versions, need different logic. | ||||||
|  |  * version 1903 (May 2019 update). | ||||||
|  |  */ | ||||||
|  | #define CONPTY_1903_BUILD	    MAKE_VER(10, 0, 18362) | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Confirm until this version.  Also the logic changes. | ||||||
|  |  * insider preview. | ||||||
|  |  */ | ||||||
|  | #define CONPTY_INSIDER_BUILD	    MAKE_VER(10, 0, 18898) | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Not stable now. | ||||||
|  |  */ | ||||||
| #define CONPTY_STABLE_BUILD	    MAKE_VER(10, 0, 32767)  // T.B.D. | #define CONPTY_STABLE_BUILD	    MAKE_VER(10, 0, 32767)  // T.B.D. | ||||||
|  |  | ||||||
|     static void |     static void | ||||||
| @@ -7281,6 +7298,12 @@ vtp_flag_init(void) | |||||||
|     if (ver >= CONPTY_STABLE_BUILD) |     if (ver >= CONPTY_STABLE_BUILD) | ||||||
| 	conpty_stable = 1; | 	conpty_stable = 1; | ||||||
|  |  | ||||||
|  |     if (ver <= CONPTY_INSIDER_BUILD) | ||||||
|  | 	conpty_type = 3; | ||||||
|  |     if (ver <= CONPTY_1903_BUILD) | ||||||
|  | 	conpty_type = 2; | ||||||
|  |     if (ver < CONPTY_FIRST_SUPPORT_BUILD) | ||||||
|  | 	conpty_type = 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) || defined(PROTO) | #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) || defined(PROTO) | ||||||
| @@ -7502,6 +7525,12 @@ has_conpty_working(void) | |||||||
|     return conpty_working; |     return conpty_working; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |     int | ||||||
|  | get_conpty_type(void) | ||||||
|  | { | ||||||
|  |     return conpty_type; | ||||||
|  | } | ||||||
|  |  | ||||||
|     int |     int | ||||||
| is_conpty_stable(void) | is_conpty_stable(void) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -106,4 +106,5 @@ void parse_queued_messages(void); | |||||||
| int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc); | int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc); | ||||||
| int build_argv_from_string(char_u *cmd, char ***argv, int *argc); | int build_argv_from_string(char_u *cmd, char ***argv, int *argc); | ||||||
| int build_argv_from_list(list_T *l, char ***argv, int *argc); | int build_argv_from_list(list_T *l, char ***argv, int *argc); | ||||||
|  | int get_special_pty_type(void); | ||||||
| /* vim: set ft=c : */ | /* vim: set ft=c : */ | ||||||
|   | |||||||
| @@ -76,6 +76,7 @@ int use_vtp(void); | |||||||
| int is_term_win32(void); | int is_term_win32(void); | ||||||
| int has_vtp_working(void); | int has_vtp_working(void); | ||||||
| int has_conpty_working(void); | int has_conpty_working(void); | ||||||
|  | int get_conpty_type(void); | ||||||
| int is_conpty_stable(void); | int is_conpty_stable(void); | ||||||
| void resize_console_buf(void); | void resize_console_buf(void); | ||||||
| /* vim: set ft=c : */ | /* vim: set ft=c : */ | ||||||
|   | |||||||
| @@ -757,6 +757,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     2027, | ||||||
| /**/ | /**/ | ||||||
|     2026, |     2026, | ||||||
| /**/ | /**/ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user