9term, acme: autoscroll

Ignore scroll/noscroll window setting.
Instead, scroll when the write begins in
or immediately after the displayed window content.

In the new scrolling discipline, executing
"Noscroll" is replaced by typing Page Up or
using the mouse to scroll higher in the buffer,
and executing "Scroll" is replaced by typing End
or using the mouse to scroll to the bottom of
the buffer.

R=r, r2
http://codereview.appspot.com/4433060
diff --git a/man/man1/9term.1 b/man/man1/9term.1
index a9f687c..33a5b05 100644
--- a/man/man1/9term.1
+++ b/man/man1/9term.1
@@ -30,8 +30,9 @@
 .PP
 The
 .B -s
-option initializes the window so that text scrolls;
-the default is not to scroll.
+option has no effect.  It formerly set the scrolling mode,
+and is recognized to avoid breaking scripts that create new windows.
+See below for a description of scrolling behavior.
 .PP
 The
 .B -c
@@ -205,10 +206,9 @@
 In response it sends the terminal's current interrupt character
 (which need not be DEL).
 .PP
-Normally, written output to a window blocks when
-the text reaches the end of the screen and the terminal
-buffer fills;
-a button 2 menu item toggles scrolling.
+Written output to a window is appended to the end of the window.
+The window scrolls to display the new output only if the
+end of the window was visible before the write.
 .PP
 .I 9term
 changes behavior according to
diff --git a/man/man1/acme.1 b/man/man1/acme.1
index d08ff92..2d24f33 100644
--- a/man/man1/acme.1
+++ b/man/man1/acme.1
@@ -646,13 +646,17 @@
 (default
 .BR $SHELL )
 in it, turning the window into something analogous to an
-.IR rio (1)
+.IR 9term (1)
 window.
 Executing text in a
 .I win
 window with button
 2 is similar to using
 .BR Send .
+.I Win
+windows follow the same scrolling heuristic as in
+.IR 9term (1):
+the window scrolls on output only if the window is displaying the end of the buffer.
 .PP
 .I Awd
 loads the tag line of its window with the directory in which it's running, suffixed
diff --git a/man/man1/rio.1 b/man/man1/rio.1
index 3c31b61..1fc0619 100644
--- a/man/man1/rio.1
+++ b/man/man1/rio.1
@@ -73,13 +73,11 @@
 .IR xterm (1).
 The
 .B \-s
-option causes
-.I rio
-to add
-.B -s
-to
-.IR 9term 's
-command-line, starting the window in scrolling mode.
+option has no effect.  It formerly set the scrolling mode for
+new windows and is recognized to avoid breaking scripts.
+See
+.IR 9term (1)
+for a description of scrolling behavior.
 .PP
 The
 .B \-version
diff --git a/man/man4/acme.4 b/man/man4/acme.4
index 40cde75..78214ca 100644
--- a/man/man4/acme.4
+++ b/man/man4/acme.4
@@ -236,22 +236,11 @@
 .B Undo
 interactive command.
 .TP
-.B noscroll
-Turn off automatic `scrolling' of the window to show text written to the body.
-.TP
 .B put
 Equivalent to the
 .B Put
 interactive command with no arguments; accepts no arguments.
 .TP
-.B scroll
-Cancel a
-.B noscroll
-message, returning the window to the default state wherein each write
-to the
-.B body
-file causes the window to `scroll' to display the new text.
-.TP
 .B show
 Guarantee at least some of the selected text is visible on the display.
 .RE
diff --git a/src/cmd/9term/9term.c b/src/cmd/9term/9term.c
index 806215d..344a7b5 100644
--- a/src/cmd/9term/9term.c
+++ b/src/cmd/9term/9term.c
@@ -67,7 +67,7 @@
 		fontname = EARGF(usage());
 		break;
 	case 's':
-		scrolling = TRUE;
+		/* no-op */
 		break;
 	case 'c':
 		cooked = TRUE;
@@ -114,7 +114,7 @@
 	timerinit();
 	servedevtext();
 	rcpid = rcstart(argc, argv, &rcfd, &sfd);
-	w = new(screen, FALSE, scrolling, rcpid, ".", nil, nil);
+	w = new(screen, FALSE, rcpid, ".", nil, nil);
 
 	threadcreate(keyboardthread, nil, STACK);
 	threadcreate(mousethread, nil, STACK);
@@ -241,7 +241,7 @@
 }
 
 Window*
