Commit Diff


commit - ec5e90b332b7faee24b11167b737e188f50132a2
commit + f853ec6f0c0569cf5bae15ce3e9d8bfc533b358b
blob - 8d99448e05f0635c4fb2697c80b760e1ef89441a
blob + 37f065f0477ec6c49761015959cc8b551e4460d5
--- downloads.c
+++ downloads.c
@@ -76,7 +76,7 @@ end:
 	 * counter, and we know for sure is < FMT_SCALED_STRSIZE so it
 	 * fits.
 	 */
-	wrap_page(&downloadwin, download_cols);
+	wrap_page(&downloadwin, download_cols, 0);
 }
 
 struct download *
blob - a71194801bebd6854ad8374b707c970a667e9e9d
blob + 4fef139c1261430ad2bf355145f043d383f467fb
--- help.c
+++ help.c
@@ -88,6 +88,6 @@ recompute_help(void)
 		helpwin.mode = "*Help*";
 		erase_buffer(&helpwin);
 		rec_compute_help(current_map, p, sizeof(p));
-		wrap_page(&helpwin, help_cols);
+		wrap_page(&helpwin, help_cols, 0);
 	}
 }
blob - 3f7a73e3c48f1a88a5ba2c6846e2c4930cd0f8bc
blob + 7238b8c53cf0fb6399c6781854e5e422333b7de3
--- telescope.h
+++ telescope.h
@@ -248,7 +248,7 @@ int		 ui_send_net(int, uint32_t, int, const void *, ui
 void		 erase_buffer(struct buffer *);
 void		 empty_linelist(struct buffer*);
 void		 empty_vlist(struct buffer*);
-int		 wrap_text(struct buffer*, const char*, struct line*, size_t, int);
-int		 wrap_page(struct buffer *, int width);
+int		 wrap_text(struct buffer*, const char*, struct line*, size_t, int, int);
+int		 wrap_page(struct buffer *, int, int);
 
 #endif /* TELESCOPE_H */
blob - d8b5580a795cafd36789f73de5967b0653662eb9
blob + 91bb028d586fd63fcc4f5f69c75730c62bc9f7a0
--- ui.c
+++ ui.c
@@ -69,7 +69,7 @@ static void		 handle_signal(int, int, void*);
 static void		 handle_resize_nodelay(int, int, void*);
 static void		 handle_download_refresh(int, int, void *);
 static void		 rearrange_windows(void);
-static void		 line_prefix_and_text(struct vline *, char *, size_t, const char **, const char **, int *);
+static void		 line_prefix_and_text(int, struct vline *, char *, size_t, const char **, const char **, int *);
 static void		 print_vline(int, int, WINDOW*, struct vline*);
 static void		 redraw_tabline(void);
 static void		 redraw_window(WINDOW *, int, int, int, int, struct buffer *);
@@ -226,30 +226,34 @@ restore_curs_x(struct buffer *buffer)
 	if (dont_apply_styling)
 		lp = raw_prefixes;
 
+	buffer->curs_x = 0;
+
+	/* small hack: don't olivetti-mode the download pane */
+	if (buffer != &downloadwin)
+		buffer->curs_x += x_offset;
+
 	vl = buffer->current_line;
 	if (vl == NULL || vl->len == 0 || vl->parent == NULL)
-		buffer->curs_x = buffer->point_offset = 0;
+		buffer->curs_x += buffer->point_offset = 0;
 	else if (vl->parent->data != NULL) {
 		text = vl->parent->data;
-		buffer->curs_x = utf8_snwidth(text, buffer->point_offset);
+		buffer->curs_x += utf8_snwidth(text, buffer->point_offset,
+		    buffer->curs_x);
 	} else {
 		text = vl->parent->line + vl->from;
-		buffer->curs_x = utf8_snwidth(text, buffer->point_offset);
+		buffer->curs_x += utf8_snwidth(text, buffer->point_offset,
+		    buffer->curs_x);
 	}
 
-	/* small hack: don't olivetti-mode the download pane */
-	if (buffer != &downloadwin)
-		buffer->curs_x += x_offset;
-
 	if (vl == NULL)
 		return;
 
 	if (vl->parent->data != NULL)
 		buffer->curs_x += utf8_swidth_between(vl->parent->line,
-		    vl->parent->data);
+		    vl->parent->data, buffer->curs_x);
 	else {
 		prfx = lp[vl->parent->type].prfx1;
-		buffer->curs_x += utf8_swidth(prfx);
+		buffer->curs_x += utf8_swidth(prfx, buffer->curs_x);
 	}
 }
 
