diff --git a/src/move.c b/src/move.c
index 719aa26..9826ff0 100644
--- a/src/move.c
+++ b/src/move.c
@@ -92,6 +92,14 @@ void do_page_up(void)
     openfile->current_x = actual_x(openfile->current->data,
 				actual_last_column(leftedge, target_column));
 
+#ifndef NANO_TINY
+    /* If a tab begins on the previous chunk and ends on this one, shift
+     * current_x forward to just after the tab, so that we stay on this one. */
+    if (ISSET(SOFTWRAP) && leftedge > 0 && leftedge % tabsize != 0 &&
+		openfile->current->data[openfile->current_x] == '\t')
+	openfile->current_x++;
+#endif
+
     /* Move the viewport so that the cursor stays immobile, if possible. */
     adjust_viewport(STATIONARY);
     refresh_needed = TRUE;
@@ -126,6 +134,14 @@ void do_page_down(void)
     openfile->current_x = actual_x(openfile->current->data,
 				actual_last_column(leftedge, target_column));
 
+#ifndef NANO_TINY
+    /* If a tab begins on the previous chunk and ends on this one, shift
+     * current_x forward to just after the tab, so that we stay on this one. */
+    if (ISSET(SOFTWRAP) && leftedge > 0 && leftedge % tabsize != 0 &&
+		openfile->current->data[openfile->current_x] == '\t')
+	openfile->current_x++;
+#endif
+
     /* Move the viewport so that the cursor stays immobile, if possible. */
     adjust_viewport(STATIONARY);
     refresh_needed = TRUE;
@@ -354,6 +370,15 @@ void do_home(bool be_clever)
     if (ISSET(SOFTWRAP)) {
 	leftedge = leftedge_for(was_column, openfile->current);
 	leftedge_x = actual_x(openfile->current->data, leftedge);
+
+	/* If a tab begins on the previous chunk and ends on this one, shift
+	 * leftedge and leftedge_x forward to just after the tab, so that we
+	 * stay on this one. */
+	if (leftedge > 0 && leftedge % tabsize != 0 &&
+		openfile->current->data[leftedge_x] == '\t') {
+	    leftedge += leftedge % tabsize;
+	    leftedge_x++;
+	}
     }
 
     if (ISSET(SMART_HOME) && be_clever) {
@@ -486,6 +511,14 @@ void do_up(bool scroll_only)
     openfile->current_x = actual_x(openfile->current->data,
 				actual_last_column(leftedge, target_column));
 
+#ifndef NANO_TINY
+    /* If a tab begins on the previous chunk and ends on this one, shift
+     * current_x forward to just after the tab, so that we stay on this one. */
+    if (ISSET(SOFTWRAP) && leftedge > 0 && leftedge % tabsize != 0 &&
+		openfile->current->data[openfile->current_x] == '\t')
+	openfile->current_x++;
+#endif
+
     /* When the cursor was on the first line of the edit window (or when just
      * scrolling without moving the cursor), scroll the edit window up -- one
      * line if we're in smooth scrolling mode, and half a page otherwise. */
@@ -530,6 +563,14 @@ void do_down(bool scroll_only)
     openfile->current_x = actual_x(openfile->current->data,
 				actual_last_column(leftedge, target_column));
 
+#ifndef NANO_TINY
+    /* If a tab begins on the previous chunk and ends on this one, shift
+     * current_x forward to just after the tab, so that we stay on this one. */
+    if (ISSET(SOFTWRAP) && leftedge > 0 && leftedge % tabsize != 0 &&
+		openfile->current->data[openfile->current_x] == '\t')
+	openfile->current_x++;
+#endif
+
     /* When the cursor was on the last line of the edit window (or when just
      * scrolling without moving the cursor), scroll the edit window down -- one
      * line if we're in smooth scrolling mode, and half a page otherwise. */
diff --git a/src/winio.c b/src/winio.c
index 9c5d1e2..59844d6 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -2975,6 +2975,8 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
 	/* Current index in text. */
     size_t column = 0;
 	/* Current column position in text. */
+    size_t prev_index = 0;
+	/* Previous index in text. */
     size_t prev_column = 0;
 	/* Previous column position in text. */
     size_t goal_column;
@@ -2991,8 +2993,10 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
     while (*text != '\0' && column < leftedge)
 	text += parse_mbchar(text, NULL, &column);
 
-    /* Use a full screen row for text. */
-    goal_column = column + editwincols;
+    /* Use a full screen row for text.  If a tab begins on the previous chunk
+     * and ends on this one, column will not be the first column of the screen
+     * row, so use leftedge instead. */
+    goal_column = leftedge + editwincols;
 
     while (*text != '\0' && column <= goal_column) {
 	/* When breaking at blanks, do it *before* the target column. */
@@ -3002,6 +3006,7 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
 	    lastblank_column = column;
 	}
 
+	prev_index = index;
 	prev_column = column;
 	char_len = parse_mbchar(text, NULL, &column);
 	text += char_len;
@@ -3020,9 +3025,22 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
     if (found_blank) {
 	text = text - index + lastblank_index;
 	parse_mbchar(text, NULL, &lastblank_column);
+
+	/* If a tab begins on this chunk and ends on the next one, break at the
+	 * last column of this screen row. */
+	if (*text == '\t')
+	    lastblank_column = goal_column;
+
 	return lastblank_column;
     }
 
+    text = text - index + prev_index;
+
+    /* If a tab begins on this chunk and ends on the next one, break at the
+     * last column of this screen row. */
+    if (*text == '\t')
+	prev_column = goal_column;
+
     /* Otherwise, return the column of the last character that doesn't
      * overshoot the target, since we can't break the text anywhere else. */
     return (editwincols > 1) ? prev_column : column - 1;
