mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Support for extended underline styles, enabled by adding the Smulx
capability with terminal-overrides (add something like 'vte*:Smulx=\E[4\:%p1%dm'). GitHub issue 1492.
This commit is contained in:
		
							
								
								
									
										56
									
								
								attributes.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								attributes.c
									
									
									
									
									
								
							| @@ -25,13 +25,13 @@ | ||||
| const char * | ||||
| attributes_tostring(int attr) | ||||
| { | ||||
| 	static char	buf[128]; | ||||
| 	static char	buf[512]; | ||||
| 	size_t		len; | ||||
|  | ||||
| 	if (attr == 0) | ||||
| 		return ("none"); | ||||
|  | ||||
| 	len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s", | ||||
| 	len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s", | ||||
| 	    (attr & GRID_ATTR_BRIGHT) ? "bright," : "", | ||||
| 	    (attr & GRID_ATTR_DIM) ? "dim," : "", | ||||
| 	    (attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "", | ||||
| @@ -39,7 +39,11 @@ attributes_tostring(int attr) | ||||
| 	    (attr & GRID_ATTR_REVERSE) ? "reverse," : "", | ||||
| 	    (attr & GRID_ATTR_HIDDEN) ? "hidden," : "", | ||||
| 	    (attr & GRID_ATTR_ITALICS) ? "italics," : "", | ||||
| 	    (attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : ""); | ||||
| 	    (attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "", | ||||
| 	    (attr & GRID_ATTR_UNDERSCORE_2) ? "double-underscore," : "", | ||||
| 	    (attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "", | ||||
| 	    (attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "", | ||||
| 	    (attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : ""); | ||||
| 	if (len > 0) | ||||
| 		buf[len - 1] = '\0'; | ||||
|  | ||||
| @@ -52,6 +56,25 @@ attributes_fromstring(const char *str) | ||||
| 	const char	delimiters[] = " ,|"; | ||||
| 	int		attr; | ||||
| 	size_t		end; | ||||
| 	u_int		i; | ||||
| 	struct { | ||||
| 		const char*	name; | ||||
| 		int		attr; | ||||
| 	} table[] = { | ||||
| 		{ "bright", GRID_ATTR_BRIGHT }, | ||||
| 		{ "bold", GRID_ATTR_BRIGHT }, | ||||
| 		{ "dim", GRID_ATTR_DIM }, | ||||
| 		{ "underscore", GRID_ATTR_UNDERSCORE }, | ||||
| 		{ "blink", GRID_ATTR_BLINK }, | ||||
| 		{ "reverse", GRID_ATTR_REVERSE }, | ||||
| 		{ "hidden", GRID_ATTR_HIDDEN }, | ||||
| 		{ "italics", GRID_ATTR_ITALICS }, | ||||
| 		{ "strikethrough", GRID_ATTR_STRIKETHROUGH }, | ||||
| 		{ "double-underscore", GRID_ATTR_UNDERSCORE_2 }, | ||||
| 		{ "curly-underscore", GRID_ATTR_UNDERSCORE_3 }, | ||||
| 		{ "dotted-underscore", GRID_ATTR_UNDERSCORE_4 }, | ||||
| 		{ "dashed-underscore", GRID_ATTR_UNDERSCORE_5 } | ||||
| 	}; | ||||
|  | ||||
| 	if (*str == '\0' || strcspn(str, delimiters) == 0) | ||||
| 		return (-1); | ||||
| @@ -64,24 +87,15 @@ attributes_fromstring(const char *str) | ||||
| 	attr = 0; | ||||
| 	do { | ||||
| 		end = strcspn(str, delimiters); | ||||
| 		if ((end == 6 && strncasecmp(str, "bright", end) == 0) || | ||||
| 		    (end == 4 && strncasecmp(str, "bold", end) == 0)) | ||||
| 			attr |= GRID_ATTR_BRIGHT; | ||||
| 		else if (end == 3 && strncasecmp(str, "dim", end) == 0) | ||||
| 			attr |= GRID_ATTR_DIM; | ||||
| 		else if (end == 10 && strncasecmp(str, "underscore", end) == 0) | ||||
| 			attr |= GRID_ATTR_UNDERSCORE; | ||||
| 		else if (end == 5 && strncasecmp(str, "blink", end) == 0) | ||||
| 			attr |= GRID_ATTR_BLINK; | ||||
| 		else if (end == 7 && strncasecmp(str, "reverse", end) == 0) | ||||
| 			attr |= GRID_ATTR_REVERSE; | ||||
| 		else if (end == 6 && strncasecmp(str, "hidden", end) == 0) | ||||
| 			attr |= GRID_ATTR_HIDDEN; | ||||
| 		else if (end == 7 && strncasecmp(str, "italics", end) == 0) | ||||
| 			attr |= GRID_ATTR_ITALICS; | ||||
| 		else if (end == 13 && strncasecmp(str, "strikethrough", end) == 0) | ||||
| 			attr |= GRID_ATTR_STRIKETHROUGH; | ||||
| 		else | ||||
| 		for (i = 0; i < nitems(table); i++) { | ||||
| 			if (end != strlen(table[i].name)) | ||||
| 				continue; | ||||
| 			if (strncasecmp(str, table[i].name, end) == 0) { | ||||
| 				attr |= table[i].attr; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if (i == nitems(table)) | ||||
| 			return (-1); | ||||
| 		str += end + strspn(str + end, delimiters); | ||||
| 	} while (*str != '\0'); | ||||
|   | ||||
							
								
								
									
										16
									
								
								grid.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								grid.c
									
									
									
									
									
								
							| @@ -764,7 +764,11 @@ grid_string_cells_code(const struct grid_cell *lastgc, | ||||
| 		{ GRID_ATTR_BLINK, 5 }, | ||||
| 		{ GRID_ATTR_REVERSE, 7 }, | ||||
| 		{ GRID_ATTR_HIDDEN, 8 }, | ||||
| 		{ GRID_ATTR_STRIKETHROUGH, 9 } | ||||
| 		{ GRID_ATTR_STRIKETHROUGH, 9 }, | ||||
| 		{ GRID_ATTR_UNDERSCORE_2, 42 }, | ||||
| 		{ GRID_ATTR_UNDERSCORE_3, 43 }, | ||||
| 		{ GRID_ATTR_UNDERSCORE_4, 44 }, | ||||
| 		{ GRID_ATTR_UNDERSCORE_5, 45 }, | ||||
| 	}; | ||||
| 	n = 0; | ||||
|  | ||||
| @@ -790,11 +794,15 @@ grid_string_cells_code(const struct grid_cell *lastgc, | ||||
| 		else | ||||
| 			strlcat(buf, "\033[", len); | ||||
| 		for (i = 0; i < n; i++) { | ||||
| 			if (i + 1 < n) | ||||
| 				xsnprintf(tmp, sizeof tmp, "%d;", s[i]); | ||||
| 			else | ||||
| 			if (s[i] < 10) | ||||
| 				xsnprintf(tmp, sizeof tmp, "%d", s[i]); | ||||
| 			else { | ||||
| 				xsnprintf(tmp, sizeof tmp, "%d:%d", s[i] / 10, | ||||
| 				    s[i] % 10); | ||||
| 			} | ||||
| 			strlcat(buf, tmp, len); | ||||
| 			if (i + 1 < n) | ||||
| 				strlcat(buf, ";", len); | ||||
| 		} | ||||
| 		strlcat(buf, "m", len); | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										38
									
								
								input.c
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								input.c
									
									
									
									
									
								
							| @@ -1835,6 +1835,7 @@ input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i) | ||||
| static void | ||||
| input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i) | ||||
| { | ||||
| 	struct grid_cell	*gc = &ictx->cell.cell; | ||||
| 	char			*s = ictx->param_list[i].str, *copy, *ptr, *out; | ||||
| 	int			 p[8]; | ||||
| 	u_int			 n; | ||||
| @@ -1857,7 +1858,39 @@ input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i) | ||||
| 	} | ||||
| 	free(copy); | ||||
|  | ||||
| 	if (n == 0 || (p[0] != 38 && p[0] != 48)) | ||||
| 	if (n == 0) | ||||
| 		return; | ||||
| 	if (p[0] == 4) { | ||||
| 		if (n != 2) | ||||
| 			return; | ||||
| 		switch (p[1]) { | ||||
| 		case 0: | ||||
| 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; | ||||
| 			break; | ||||
| 		case 1: | ||||
| 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; | ||||
| 			gc->attr |= GRID_ATTR_UNDERSCORE; | ||||
| 			break; | ||||
| 		case 2: | ||||
| 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; | ||||
| 			gc->attr |= GRID_ATTR_UNDERSCORE_2; | ||||
| 			break; | ||||
| 		case 3: | ||||
| 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; | ||||
| 			gc->attr |= GRID_ATTR_UNDERSCORE_3; | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; | ||||
| 			gc->attr |= GRID_ATTR_UNDERSCORE_4; | ||||
| 			break; | ||||
| 		case 5: | ||||
| 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; | ||||
| 			gc->attr |= GRID_ATTR_UNDERSCORE_5; | ||||
| 			break; | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 	if (p[0] != 38 && p[0] != 48) | ||||
| 		return; | ||||
| 	if (p[1] == -1) | ||||
| 		i = 2; | ||||
| @@ -1927,6 +1960,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) | ||||
| 			gc->attr |= GRID_ATTR_ITALICS; | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; | ||||
| 			gc->attr |= GRID_ATTR_UNDERSCORE; | ||||
| 			break; | ||||
| 		case 5: | ||||
| @@ -1948,7 +1982,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) | ||||
| 			gc->attr &= ~GRID_ATTR_ITALICS; | ||||
| 			break; | ||||
| 		case 24: | ||||
| 			gc->attr &= ~GRID_ATTR_UNDERSCORE; | ||||
| 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; | ||||
| 			break; | ||||
| 		case 25: | ||||
| 			gc->attr &= ~GRID_ATTR_BLINK; | ||||
|   | ||||
							
								
								
									
										11
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								tmux.1
									
									
									
									
									
								
							| @@ -2857,8 +2857,12 @@ or a comma-delimited list of one or more of: | ||||
| .Ic reverse , | ||||
| .Ic hidden , | ||||
| .Ic italics , | ||||
| .Ic strikethrough , | ||||
| .Ic double-underscore | ||||
| .Ic curly-underscore | ||||
| .Ic dotted-underscore | ||||
| or | ||||
| .Ic strikethrough | ||||
| .Ic dashed-underscore | ||||
| to turn an attribute on, or an attribute prefixed with | ||||
| .Ql no | ||||
| to turn one off. | ||||
| @@ -4525,6 +4529,11 @@ to change the cursor colour from inside | ||||
| .Bd -literal -offset indent | ||||
| $ printf '\e033]12;red\e033\e\e' | ||||
| .Ed | ||||
| .It Em \&Smulx | ||||
| Set a styled underline. | ||||
| The single parameter is one of: 0 for no underline, 1 for normal | ||||
| underline, 2 for double underline, 3 for curly underline, 4 for dotted | ||||
| underline and 5 for dashed underline. | ||||
| .It Em \&Ss , Se | ||||
| Set or reset the cursor style. | ||||
| If set, a sequence such as this may be used | ||||
|   | ||||
							
								
								
									
										13
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -429,6 +429,7 @@ enum tty_code_code { | ||||
| 	TTYC_SMCUP, | ||||
| 	TTYC_SMKX, | ||||
| 	TTYC_SMSO, | ||||
| 	TTYC_SMULX, | ||||
| 	TTYC_SMUL, | ||||
| 	TTYC_SMXX, | ||||
| 	TTYC_SS, | ||||
| @@ -554,6 +555,18 @@ enum utf8_state { | ||||
| #define GRID_ATTR_ITALICS 0x40 | ||||
| #define GRID_ATTR_CHARSET 0x80	/* alternative character set */ | ||||
| #define GRID_ATTR_STRIKETHROUGH 0x100 | ||||
| #define GRID_ATTR_UNDERSCORE_2 0x200 | ||||
| #define GRID_ATTR_UNDERSCORE_3 0x400 | ||||
| #define GRID_ATTR_UNDERSCORE_4 0x800 | ||||
| #define GRID_ATTR_UNDERSCORE_5 0x1000 | ||||
|  | ||||
| /* All underscore attributes. */ | ||||
| #define GRID_ATTR_ALL_UNDERSCORE \ | ||||
| 	(GRID_ATTR_UNDERSCORE|	 \ | ||||
| 	 GRID_ATTR_UNDERSCORE_2| \ | ||||
| 	 GRID_ATTR_UNDERSCORE_3| \ | ||||
| 	 GRID_ATTR_UNDERSCORE_4| \ | ||||
| 	 GRID_ATTR_UNDERSCORE_5) | ||||
|  | ||||
| /* Grid flags. */ | ||||
| #define GRID_FLAG_FG256 0x1 | ||||
|   | ||||
							
								
								
									
										45
									
								
								tty-term.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								tty-term.c
									
									
									
									
									
								
							| @@ -256,6 +256,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { | ||||
| 	[TTYC_SMCUP] = { TTYCODE_STRING, "smcup" }, | ||||
| 	[TTYC_SMKX] = { TTYCODE_STRING, "smkx" }, | ||||
| 	[TTYC_SMSO] = { TTYCODE_STRING, "smso" }, | ||||
| 	[TTYC_SMULX] = { TTYCODE_STRING, "Smulx" }, | ||||
| 	[TTYC_SMUL] = { TTYCODE_STRING, "smul" }, | ||||
| 	[TTYC_SMXX] =  { TTYCODE_STRING, "smxx" }, | ||||
| 	[TTYC_SS] = { TTYCODE_STRING, "Ss" }, | ||||
| @@ -302,25 +303,50 @@ tty_term_strip(const char *s) | ||||
| 	return (xstrdup(buf)); | ||||
| } | ||||
|  | ||||
| static char * | ||||
| tty_term_override_next(const char *s, size_t *offset) | ||||
| { | ||||
| 	static char	value[BUFSIZ]; | ||||
| 	size_t		n = 0, at = *offset; | ||||
|  | ||||
| 	if (s[at] == '\0') | ||||
| 		return (NULL); | ||||
|  | ||||
| 	while (s[at] != '\0' && s[at] != ':') { | ||||
| 		if (s[at] == '\\' && s[at + 1] == ':') { | ||||
| 			value[n++] = ':'; | ||||
| 			at += 2; | ||||
| 		} else { | ||||
| 			value[n++] = s[at]; | ||||
| 			at++; | ||||
| 		} | ||||
| 		if (n == (sizeof value) - 1) | ||||
| 			return (NULL); | ||||
| 	} | ||||
| 	if (s[at] != '\0') | ||||
| 		*offset = at + 1; | ||||
| 	else | ||||
| 		*offset = at; | ||||
| 	value[n] = '\0'; | ||||
| 	return (value); | ||||
| } | ||||
|  | ||||
| static void | ||||
| tty_term_override(struct tty_term *term, const char *override) | ||||
| { | ||||
| 	const struct tty_term_code_entry	*ent; | ||||
| 	struct tty_code				*code; | ||||
| 	char					*next, *s, *copy, *cp, *value; | ||||
| 	size_t                                   offset = 0; | ||||
| 	char					*cp, *value, *s; | ||||
| 	const char				*errstr; | ||||
| 	u_int					 i; | ||||
| 	int					 n, remove; | ||||
|  | ||||
| 	copy = next = xstrdup(override); | ||||
|  | ||||
| 	s = strsep(&next, ":"); | ||||
| 	if (s == NULL || next == NULL || fnmatch(s, term->name, 0) != 0) { | ||||
| 		free(copy); | ||||
| 	s = tty_term_override_next(override, &offset); | ||||
| 	if (s == NULL || fnmatch(s, term->name, 0) != 0) | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	while ((s = strsep(&next, ":")) != NULL) { | ||||
| 	while ((s = tty_term_override_next(override, &offset)) != NULL) { | ||||
| 		if (*s == '\0') | ||||
| 			continue; | ||||
| 		value = NULL; | ||||
| @@ -341,6 +367,8 @@ tty_term_override(struct tty_term *term, const char *override) | ||||
|  | ||||
| 		if (remove) | ||||
| 			log_debug("%s override: %s@", term->name, s); | ||||
| 		else if (*value == '\0') | ||||
| 			log_debug("%s override: %s", term->name, s); | ||||
| 		else | ||||
| 			log_debug("%s override: %s=%s", term->name, s, value); | ||||
|  | ||||
| @@ -379,7 +407,6 @@ tty_term_override(struct tty_term *term, const char *override) | ||||
|  | ||||
| 		free(value); | ||||
| 	} | ||||
| 	free(s); | ||||
| } | ||||
|  | ||||
| struct tty_term * | ||||
|   | ||||
							
								
								
									
										13
									
								
								tty.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								tty.c
									
									
									
									
									
								
							| @@ -2163,8 +2163,19 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, | ||||
| 		tty_putcode(tty, TTYC_DIM); | ||||
| 	if (changed & GRID_ATTR_ITALICS) | ||||
| 		tty_set_italics(tty); | ||||
| 	if (changed & GRID_ATTR_UNDERSCORE) | ||||
| 	if (changed & GRID_ATTR_ALL_UNDERSCORE) { | ||||
| 		if ((changed & GRID_ATTR_UNDERSCORE) || | ||||
| 		    !tty_term_has(tty->term, TTYC_SMULX)) | ||||
| 			tty_putcode(tty, TTYC_SMUL); | ||||
| 		else if (changed & GRID_ATTR_UNDERSCORE_2) | ||||
| 			tty_putcode1(tty, TTYC_SMULX, 2); | ||||
| 		else if (changed & GRID_ATTR_UNDERSCORE_3) | ||||
| 			tty_putcode1(tty, TTYC_SMULX, 3); | ||||
| 		else if (changed & GRID_ATTR_UNDERSCORE_4) | ||||
| 			tty_putcode1(tty, TTYC_SMULX, 4); | ||||
| 		else if (changed & GRID_ATTR_UNDERSCORE_5) | ||||
| 			tty_putcode1(tty, TTYC_SMULX, 5); | ||||
| 	} | ||||
| 	if (changed & GRID_ATTR_BLINK) | ||||
| 		tty_putcode(tty, TTYC_BLINK); | ||||
| 	if (changed & GRID_ATTR_REVERSE) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Nicholas Marriott
					Nicholas Marriott