@@ -429,7 +433,7 @@ rearrange_windows(void)
 		wresize(minibuffer, minibuffer_lines, COLS);
 		lines -= minibuffer_lines;
 
-		wrap_page(&ministate.compl.buffer, COLS);
+		wrap_page(&ministate.compl.buffer, COLS, 0);
 	}
 
 	mvwin(echoarea, --lines, 0);
@@ -445,7 +449,7 @@ rearrange_windows(void)
 		wresize(download, download_lines, download_cols);
 		lines -= download_lines;
 
-		wrap_page(&downloadwin, download_cols);
+		wrap_page(&downloadwin, download_cols, 0);
 	}
 
 	body_lines = show_tab_bar ? --lines : lines;
@@ -461,7 +465,7 @@ rearrange_windows(void)
 		mvwin(help, show_tab_bar, 0);
 		wresize(help, help_lines, help_cols);
 
-		wrap_page(&helpwin, help_cols);
+		wrap_page(&helpwin, help_cols, 0);
 
 		body_cols = COLS - help_cols - 1;
 		mvwin(body, show_tab_bar, help_cols);
@@ -474,12 +478,12 @@ rearrange_windows(void)
 	if (show_tab_bar)
 		wresize(tabline, 1, COLS);
 
-	wrap_page(&current_tab->buffer, body_cols);
+	wrap_page(&current_tab->buffer, body_cols, x_offset);
 	redraw_tab(current_tab);
 }
 
 static void
