diff --git a/src/move.c b/src/move.c
index b36b4bca..1d6f41c8 100644
--- a/src/move.c
+++ b/src/move.c
@@ -64,51 +64,6 @@ void get_edge_and_target(size_t *leftedge, size_t *target_column)
     }
 }
 
-/* Return the index in line->data that corresponds to the given column on the
- * chunk that starts at the given leftedge.  If the index lands on a tab, and
- * this tab starts on an earlier chunk, and the tab ends on this row OR we're
- * going forward, then increment the index and recalculate leftedge. */
-size_t proper_x(filestruct *line, size_t *leftedge, bool forward,
-		size_t column, bool *shifted)
-{
-    size_t index = actual_x(line->data, column);
-
-#ifndef NANO_TINY
-    if (ISSET(SOFTWRAP) && line->data[index] == '\t' && (forward ||
-		*leftedge / tabsize < (*leftedge + editwincols) / tabsize) &&
-		*leftedge % tabsize != 0 && column < *leftedge + tabsize) {
-	index++;
-
-	*leftedge = leftedge_for(strnlenpt(line->data, index), line);
-
-	if (shifted != NULL)
-	    *shifted = TRUE;
-    }
-#endif
-
-    return index;
-}
-
-/* Adjust the values for current_x and placewewant in case we have landed in
- * the middle of a tab that crosses a row boundary. */
-void set_proper_index_and_pww(size_t *leftedge, size_t target, bool forward)
-{
-    bool shifted = FALSE;
-
-    openfile->current_x = proper_x(openfile->current, leftedge, forward,
-			actual_last_column(*leftedge, target), &shifted);
-
-    /* If the index was incremented, try going to the target column. */
-    if (shifted) {
-	size_t newer_x = actual_x(openfile->current->data, *leftedge + target);
-
-	if (newer_x > openfile->current_x)
-	    openfile->current_x = newer_x;
-    }
-
-    openfile->placewewant = *leftedge + target;
-}
-
 /* Move up nearly one screenful. */
 void do_page_up(void)
 {
@@ -127,12 +82,14 @@ void do_page_up(void)
 
     /* Move up the required number of lines or chunks.  If we can't, we're
      * at the top of the file, so put the cursor there and get out. */
-    if (go_back_chunks(mustmove, &openfile->current, &leftedge) > 0) {
+    if (go_back_chunks(mustmove, &openfile->current, &leftedge, MOVING_UP) > 0) {
 	do_first_line();
 	return;
     }
 
-    set_proper_index_and_pww(&leftedge, target_column, FALSE);
+    openfile->current_x = actual_x(openfile->current->data,
+				actual_last_column(leftedge, target_column));
+    openfile->placewewant = leftedge + target_column;
 
     /* Move the viewport so that the cursor stays immobile, if possible. */
     adjust_viewport(STATIONARY);
@@ -157,12 +114,14 @@ void do_page_down(void)
 
     /* Move down the required number of lines or chunks.  If we can't, we're
      * at the bottom of the file, so put the cursor there and get out. */
-    if (go_forward_chunks(mustmove, &openfile->current, &leftedge) > 0) {
+    if (go_forward_chunks(mustmove, &openfile->current, &leftedge, MOVING_DOWN) > 0) {
 	do_last_line();
 	return;
     }
 
-    set_proper_index_and_pww(&leftedge, target_column, TRUE);
+    openfile->current_x = actual_x(openfile->current->data,
+				actual_last_column(leftedge, target_column));
+    openfile->placewewant = leftedge + target_column;
 
     /* Move the viewport so that the cursor stays immobile, if possible. */
     adjust_viewport(STATIONARY);
@@ -384,8 +343,13 @@ void do_home(void)
 
     if (ISSET(SOFTWRAP)) {
 	leftedge = leftedge_for(was_column, openfile->current);
-	leftedge_x = proper_x(openfile->current, &leftedge, FALSE, leftedge,
-				NULL);
+	leftedge_x = actual_x(openfile->current->data, leftedge);
+
+	/* If the line begins on a straddling tab on the previous row, shift
+	 * forward to the next row. */
+	if (openfile->current->data[leftedge_x] == '\t' &&
+		strnlenpt(openfile->current->data, leftedge_x) < leftedge)
+	    leftedge_x++;
     }
 
     if (ISSET(SMART_HOME)) {
@@ -445,7 +409,8 @@ void do_end(void)
 	bool last_chunk = FALSE;
 	size_t leftedge = leftedge_for(was_column, openfile->current);
 	size_t rightedge = get_softwrap_breakpoint(openfile->current->data,
-						leftedge, &last_chunk);
+						leftedge, &last_chunk,
+						NOT_MOVING);
 	size_t rightedge_x;
 
 	/* If we're on the last chunk, we're already at the end of the line.
@@ -496,10 +461,12 @@ void do_up(bool scroll_only)
     get_edge_and_target(&leftedge, &target_column);
 
     /* If we can't move up one line or chunk, we're at top of file. */
-    if (go_back_chunks(1, &openfile->current, &leftedge) > 0)
+    if (go_back_chunks(1, &openfile->current, &leftedge, MOVING_UP) > 0)
 	return;
 
-    set_proper_index_and_pww(&leftedge, target_column, FALSE);
+    openfile->current_x = actual_x(openfile->current->data,
+				actual_last_column(leftedge, target_column));
+    openfile->placewewant = leftedge + target_column;
 
     if (scroll_only)
 	edit_scroll(BACKWARD, 1);
@@ -520,10 +487,12 @@ void do_down(bool scroll_only)
     get_edge_and_target(&leftedge, &target_column);
 
     /* If we can't move down one line or chunk, we're at bottom of file. */
-    if (go_forward_chunks(1, &openfile->current, &leftedge) > 0)
+    if (go_forward_chunks(1, &openfile->current, &leftedge, MOVING_DOWN) > 0)
 	return;
 
-    set_proper_index_and_pww(&leftedge, target_column, TRUE);
+    openfile->current_x = actual_x(openfile->current->data,
+				actual_last_column(leftedge, target_column));
+    openfile->placewewant = leftedge + target_column;
 
     if (scroll_only)
 	edit_scroll(FORWARD, 1);
diff --git a/src/nano.c b/src/nano.c
index 412b17ee..dc67cd9f 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -1771,9 +1771,9 @@ int do_mouse(void)
 
 	/* Move current up or down to the row corresponding to mouse_row. */
 	if (row_count < 0)
-	    go_back_chunks(-row_count, &openfile->current, &leftedge);
+	    go_back_chunks(-row_count, &openfile->current, &leftedge, NOT_MOVING);
 	else
-	    go_forward_chunks(row_count, &openfile->current, &leftedge);
+	    go_forward_chunks(row_count, &openfile->current, &leftedge, NOT_MOVING);
 
 	openfile->current_x = actual_x(openfile->current->data,
 				actual_last_column(leftedge, mouse_col));
diff --git a/src/nano.h b/src/nano.h
index 7960d3be..00358a95 100644
--- a/src/nano.h
+++ b/src/nano.h
@@ -155,6 +155,10 @@ typedef enum {
     SOFTMARK, HARDMARK
 } mark_type;
 
+typedef enum {
+    NOT_MOVING, MOVING_UP, MOVING_DOWN
+} softwrap_move_type;
+
 typedef enum {
     CENTERING, FLOWING, STATIONARY
 } update_type;
diff --git a/src/proto.h b/src/proto.h
index 71c12d40..86489967 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -663,13 +663,15 @@ int update_line(filestruct *fileptr, size_t index);
 int update_softwrapped_line(filestruct *fileptr);
 #endif
 bool line_needs_update(const size_t old_column, const size_t new_column);
-int go_back_chunks(int nrows, filestruct **line, size_t *leftedge);
-int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge);
+int go_back_chunks(int nrows, filestruct **line, size_t *leftedge,
+			softwrap_move_type moving);
+int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge,
+			softwrap_move_type moving);
 bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge);
 void edit_scroll(bool direction, int nrows);
 #ifndef NANO_TINY
 size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
