mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:44:18 +00:00 
			
		
		
		
	Add a UTF-8 aware string length function and make UTF-8 in
status-left/status-right work properly. At the moment any top-bit-set characters are assumed to be UTF-8: a status-utf8 option to configure this will come shortly.
This commit is contained in:
		
							
								
								
									
										114
									
								
								screen-write.c
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								screen-write.c
									
									
									
									
									
								
							@@ -52,20 +52,126 @@ screen_write_putc(
 | 
				
			|||||||
	screen_write_cell(ctx, gc, NULL);
 | 
						screen_write_cell(ctx, gc, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Calculate string length. */
 | 
				
			||||||
 | 
					size_t printflike1
 | 
				
			||||||
 | 
					screen_write_strlen(const char *fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list	ap;
 | 
				
			||||||
 | 
						char   *msg;
 | 
				
			||||||
 | 
						u_char *ptr, utf8buf[4];
 | 
				
			||||||
 | 
						size_t	left, size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, fmt);
 | 
				
			||||||
 | 
						xvasprintf(&msg, fmt, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr = msg;
 | 
				
			||||||
 | 
						while (*ptr != '\0') {
 | 
				
			||||||
 | 
							if (*ptr > 0x7f) {	/* Assume this is UTF-8. */
 | 
				
			||||||
 | 
								memset(utf8buf, 0xff, sizeof utf8buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								left = strlen(ptr);
 | 
				
			||||||
 | 
								if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
 | 
				
			||||||
 | 
									memcpy(utf8buf, ptr, 2);
 | 
				
			||||||
 | 
									ptr += 2;
 | 
				
			||||||
 | 
								} else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) {
 | 
				
			||||||
 | 
									memcpy(utf8buf, ptr, 3);
 | 
				
			||||||
 | 
									ptr += 3;
 | 
				
			||||||
 | 
								} else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) {
 | 
				
			||||||
 | 
									memcpy(utf8buf, ptr, 4);
 | 
				
			||||||
 | 
									ptr += 4;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*utf8buf = *ptr;
 | 
				
			||||||
 | 
									ptr++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								size += utf8_width(utf8buf);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								size++;
 | 
				
			||||||
 | 
								ptr++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Write string. */
 | 
					/* Write string. */
 | 
				
			||||||
void printflike3
 | 
					void printflike3
 | 
				
			||||||
screen_write_puts(
 | 
					screen_write_puts(
 | 
				
			||||||
    struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...)
 | 
					    struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	va_list	ap;
 | 
						va_list	ap;
 | 
				
			||||||
	char   *msg, *ptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	va_start(ap, fmt);
 | 
						va_start(ap, fmt);
 | 
				
			||||||
	xvasprintf(&msg, fmt, ap);
 | 
						screen_write_vnputs(ctx, -1, gc, fmt, ap);
 | 
				
			||||||
	va_end(ap);
 | 
						va_end(ap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (ptr = msg; *ptr != '\0'; ptr++)
 | 
					/* Write string with length limit (-1 for unlimited). */
 | 
				
			||||||
		screen_write_putc(ctx, gc, (u_char) *ptr);
 | 
					void printflike4
 | 
				
			||||||
 | 
					screen_write_nputs(struct screen_write_ctx *ctx,
 | 
				
			||||||
 | 
					    ssize_t maxlen, struct grid_cell *gc, const char *fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list	ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, fmt);
 | 
				
			||||||
 | 
						screen_write_vnputs(ctx, maxlen, gc, fmt, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					screen_write_vnputs(struct screen_write_ctx *ctx,
 | 
				
			||||||
 | 
					    ssize_t maxlen, struct grid_cell *gc, const char *fmt, va_list ap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char   *msg;
 | 
				
			||||||
 | 
						u_char *ptr, utf8buf[4];
 | 
				
			||||||
 | 
						size_t	left, size = 0;
 | 
				
			||||||
 | 
						int	width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xvasprintf(&msg, fmt, ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr = msg;
 | 
				
			||||||
 | 
						while (*ptr != '\0') {
 | 
				
			||||||
 | 
							if (*ptr > 0x7f) {	/* Assume this is UTF-8. */
 | 
				
			||||||
 | 
								memset(utf8buf, 0xff, sizeof utf8buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								left = strlen(ptr);
 | 
				
			||||||
 | 
								if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
 | 
				
			||||||
 | 
									memcpy(utf8buf, ptr, 2);
 | 
				
			||||||
 | 
									ptr += 2;
 | 
				
			||||||
 | 
								} else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) {
 | 
				
			||||||
 | 
									memcpy(utf8buf, ptr, 3);
 | 
				
			||||||
 | 
									ptr += 3;
 | 
				
			||||||
 | 
								} else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) {
 | 
				
			||||||
 | 
									memcpy(utf8buf, ptr, 4);
 | 
				
			||||||
 | 
									ptr += 4;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*utf8buf = *ptr;
 | 
				
			||||||
 | 
									ptr++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								width = utf8_width(utf8buf);
 | 
				
			||||||
 | 
								if (maxlen > 0 && size + width > (size_t) maxlen) {
 | 
				
			||||||
 | 
									while (size < (size_t) maxlen) {
 | 
				
			||||||
 | 
										screen_write_putc(ctx, gc, ' ');
 | 
				
			||||||
 | 
										size++;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								size += width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								gc->flags |= GRID_FLAG_UTF8;
 | 
				
			||||||
 | 
								screen_write_cell(ctx, gc, utf8buf);
 | 
				
			||||||
 | 
								gc->flags &= ~GRID_FLAG_UTF8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (maxlen > 0 && size > (size_t) maxlen)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								size++;
 | 
				
			||||||
 | 
								screen_write_putc(ctx, gc, *ptr);
 | 
				
			||||||
 | 
								ptr++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xfree(msg);
 | 
						xfree(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								status.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								status.c
									
									
									
									
									
								
							@@ -47,8 +47,8 @@ status_redraw(struct client *c)
 | 
				
			|||||||
	struct window_pane	       *wp;
 | 
						struct window_pane	       *wp;
 | 
				
			||||||
	struct screen		       *sc = NULL, old_status;
 | 
						struct screen		       *sc = NULL, old_status;
 | 
				
			||||||
	char		 	       *left, *right, *text, *ptr;
 | 
						char		 	       *left, *right, *text, *ptr;
 | 
				
			||||||
	size_t				llen, rlen, offset, xx, yy, sy;
 | 
						size_t				llen, llen2, rlen, rlen2, offset;
 | 
				
			||||||
	size_t				size, start, width;
 | 
						size_t				xx, yy, sy, size, start, width;
 | 
				
			||||||
	struct grid_cell	        stdgc, gc;
 | 
						struct grid_cell	        stdgc, gc;
 | 
				
			||||||
	int				larrow, rarrow;
 | 
						int				larrow, rarrow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,15 +78,16 @@ status_redraw(struct client *c)
 | 
				
			|||||||
	left = status_replace(s, options_get_string(
 | 
						left = status_replace(s, options_get_string(
 | 
				
			||||||
	    &s->options, "status-left"), c->status_timer.tv_sec);
 | 
						    &s->options, "status-left"), c->status_timer.tv_sec);
 | 
				
			||||||
	llen = options_get_number(&s->options, "status-left-length");
 | 
						llen = options_get_number(&s->options, "status-left-length");
 | 
				
			||||||
	if (strlen(left) < llen)
 | 
						llen2 = screen_write_strlen("%s", left);
 | 
				
			||||||
		llen = strlen(left);
 | 
						if (llen2 < llen)
 | 
				
			||||||
	left[llen] = '\0';
 | 
							llen = llen2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	right = status_replace(s, options_get_string(
 | 
						right = status_replace(s, options_get_string(
 | 
				
			||||||
	    &s->options, "status-right"), c->status_timer.tv_sec);
 | 
						    &s->options, "status-right"), c->status_timer.tv_sec);
 | 
				
			||||||
	rlen = options_get_number(&s->options, "status-right-length");
 | 
						rlen = options_get_number(&s->options, "status-right-length");
 | 
				
			||||||
	if (strlen(right) < rlen)
 | 
						rlen2 = screen_write_strlen("%s", right);
 | 
				
			||||||
		rlen = strlen(right);
 | 
						if (rlen2 < rlen)
 | 
				
			||||||
 | 
							rlen = rlen2;
 | 
				
			||||||
	right[rlen] = '\0';
 | 
						right[rlen] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
@@ -163,7 +164,7 @@ draw:
 | 
				
			|||||||
	screen_write_start(&ctx, NULL, &c->status);
 | 
						screen_write_start(&ctx, NULL, &c->status);
 | 
				
			||||||
	if (llen != 0) {
 | 
						if (llen != 0) {
 | 
				
			||||||
 		screen_write_cursormove(&ctx, 0, yy);
 | 
					 		screen_write_cursormove(&ctx, 0, yy);
 | 
				
			||||||
		screen_write_puts(&ctx, &stdgc, "%s ", left);
 | 
							screen_write_nputs(&ctx, llen + 1, &stdgc, "%s ", left);
 | 
				
			||||||
		if (larrow)
 | 
							if (larrow)
 | 
				
			||||||
			screen_write_putc(&ctx, &stdgc, ' ');
 | 
								screen_write_putc(&ctx, &stdgc, ' ');
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -220,7 +221,7 @@ draw:
 | 
				
			|||||||
	/* Draw the last item. */
 | 
						/* Draw the last item. */
 | 
				
			||||||
	if (rlen != 0) {
 | 
						if (rlen != 0) {
 | 
				
			||||||
		screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy);
 | 
							screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy);
 | 
				
			||||||
		screen_write_puts(&ctx, &stdgc, " %s", right);
 | 
							screen_write_nputs(&ctx, rlen + 1, &stdgc, " %s", right);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Draw the arrows. */
 | 
						/* Draw the arrows. */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								tmux.h
									
									
									
									
									
								
							@@ -1347,8 +1347,13 @@ void	 grid_view_delete_cells(struct grid *, u_int, u_int, u_int);
 | 
				
			|||||||
void	 screen_write_start(
 | 
					void	 screen_write_start(
 | 
				
			||||||
    	     struct screen_write_ctx *, struct window_pane *, struct screen *);
 | 
					    	     struct screen_write_ctx *, struct window_pane *, struct screen *);
 | 
				
			||||||
void	 screen_write_stop(struct screen_write_ctx *);
 | 
					void	 screen_write_stop(struct screen_write_ctx *);
 | 
				
			||||||
void printflike3 screen_write_puts(
 | 
					size_t printflike1 screen_write_strlen(const char *, ...);
 | 
				
			||||||
	     struct screen_write_ctx *, struct grid_cell *, const char *, ...);
 | 
					void printflike3 screen_write_puts(struct screen_write_ctx *,
 | 
				
			||||||
 | 
					    	     struct grid_cell *, const char *, ...);
 | 
				
			||||||
 | 
					void printflike4 screen_write_nputs(struct screen_write_ctx *,
 | 
				
			||||||
 | 
					    	     ssize_t, struct grid_cell *, const char *, ...);
 | 
				
			||||||
 | 
					void	 screen_write_vnputs(struct screen_write_ctx *,
 | 
				
			||||||
 | 
					    	     ssize_t, struct grid_cell *, const char *, va_list);
 | 
				
			||||||
void	 screen_write_putc(
 | 
					void	 screen_write_putc(
 | 
				
			||||||
    	     struct screen_write_ctx *, struct grid_cell *, u_char);
 | 
					    	     struct screen_write_ctx *, struct grid_cell *, u_char);
 | 
				
			||||||
void	 screen_write_copy(struct screen_write_ctx *,
 | 
					void	 screen_write_copy(struct screen_write_ctx *,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user