$NetBSD: patch-az,v 1.1 2009/08/07 16:39:21 lukem Exp $

--- ../vi/v_txt.c.orig	2007-11-19 03:41:42.000000000 +1100
+++ ../vi/v_txt.c
@@ -948,7 +948,7 @@ k_escape:	LINE_RESOLVE;
 
 		switch (carat) {
 		case C_CARATSET:	/* ^^D */
-			if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1)
+			if (tp->ai == 0 || tp->cno != tp->ai + tp->offset + 1)
 				goto ins_ch;
 
 			/* Save the ai string for later. */
@@ -961,17 +961,18 @@ k_escape:	LINE_RESOLVE;
 			carat = C_NOCHANGE;
 			goto leftmargin;
 		case C_ZEROSET:		/* 0^D */
-			if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1)
+			if (tp->ai == 0 || tp->cno != tp->ai + tp->offset + 1)
 				goto ins_ch;
 
 			carat = C_NOTSET;
 leftmargin:		tp->lb[tp->cno - 1] = ' ';
 			tp->owrite += tp->cno - tp->offset;
-			tp->ai = 0;
 			tp->cno = tp->offset;
 			break;
+		case C_NOCHANGE:	/* ^D after reset with ^^D */
+			/* FALLTHROUGH */
 		case C_NOTSET:		/* ^D */
-			if (tp->ai == 0 || tp->cno > tp->ai + tp->offset)
+			if (tp->ai == 0 || tp->cno != tp->ai + tp->offset)
 				goto ins_ch;
 
 			(void)txt_dent(sp, tp, 0);
@@ -1719,13 +1720,19 @@ txt_ai_resolve(SCR *sp, TEXT *tp, int *c
 	/*
 	 * If there are no spaces, or no tabs after spaces and less than
 	 * ts spaces, it's already minimal.
+	 * Keep analysing if expandtab is set.
 	 */
-	if (!spaces || !tab_after_sp && spaces < ts)
+	if ((!spaces || (!tab_after_sp && spaces < ts)) &&
+	    !O_ISSET(sp, O_EXPANDTAB))
 		return;
 
 	/* Count up spaces/tabs needed to get to the target. */
-	for (cno = 0, tabs = 0; cno + COL_OFF(cno, ts) <= scno; ++tabs)
-		cno += COL_OFF(cno, ts);
+	cno = 0;
+	tabs = 0;
+	if (!O_ISSET(sp, O_EXPANDTAB)) {
+		for (; cno + COL_OFF(cno, ts) <= scno; ++tabs)
+			cno += COL_OFF(cno, ts);
+	}
 	spaces = scno - cno;
 
 	/*
@@ -1889,7 +1896,6 @@ txt_dent(SCR *sp, TEXT *tp, int isindent
 	CHAR_T ch;
 	u_long sw, ts;
 	size_t cno, current, spaces, target, tabs, off;
-	int ai_reset;
 
 	ts = O_VAL(sp, O_TABSTOP);
 	sw = O_VAL(sp, O_SHIFTWIDTH);
@@ -1921,16 +1927,6 @@ txt_dent(SCR *sp, TEXT *tp, int isindent
 		target -= --target % sw;
 
 	/*
-	 * The AI characters will be turned into overwrite characters if the
-	 * cursor immediately follows them.  We test both the cursor position
-	 * and the indent flag because there's no single test.  (^T can only
-	 * be detected by the cursor position, and while we know that the test
-	 * is always true for ^D, the cursor can be in more than one place, as
-	 * "0^D" and "^D" are different.)
-	 */
-	ai_reset = !isindent || tp->cno == tp->ai + tp->offset;
-
-	/*
 	 * Back up over any previous <blank> characters, changing them into
 	 * overwrite characters (including any ai characters).  Then figure
 	 * out the current screen column.
@@ -1957,15 +1953,16 @@ txt_dent(SCR *sp, TEXT *tp, int isindent
 	if (current >= target)
 		spaces = tabs = 0;
 	else {
-		for (cno = current,
-		    tabs = 0; cno + COL_OFF(cno, ts) <= target; ++tabs)
-			cno += COL_OFF(cno, ts);
+		cno = current;
+		tabs = 0;
+		if (!O_ISSET(sp, O_EXPANDTAB)) {
+			for (; cno + COL_OFF(cno, ts) <= target; ++tabs)
+				cno += COL_OFF(cno, ts);
+		}
 		spaces = target - cno;
 	}
 
-	/* If we overwrote ai characters, reset the ai count. */
-	if (ai_reset)
-		tp->ai = tabs + spaces;
+	tp->ai = tabs + spaces;
 
 	/*
 	 * Call txt_insch() to insert each character, so that we get the