-line_prefix_and_text(struct vline *vl, char *buf, size_t len,
+line_prefix_and_text(int col, struct vline *vl, char *buf, size_t len,
     const char **prfx_ret, const char **text_ret, int *text_len)
 {
 	struct lineprefix *lp = line_prefixes;
@@ -511,7 +515,7 @@ line_prefix_and_text(struct vline *vl, char *buf, size
 
 	if (cont) {
 		memset(buf, 0, len);
-		width = utf8_swidth_between(vl->parent->line, space);
+		width = utf8_swidth_between(vl->parent->line, space, col);
 		for (i = 0; i < width + 1 && i < len - 1; ++i)
 			buf[i] = ' ';
 	} else {
@@ -587,7 +591,7 @@ print_vline(int off, int width, WINDOW *window, struct
 	if (vl->parent->type == LINE_FRINGE && fringe_ignore_offset)
 		off = 0;
 
-	line_prefix_and_text(vl, emojibuf, sizeof(emojibuf), &prfx,
+	line_prefix_and_text(off, vl, emojibuf, sizeof(emojibuf), &prfx,
 	    &text, &textlen);
 
 	wattr_on(window, body_face.left, NULL);
@@ -972,7 +976,7 @@ do_redraw_minibuffer(void)
 		start = hist_cur(ministate.hist);
 	line = buffer->current_line->parent->line + buffer->current_line->from;
 	c = line + buffer->point_offset;
-	while (start < c && utf8_swidth_between(start, c) > (size_t)COLS/2) {
+	while (start < c && utf8_swidth_between(start, c, off_x) > (size_t)COLS/2) {
 		start += grapheme_next_character_break_utf8(start, SIZE_MAX);
 	}
 
@@ -981,7 +985,7 @@ do_redraw_minibuffer(void)
 	if (ministate.curmesg != NULL)
 		wprintw(echoarea, " [%s]", ministate.curmesg);
 
-	wmove(echoarea, 0, off_x + utf8_swidth_between(start, c));
+	wmove(echoarea, 0, off_x + utf8_swidth_between(start, c, off_x));
 }
 
 static void
@@ -1236,7 +1240,7 @@ ui_on_tab_loaded(struct tab *tab)
 void
 ui_on_tab_refresh(struct tab *tab)
 {
-	wrap_page(&tab->buffer, body_cols);
+	wrap_page(&tab->buffer, body_cols, x_offset);
 	if (tab == current_tab)
 		redraw_tab(tab);
 	else
blob - 0df3b69ead606f8dc306a10192e45832ac86b0a2
blob + 37b942d203b94dd4d84fed7f53f56d5e684bebb4
--- utf8.c
+++ utf8.c
@@ -75,9 +75,12 @@ utf8_decode(uint32_t* restrict state, uint32_t* restri
 	return decode(state, codep, byte);
 }
 
-/* returns only 0, 1, 2 or 8.  assumes sizeof(wchar_t) is 4 */
+/*
+ * returns 0, 1, 2 or less than 8 for tabs.  assumes that
+ * sizeof(wchar_t) == 4
+ */
 static size_t
-utf8_chwidth(uint32_t cp)
+utf8_chwidth(uint32_t cp, int col)
 {
 	/* XXX: if we're running on a platform where sizeof(wchar_t)
 	 * == 2 what to do?  The manpage for wcwidth and wcs isn't
@@ -86,54 +89,64 @@ utf8_chwidth(uint32_t cp)
 	assert(sizeof(wchar_t) == 4);
 
 	/*
-	 * quick and dirty fix for the tabs.  In the future we may
-	 * want to expand tabs into N spaces, but for the time being
-	 * this seems to be good enough (tm).
+	 * Tabs are wide until the next multiple of eight.
 	 */
 	if (cp == '\t')
-		return 8;
+		return (((col + 8) / 8) * 8) - col;
 
 	return wcwidth((wchar_t)cp);
 }
 
 size_t
-utf8_snwidth(const char *s, size_t off)
+utf8_snwidth(const char *s, size_t off, int col)
 {
 	size_t i, tot;
 	uint32_t cp = 0, state = 0;
+	int width;
 
 	tot = 0;
 	for (i = 0; i < off; ++i)
-		if (!decode(&state, &cp, s[i]))
-			tot += utf8_chwidth(cp);
+		if (!decode(&state, &cp, s[i])) {
+			width = utf8_chwidth(cp, col);
+			tot += width;
+			col += width;
+		}
 
 	return tot;
 }
 
 size_t
-utf8_swidth(const char *s)
+utf8_swidth(const char *s, int col )
 {
 	size_t tot;
 	uint32_t cp = 0, state = 0;
+	int width;
 
 	tot = 0;
 	for (; *s; ++s)
-		if (!decode(&state, &cp, *s))
-			tot += utf8_chwidth(cp);
+		if (!decode(&state, &cp, *s)) {
+			width = utf8_chwidth(cp, col);
+			tot += width;
+			col += width;
+		}
 
 	return tot;
 }
 
 size_t
-utf8_swidth_between(const char *str, const char *end)
+utf8_swidth_between(const char *str, const char *end, int col)
 {
 	size_t tot;
 	uint32_t cp = 0, state = 0;
+	int width;
 
 	tot = 0;
 	for (; *str && str < end; ++str)
-		if (!decode(&state, &cp, *str))
-			tot += utf8_chwidth(cp);
+		if (!decode(&state, &cp, *str)) {
+			width = utf8_chwidth(cp, col);
+			tot += width;
+			col += width;
+		}
 	return tot;
 }
 
blob - 2dec60084feb41ed7eb0678f55d2f77cea2fdd82
blob + 9fbfb611fc480b5d59b6ea5d595e17d204534256
--- utf8.h
+++ utf8.h
@@ -22,9 +22,9 @@
 
 /* utf8.c */
 uint32_t	 utf8_decode(uint32_t*restrict, uint32_t*restrict, uint8_t);
-size_t		 utf8_snwidth(const char*, size_t);
-size_t		 utf8_swidth(const char*);
-size_t		 utf8_swidth_between(const char*, const char*);
+size_t		 utf8_snwidth(const char*, size_t, int);
+size_t		 utf8_swidth(const char*, int);
+size_t		 utf8_swidth_between(const char*, const char*, int);
 int		 emojied_line(const char *, const char **);
 
 /* emoji-matcher.c */
blob - aed5aef2f6f14cfbbf11cfb520bab412e2e27bdb
blob + ca120f275e67a2c9aa8da7365aa6f4a4eb2fed3f
--- wrap.c
+++ wrap.c
@@ -105,7 +105,7 @@ push_line(struct buffer *buffer, struct line *l, const
  */
 int
 wrap_text(struct buffer *buffer, const char *prfx, struct line *l,
-    size_t width, int oneline)
+    size_t width, int base_offset, int oneline)
 {
 	const char	*line, *space;
 	size_t		 ret, off, start, cur, prfxwidth;
@@ -114,15 +114,15 @@ wrap_text(struct buffer *buffer, const char *prfx, str
 	if ((line = l->line) == NULL || *line == '\0')
 		return push_line(buffer, l, NULL, 0, 0);
 
-	prfxwidth = utf8_swidth(prfx);
-	cur = prfxwidth;
+	prfxwidth = utf8_swidth(prfx, base_offset);
+	cur = base_offset + prfxwidth;
 	start = 0;
 	flags = 0;
 
 	if (l->type == LINE_LINK && emojify_link &&
 	    emojied_line(l->line, &space)) {
-	    	prfxwidth = utf8_swidth_between(l->line, space);
-		cur = prfxwidth;
+	    	prfxwidth = utf8_swidth_between(l->line, space, base_offset);
+		cur = base_offset + prfxwidth;
 		line = space + 1;
 	}
 
@@ -130,7 +130,8 @@ wrap_text(struct buffer *buffer, const char *prfx, str
 		size_t t;
 
 		ret = grapheme_next_line_break_utf8(&line[off], SIZE_MAX);
-		t = utf8_swidth_between(&line[off], &line[off + ret]);
+		t = utf8_swidth_between(&line[off], &line[off + ret],
+		    base_offset);
 
 		/* we can't reach the last column */
 		if (cur + t < width) {
@@ -146,7 +147,7 @@ wrap_text(struct buffer *buffer, const char *prfx, str
 
 		flags = L_CONTINUATION;
 		start = off;
-		cur = t + prfxwidth;
+		cur = base_offset + prfxwidth + t;
 	}
 
 	if (off != start)
@@ -155,7 +156,7 @@ wrap_text(struct buffer *buffer, const char *prfx, str
 }
 
 int
-wrap_page(struct buffer *buffer, int width)
+wrap_page(struct buffer *buffer, int width, int x_offset)
 {
 	struct line		*l;
 	const struct line	*top_orig, *orig;
@@ -193,7 +194,7 @@ wrap_page(struct buffer *buffer, int width)
 		case LINE_PATCH_ADD:
 		case LINE_PATCH_DEL:
 			wrap_text(buffer, prfx, l, MIN(fill_column, width),
-			    0);
+			    x_offset, 0);
 			break;
 		case LINE_COMPL:
 		case LINE_COMPL_CURRENT:
@@ -201,7 +202,7 @@ wrap_page(struct buffer *buffer, int width)
 		case LINE_DOWNLOAD:
 		case LINE_DOWNLOAD_DONE:
 		case LINE_DOWNLOAD_INFO:
-			wrap_text(buffer, prfx, l, width, 1);
+			wrap_text(buffer, prfx, l, width, x_offset, 1);
 			break;
 		case LINE_FRINGE:
 			/* never, ever wrapped */