-				bool *end_of_line);
+				bool *end_of_line, softwrap_move_type moving);
 size_t get_chunk_and_edge(size_t column, filestruct *line, size_t *leftedge);
 size_t chunk_for(size_t column, filestruct *line);
 size_t leftedge_for(size_t column, filestruct *line);
diff --git a/src/search.c b/src/search.c
index ea7b6b65..1e11cb63 100644
--- a/src/search.c
+++ b/src/search.c
@@ -887,7 +887,7 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
 	    size_t leftedge = leftedge_for(xplustabs(), openfile->current);
 
 	    rows_from_tail = (editwinrows / 2) -
-			go_forward_chunks(editwinrows / 2, &line, &leftedge);
+			go_forward_chunks(editwinrows / 2, &line, &leftedge, NOT_MOVING);
 	} else
 #endif
 	    rows_from_tail = openfile->filebot->lineno -
diff --git a/src/winio.c b/src/winio.c
index f90d23dc..920d7b0d 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -2781,7 +2781,8 @@ int update_softwrapped_line(filestruct *fileptr)
     while (row < editwinrows) {
 	bool end_of_line = FALSE;
 
-	to_col = get_softwrap_breakpoint(fileptr->data, from_col, &end_of_line);
+	to_col = get_softwrap_breakpoint(fileptr->data, from_col, &end_of_line,
+						NOT_MOVING);
 
 	blank_row(edit, row, 0, COLS);
 
@@ -2823,7 +2824,8 @@ bool line_needs_update(const size_t old_column, const size_t new_column)
  * given column (leftedge).  After moving, leftedge will be set to the
  * starting column of the current chunk.  Return the number of chunks we
  * couldn't move up, which will be zero if we completely succeeded. */
-int go_back_chunks(int nrows, filestruct **line, size_t *leftedge)
+int go_back_chunks(int nrows, filestruct **line, size_t *leftedge,
+			softwrap_move_type moving)
 {
     int i;
 
@@ -2836,7 +2838,7 @@ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge)
 	    *leftedge = 0;
 
 	    if (chunk >= i)
-		return go_forward_chunks(chunk - i, line, leftedge);
+		return go_forward_chunks(chunk - i, line, leftedge, MOVING_UP);
 
 	    if (*line == openfile->fileage)
 		break;
@@ -2860,7 +2862,8 @@ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge)
  * given column (leftedge).  After moving, leftedge will be set to the
  * starting column of the current chunk.  Return the number of chunks we
  * couldn't move down, which will be zero if we completely succeeded. */