-new(Image *i, int hideit, int scrollit, int pid, char *dir, char *cmd, char **argv)
+new(Image *i, int hideit, int pid, char *dir, char *cmd, char **argv)
 {
 	Window *w;
 	Mousectl *mc;
@@ -258,7 +258,7 @@
 	*mc = *mousectl;
 /*	mc->image = i; */
 	mc->c = cm;
-	w = wmk(i, mc, ck, cctl, scrollit);
+	w = wmk(i, mc, ck, cctl);
 	free(mc);	/* wmk copies *mc */
 	window = erealloc(window, ++nwindow*sizeof(Window*));
 	window[nwindow-1] = w;
@@ -288,7 +288,6 @@
 	Snarf,
 	Plumb,
 	Send,
-	Scroll,
 	Cook
 };
 
@@ -298,7 +297,6 @@
 	"snarf",
 	"plumb",
 	"send",
-	"scroll",
 	"cook",
 	nil
 };
@@ -317,10 +315,6 @@
 	if(w->deleted)
 		return;
 	incref(&w->ref);
-	if(w->scrolling)
-		menu2str[Scroll] = "noscroll";
-	else
-		menu2str[Scroll] = "scroll";
 	if(cooked)
 		menu2str[Cook] = "nocook";
 	else
@@ -364,11 +358,6 @@
 		wsetselect(w, w->nr, w->nr);
 		wshow(w, w->nr);
 		break;
-
-	case Scroll:
-		if(w->scrolling ^= 1)
-			wshow(w, w->nr);
-		break;
 	
 	case Cook:
 		cooked ^= 1;
diff --git a/src/cmd/9term/dat.h b/src/cmd/9term/dat.h
index bc6d1fc..052f3b8 100644
--- a/src/cmd/9term/dat.h
+++ b/src/cmd/9term/dat.h
@@ -131,7 +131,6 @@
 	Rectangle		lastsr;
 	int			topped;
 	int			notefd;
-	uchar		scrolling;
 	Cursor		cursor;
 	Cursor		*cursorp;
 	uchar		holding;
@@ -149,7 +148,7 @@
 void		winctl(void*);
 void		winshell(void*);
 Window*	wlookid(int);
-Window*	wmk(Image*, Mousectl*, Channel*, Channel*, int);
+Window*	wmk(Image*, Mousectl*, Channel*, Channel*);
 Window*	wpointto(Point);
 Window*	wtop(Point);
 void		wtopme(Window*);
diff --git a/src/cmd/9term/fns.h b/src/cmd/9term/fns.h
index a0ae686..cdb5ff6 100644
--- a/src/cmd/9term/fns.h
+++ b/src/cmd/9term/fns.h
@@ -6,7 +6,7 @@
 int	wunhide(int);
 void	freescrtemps(void);
 int	parsewctl(char**, Rectangle, Rectangle*, int*, int*, int*, int*, char**, char*, char*);
-Window *new(Image*, int, int, int, char*, char*, char**);
+Window *new(Image*, int, int, char*, char*, char**);
 void	riosetcursor(Cursor*, int);
 int	min(int, int);
 int	max(int, int);
diff --git a/src/cmd/9term/win.c b/src/cmd/9term/win.c
index 93dc770..fd8e399 100644
--- a/src/cmd/9term/win.c
+++ b/src/cmd/9term/win.c
@@ -181,7 +181,7 @@
 	putenv("winid", buf);
 	sprint(buf, "%d/tag", id);
 	fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
-	write(fd, " Send Noscroll", 1+4+1+8);
+	write(fd, " Send", 1+4);
 	close(fd);
 	sprint(buf, "%d/event", id);
 	eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
@@ -440,14 +440,6 @@
 				}
 				char buf[100];
 				snprint(buf, sizeof buf, "%.*S", e.nr, e.r);
