diff --git a/wintable/new/select.h b/wintable/new/select.h
index c849802..68e2eb6 100644
--- a/wintable/new/select.h
+++ b/wintable/new/select.h
@@ -3,11 +3,36 @@
 // damn winsock
 static void doselect(struct table *t, intptr_t row, intptr_t column)
 {
+	RECT r, client;
+	intptr_t oldrow;
+	LONG height;
+
+	oldrow = t->selectedRow;
 	t->selectedRow = row;
 	t->selectedColumn = column;
+
 	// TODO scroll to ensure the full cell is visible
-	// TODO redraw only the old and new columns /if there was no scrolling/
-	InvalidateRect(t->hwnd, NULL, TRUE);
+
+	// now redraw the old and new /rows/
+	if (GetClientRect(t->hwnd, &client) == 0)
+		panic("error getting Table client rect in doselect()");
+	client.top += t->headerHeight;
+	height = rowht(t);
+	r.left = client.left;
+	r.right = client.right;
+	if (oldrow != -1 && oldrow >= t->vscrollpos) {
+		r.top = client.top + ((oldrow - t->vscrollpos) * height);
+		r.bottom = r.top + height;
+		if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
+			panic("error queueing previously selected row for redraw in doselect()");
+	}
+	// t->selectedRow must be visible by this point; we scrolled to it
+	if (t->selectedRow != -1 && t->selectedRow != oldrow) {
+		r.top = client.top + ((t->selectedRow - t->vscrollpos) * height);
+		r.bottom = r.top + height;
+		if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
+			panic("error queueing newly selected row for redraw in doselect()");
+	}
 }
 
 // TODO which WM_xBUTTONDOWNs?