-int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge)
+int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge,
+			softwrap_move_type moving)
 {
     int i;
 
@@ -2873,7 +2876,8 @@ int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge)
 	    bool end_of_line = FALSE;
 
 	    current_leftedge = get_softwrap_breakpoint((*line)->data,
-					current_leftedge, &end_of_line);
+					current_leftedge, &end_of_line,
+					moving);
 
 	    if (!end_of_line)
 		continue;
@@ -2905,7 +2909,7 @@ bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge)
     if (ISSET(SOFTWRAP)) {
 	filestruct *line = openfile->current;
 	size_t leftedge = leftedge_for(xplustabs(), openfile->current);
-	int rows_left = go_back_chunks(editwinrows - 1, &line, &leftedge);
+	int rows_left = go_back_chunks(editwinrows - 1, &line, &leftedge, NOT_MOVING);
 
 	return (rows_left > 0 || line->lineno < was_lineno ||
 		(line->lineno == was_lineno && leftedge <= was_leftedge));
@@ -2927,9 +2931,9 @@ void edit_scroll(bool direction, int nrows)
     /* Move the top line of the edit window the requested number of rows up or
      * down, and reduce the number of rows with the amount we couldn't move. */
     if (direction == BACKWARD)
-	nrows -= go_back_chunks(nrows, &openfile->edittop, &openfile->firstcolumn);
+	nrows -= go_back_chunks(nrows, &openfile->edittop, &openfile->firstcolumn, NOT_MOVING);
     else
-	nrows -= go_forward_chunks(nrows, &openfile->edittop, &openfile->firstcolumn);
+	nrows -= go_forward_chunks(nrows, &openfile->edittop, &openfile->firstcolumn, NOT_MOVING);
 
     /* Don't bother scrolling zero rows, nor more than the window can hold. */
     if (nrows == 0) {
@@ -2966,7 +2970,7 @@ void edit_scroll(bool direction, int nrows)
 
     /* If we scrolled forward, move down to the start of the blank region. */
     if (direction == FORWARD)
-	go_forward_chunks(editwinrows - nrows, &line, &leftedge);
+	go_forward_chunks(editwinrows - nrows, &line, &leftedge, NOT_MOVING);
 
 #ifndef NANO_TINY
     if (ISSET(SOFTWRAP)) {
@@ -2990,11 +2994,14 @@ void edit_scroll(bool direction, int nrows)
 
 #ifndef NANO_TINY
 /* Get the column number after leftedge where we can break the given text, and
- * return it.  This will always be editwincols or less after leftedge.  Set
- * end_of_line to TRUE if we reach the end of the line while searching the
- * text.  Assume leftedge is the leftmost column of a softwrapped chunk. */
+ * return it.  This will always be editwincols or less after leftedge, unless
+ * moving is something other than NOT_MOVING and we're inside a tab; in that
+ * case, we move up if it's MOVING_UP or down if it's MOVING_DOWN until we're
+ * outside the tab.  Set end_of_line to TRUE if we reach the end of the line
+ * while searching the text.  Assume leftedge is the leftmost column of a
+ * softwrapped chunk. */
 size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
-				bool *end_of_line)
+				bool *end_of_line, softwrap_move_type moving)
 {
     size_t column = 0;
 	/* Current column position in text. */
@@ -3047,9 +3054,26 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
     }
 
     /* If a tab is split over two chunks, break at the screen's edge. */
-    if (*(text - char_len) == '\t')
+    if (*(text - char_len) == '\t') {
 	previous_col = goal_column;
 
+	if (moving) {
+	    /* If a tab takes up multiple rows' worth of chunks, move until
+	     * we're outside of it. */
+	    if (moving == MOVING_DOWN) {
+		size_t after_tab_col = goal_column + tabsize;
+
+		while (after_tab_col > previous_col + editwincols)
+		    previous_col += editwincols;
+	    } else if (moving == MOVING_UP) {
+		size_t before_tab_col = goal_column + tabsize;
+
+		while (before_tab_col < previous_col - editwincols)
+		    previous_col -= editwincols;
+	    }
+	}
+    }
+
     /* Otherwise, return the column of the last character that doesn't
      * overshoot the limit, since we can't break the text anywhere else. */
     return (editwincols > 1) ? previous_col : column - 1;
@@ -3064,7 +3088,8 @@ size_t get_chunk_and_edge(size_t column, filestruct *line, size_t *leftedge)
     bool end_of_line = FALSE;
 
     while (TRUE) {
-	end_col = get_softwrap_breakpoint(line->data, start_col, &end_of_line);
+	end_col = get_softwrap_breakpoint(line->data, start_col, &end_of_line,
+						NOT_MOVING);
 
 	/* We reached the end of the line and/or found column, so get out. */
 	if (end_of_line || (column >= start_col && column < end_col)) {
@@ -3132,7 +3157,8 @@ size_t actual_last_column(size_t leftedge, size_t column)
     if (ISSET(SOFTWRAP)) {
 	bool last_chunk;
 	size_t end_col = get_softwrap_breakpoint(openfile->current->data,
-					leftedge, &last_chunk) - leftedge;
+					leftedge, &last_chunk, NOT_MOVING) -
+					leftedge;
 
 	/* If we're not on the last chunk, we're one column past the end of
 	 * the row.  Shifting back one column might put us in the middle of
@@ -3175,7 +3201,7 @@ bool current_is_below_screen(void)
 
 	/* If current[current_x] is more than a screen's worth of lines after
 	 * edittop at column firstcolumn, it's below the screen. */
-	return (go_forward_chunks(editwinrows - 1, &line, &leftedge) == 0 &&
+	return (go_forward_chunks(editwinrows - 1, &line, &leftedge, NOT_MOVING) == 0 &&
 			(line->lineno < openfile->current->lineno ||
 			(line->lineno == openfile->current->lineno &&
 			leftedge < leftedge_for(xplustabs(),
@@ -3293,7 +3319,7 @@ void adjust_viewport(update_type manner)
 #endif
 
     /* Move edittop back goal rows, starting at current[current_x]. */
-    go_back_chunks(goal, &openfile->edittop, &openfile->firstcolumn);
+    go_back_chunks(goal, &openfile->edittop, &openfile->firstcolumn, NOT_MOVING);
 }
 
 /* Unconditionally redraw the entire screen. */
@@ -3466,7 +3492,8 @@ void spotlight_softwrapped(bool active, size_t from_col, size_t to_col)
 
     while (row < editwinrows) {
 	break_col = get_softwrap_breakpoint(openfile->current->data,
-						leftedge, &end_of_line);
+						leftedge, &end_of_line,
+						NOT_MOVING);
 
 	/* Stop after the end of the word, by pretending the end of the word is
 	 * the end of the line. */