-				if(cistrcmp(buf, "scroll") == 0) {
-					fsprint(ctlfd, "scroll\nshow");
-					break;
-				}
-				if(cistrcmp(buf, "noscroll") == 0) {
-					fsprint(ctlfd, "noscroll");
-					break;
-				}
 				if(cistrcmp(buf, "cook") == 0) {
 					cook = 1;
 					break;
diff --git a/src/cmd/9term/wind.c b/src/cmd/9term/wind.c
index 4cc9c20..aa7c828 100644
--- a/src/cmd/9term/wind.c
+++ b/src/cmd/9term/wind.c
@@ -36,7 +36,7 @@
 static	Image	*paleholdcol;
 
 Window*
-wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl, int scrolling)
+wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl)
 {
 	Window *w;
 	Rectangle r;
@@ -77,7 +77,6 @@
 	w->topped = ++topped;
 	w->id = ++id;
 	w->notefd = -1;
-	w->scrolling = scrolling;
 	w->dir = estrdup(startdir);
 	w->label = estrdup("<unnamed>");
 	r = insetrect(w->i->r, Selborder);
@@ -192,7 +191,7 @@
 {
 	Rune *rp, *bp, *up, *kbdr;
 	uint qh;
-	int nr, nb, c, wid, i, npart, initial, lastb;
+	int nr, nb, c, wid, i, npart, initial, lastb, scrolling;
 	char *s, *t, part[UTFmax];
 	Window *w;
 	Mousestate *mp, m;
@@ -248,10 +247,7 @@
 			alts[WMouseread].op = CHANSND;
 		else
 			alts[WMouseread].op = CHANNOP;
-		if(!w->scrolling && !w->mouseopen && w->qh>w->org+w->f.nchars)
-			alts[WCwrite].op = CHANNOP;
-		else
-			alts[WCwrite].op = CHANSND;
+		alts[WCwrite].op = CHANSND;
 		if(w->deleted || !w->wctlready)
 			alts[WWread].op = CHANNOP;
 		else
@@ -369,8 +365,9 @@
 				w->qh = qh;
 			}
 			nr = up - rp;
+			scrolling = w->org <= w->qh && w->qh <= w->org + w->f.nchars;
 			w->qh = winsert(w, rp, nr, w->qh)+nr;
-			if(w->scrolling || w->mouseopen)
+			if(scrolling)
 				wshow(w, w->qh);
 			wsetselect(w, w->q0, w->q1);
 			wscrdraw(w);
diff --git a/src/cmd/acme/dat.h b/src/cmd/acme/dat.h
index b15395f..300ba65 100644
--- a/src/cmd/acme/dat.h
+++ b/src/cmd/acme/dat.h
@@ -243,7 +243,6 @@
 	Range	limit;
 	uchar	nopen[QMAX];
 	uchar	nomark;
-	uchar	noscroll;
 	Range	wrselrange;
 	int		rdselfd;
 	Column	*col;
diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c
index a71b5b4..ad4da00 100644
--- a/src/cmd/acme/exec.c
+++ b/src/cmd/acme/exec.c
@@ -960,6 +960,7 @@
 	if(textreadc(t, t->file->b.nc-1) != '\n'){
 		textinsert(t, t->file->b.nc, Lnl, 1, TRUE);
 		textsetselect(t, t->file->b.nc, t->file->b.nc);
+		textshow(t, t->q1, t->q1, 1);
 	}
 }
 
diff --git a/src/cmd/acme/xfid.c b/src/cmd/acme/xfid.c
index db5d54b..18b06dd 100644
--- a/src/cmd/acme/xfid.c
+++ b/src/cmd/acme/xfid.c
@@ -510,8 +510,8 @@
 		if(tq1 >= q0)
 			tq1 += nr;
 		textsetselect(t, tq0, tq1);
-		if(!t->w->noscroll)
-			textshow(t, q0, q0+nr, 0);
+		if(t->org <= q0 && q0 <= t->org+t->fr.nchars)
+			textshow(t, q0+nr, q0+nr, 0);
 		textscrdraw(t);
 		winsettag(w);
 		free(r);
@@ -568,7 +568,7 @@
 				}
 				q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
 				textsetselect(t, t->q0, t->q1);	/* insert could leave it somewhere else */
-				if(qid!=QWwrsel && !t->w->noscroll)
+				if(qid!=QWwrsel && t->org <= q0 && q0 < t->org+t->fr.nchars)
 					textshow(t, q0+nr, q0+nr, 1);
 				textscrdraw(t);
 			}
@@ -768,18 +768,10 @@
 			w->filemenu = TRUE;
 			m = 4;
 		}else
-		if(strncmp(p, "noscroll", 8) == 0){	/* turn off automatic scrolling */
-			w->noscroll = TRUE;
-			m = 8;
-		}else
 		if(strncmp(p, "cleartag", 8) == 0){	/* wipe tag right of bar */
 			wincleartag(w);
 			settag = TRUE;
 			m = 8;
-		}else
-		if(strncmp(p, "scroll", 6) == 0){	/* turn on automatic scrolling (writes to body only) */
-			w->noscroll = FALSE;
-			m = 6;
 		}else{
 			err = Ebadctl;
 			break;