9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* Re: [9fans] The VT saga
@ 2000-09-11  9:41 lucio
  2000-11-07 14:32 ` Micah Stetson
  0 siblings, 1 reply; 9+ messages in thread
From: lucio @ 2000-09-11  9:41 UTC (permalink / raw)
  To: 9fans; +Cc: lucio

[-- Attachment #1: Type: text/plain, Size: 3698 bytes --]

On Sun, Sep 10, 2000 at 19:05:36 (+0200), Lucio De Re wrote:
> 
> I see there's another point of confusion.  It seems that after
> resizing (I used hide-and-restore, at first, but actual resizing
> has a similar effect), the emulator reports three columns more
> than are actually represented.
> 
I eventually tracked that one down to some wishful thinking in SSH: at
resize time, the screen text dimensions are computed directly from the
screen bitsize, which omits the margin and border values.

In the process of determining where the problem lay and how to fix it,
I changed a few bits in VT that may or may not have needed changing.
I _think_ the result is tidier, but I may have fidgetted with things
that would have been best left alone.

The rationale was that constant "INSET" could easily be identified
with "Borderwidth" (defined in draw.h) and could thus be dismissed - I
left the definition in "cons.h", but it can be removed.  I also
decided that the screen area should include the borderwidth and
simplified the "r.max" assignment accordingly, the new version is
practically identical to the original in spirit.

If opening "/dev/wctl" or writing to it does not work - note that I
removed the Borderwidth offset from the "fprint()" - then presumably
VT is expected to draw its own border, where, again "Borderwidth"
seems a useful replacement for "INSET" (I appreciate - or, better,
don't appreciate :-) - that "INSET" has value "3" while "Borderwidth"
has value "4").  More to ensure that we don't make mistakes (redundant
occurrences of constants can lead to errors, here 79/80 and 23/24 are
involved) I caused "xmax" and "ymax" to be re-evaluated.  Its only
real advantage is that now the menu entry values need to be changed in
one place (well, OK, two places).  I suppose I should go to the
trouble of calculating that first menu entry from two compile-time
constants, it would not be hard.

I did that, too, please be gentle with the criticism, I'm sure I
haven't quite got Bell Labs' philosophy down pat :-)

The changes in SSH are also pretty minute.  The rationale here is that
the environment should be queried instead of calculating the text
dimensions of the screen on resizing the window (which also occurs
when the window is restored from a HIDE command).  There is already a
facility to query the environment with a default value in the SSH
code, so it was easy to rope that into the task, thus changing things
as little as possible.

Unfortunately, that did not quite suffice, in fact it caused some
hassles, as it managed to query the environment _before_ VT got around
to changing it (VT does a deferred "resize()" rather than respond
immediately).

I added a 200ms delay between reading the "/dev/wctl" device and
notifying the remote host of the change.  I'm not sure if the
deferring in VT may linger beyond this limit, in which case it may be
essential to do deferred processing of window resizing (ouch, that
would be a bit painful!)  in SSH as well.

I take it (on faith, I haven't tested this) that the undocumented
operation of "/dev/wclt" on READ is to return the current dimension of
the window then block until a window change occurs.  I think that is
remarkably elegant: the simplicity with which one can handle window
resizing in such a situation is a thing of beauty, a masterpiece,
(insert own superlatives here)...

I see it is documented in the newer rio(4) man page; my admiration to
the inventor.

I include the changes, wdiffs based on the July 17th release, to
/sys/src/cmd/VT and /sys/src/cmd/SSH for inspection and inclusion (if
so desired) in the next release.

++L


[-- Attachment #2: Type: message/rfc822, Size: 2295 bytes --]


diff -n /mnt/wrap/sys/src/cmd/vt/main.c /sys/src/cmd/vt/main.c
/mnt/wrap/sys/src/cmd/vt/main.c:8 a /sys/src/cmd/vt/main.c:9,11
> #define		LINES	(24)		/* menu selection */
> #define		COLS	(80)
> 
/mnt/wrap/sys/src/cmd/vt/main.c:462 a /sys/src/cmd/vt/main.c:466
> 	char buf[12];
/mnt/wrap/sys/src/cmd/vt/main.c:464 a /sys/src/cmd/vt/main.c:469,470
> 		snprint (buf, sizeof(buf), "%dx%d", LINES, COLS);
> 		menu3.item[0] = buf;
/mnt/wrap/sys/src/cmd/vt/main.c:470 c /sys/src/cmd/vt/main.c:476
< 		case 0:		/* 24x80 */
---
> 		case 0:		/* LINESxCOLS */
/mnt/wrap/sys/src/cmd/vt/main.c:472,474 c /sys/src/cmd/vt/main.c:478
< 			r.max = addpt(screen->r.min,
< 				Pt(80*CW+2*XMARGIN+2*INSET,
< 				24*NS+2*YMARGIN+2*INSET));
---
> 			r.max = addpt(r.min, Pt(COLS*CW+2*(XMARGIN+Borderwidth), LINES*NS+2*(YMARGIN+Borderwidth)));
/mnt/wrap/sys/src/cmd/vt/main.c:476,479 c /sys/src/cmd/vt/main.c:480,486
< 			if(fd < 0 || fprint(fd, "resize -dx %d -dy %d\n", Dx(r)+2*Borderwidth, Dy(r)+2*Borderwidth) < 0){
< 				border(screen, r, INSET, bordercol, ZP);
< 				xmax = 79;
< 				ymax = 23;
---
> 			if(fd < 0 || fprint(fd, "resize -dx %d -dy %d\n", Dx(r), Dy(r)) < 0){
> 				// r.max = addpt(r.max, Pt(Borderwidth, Borderwidth));
> 				border(screen, r, Borderwidth, bordercol, ZP);
> 				// xmax = 79;
> 				// ymax = 23;
> 				xmax = (Dx(screen->r)-2*XMARGIN)/CW-1;
> 				ymax = (Dy(screen->r)-2*YMARGIN)/NS-1;
/mnt/wrap/sys/src/cmd/vt/main.c:577 c /sys/src/cmd/vt/main.c:584
< 	draw(screen, Rpt(pt(0, dy), pt(xmax+1, ly-sy)), screen, nil, pt(0, sy));
---
> 	draw(screen, Rpt(pt(0, dy), pt(xmax+1, ly+1)), screen, nil, pt(0, sy));
diff -n /mnt/wrap/sys/src/cmd/ssh/cmd/client_io.c /sys/src/cmd/ssh/cmd/client_io.c
/mnt/wrap/sys/src/cmd/ssh/cmd/client_io.c:302 a /sys/src/cmd/ssh/cmd/client_io.c:303
> 		sleep (200);
diff -n /mnt/wrap/sys/src/cmd/ssh/cmd/client_messages.c /sys/src/cmd/ssh/cmd/client_messages.c
/mnt/wrap/sys/src/cmd/ssh/cmd/client_messages.c:507,508 c /sys/src/cmd/ssh/cmd/client_messages.c:507,508
< 	putlong(packet, height/cheight);	/* rows */
< 	putlong(packet, width/cwidth);	/* columns */
---
> 	putlong(packet, lines = int_env("LINES", height/cheight));	/* rows */
> 	putlong(packet, cols = int_env("COLS", width/cwidth));	/* columns */

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] The VT saga
  2000-09-11  9:41 [9fans] The VT saga lucio
@ 2000-11-07 14:32 ` Micah Stetson
  0 siblings, 0 replies; 9+ messages in thread
From: Micah Stetson @ 2000-11-07 14:32 UTC (permalink / raw)
  To: 9fans

[-- Attachment #1: Type: text/plain, Size: 1228 bytes --]

I took a look at vt tonight and while vttest still just turns
up its nose at me, it looks like I've eliminated most of the
real problems I had with Mutt and vi.  There are mainly
three changes.

First, I finally think I've got scroll() right.  Lucio's
previous patch said
> /mnt/wrap/sys/src/cmd/vt/main.c:577 c /sys/src/cmd/vt/main.c:584
> < 	draw(screen, Rpt(pt(0, dy), pt(xmax+1, ly-sy)), screen, nil, pt(0, sy));
> ---
> > 	draw(screen, Rpt(pt(0, dy), pt(xmax+1, ly+1)), screen, nil, pt(0, sy));
but it should really have dy+ly-sy in there.

Second, I made the delete to end of line and delete to end of
screen stuff work like the vt100 user's guide says it should.

Last, I changed yscrmin and yscrmax so that they are always the
beginning and end of the scrolling region even when that region
is the whole screen.  That got rid of a bunch of lines that
looked like
	M = yscrmax ? yscrmax : ymax;
Maybe there was a good reason for doing it the other way, but
I don't see it.

Anyway, attached are my current in-progress versions of vt.c
and main.c from /sys/src/cmd/vt.  They do not include the
patch Lucio posted to this list a few weeks back.  I hope
this is helpful to somebody.

Micah



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: main.c --]
[-- Type: text/x-csrc, Size: 12856 bytes --]

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <bio.h>
#include <keyboard.h>
#include "cons.h"

enum{
	Ehost		= 4,
};

char	*menutext2[] = {
	"backup",
	"forward",
	"reset",
	"clear",
	"send",
	"page",
	0
};

char	*menutext3[] = {
	"24x80",
	"crnl",
	"nl",
	"raw",
	0
};

/* variables associated with the screen */

int	x, y;	/* character positions */
char	*backp;
int	backc;
int	atend;
int	nbacklines;
int	xmax, ymax;
int	blocked;
int	resize_flag;
int	pagemode;
int	olines;
int	peekc;
Menu	menu2;
Menu	menu3;
char	*histp;
char	hist[HISTSIZ];
int	yscrmin, yscrmax;

Image	*text;
Image	*background;
Image	*bordercol;
Image	*cursback;
Image	*red;

/* terminal control */
struct ttystate ttystate[2] = { {0, 1}, {0,0} };

int	NS;
int	CW;
Consstate *cs;
Mouse	mouse;

int	outfd = -1;
Biobuf	*snarffp = 0;

char	*host_buf;
char	*hostp;			/* input from host */
int	host_bsize = 2*BSIZE;
int	hostlength;			/* amount of input from host */
char	echo_input[BSIZE];
char	*echop = echo_input;	/* characters to echo, after canon */
char	sendbuf[BSIZE];	/* hope you can't type ahead more than BSIZE chars */
char	*sendp = sendbuf;

/* functions */
void	initialize(int, char **);
void	ebegin(int);
int	waitchar(void);
int	rcvchar(void);
void	set_input(char *);
void	set_host(Event *);
void	bigscroll(void);
void	readmenu(void);
void	eresized(int);
void	resize(void);
void	send_interrupt(void);
int	alnum(int);
void	escapedump(int,uchar *,int);
char *term;
struct funckey *fk;

int	debug;

void
main(int argc, char **argv)
{
	initialize(argc, argv);
	emulate();
}

void
initialize(int argc, char **argv)
{
	int dayglo = 1;

	rfork(RFENVG|RFNAMEG|RFNOTEG);

	term = "vt100";
	fk = vt100fk;
	ARGBEGIN{
	case '2':
		term = "vt220";
		fk = vt220fk;
		break;
	case 's': /* for sape */
		dayglo = 0;
		break;
	}ARGEND;

	host_buf = malloc(host_bsize);
	hostp = host_buf;
	hostlength = 0;

	if(initdraw(0,0,term) < 0){
		fprint(2, "%s: initdraw failed: %r\n", term);
		exits("initdraw");
	}
	ebegin(Ehost);

	histp = hist;
	menu2.item = menutext2;
	menu3.item = menutext3;
	pagemode = 0;
	blocked = 0;
	NS = font->height ;
	CW = stringwidth(font, "m");
	text = allocimage(display, Rect(0,0,1,1), screen->chan, 1, dayglo?0x00F0F0F0:0);
	background = allocimage(display, Rect(0,0,1,1), screen->chan, 1, dayglo?0x33333333:-1);
	bordercol = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCCC);
	cursback = allocimage(display, Rect(0, 0, CW+1, NS+1), screen->chan, 0, DNofill);
	red =  allocimage(display, Rect(0, 0, CW+1, NS+1), screen->chan, 1, DRed);

	eresized(0);

	if(argc > 0) {
		sendnchars(strlen(argv[0]),argv[0]);
		sendnchars(1,"\n");
	}
}

void
clear(Rectangle r)
{
	draw(screen, r, background, nil, ZP);
}

void
newline(void)
{
	nbacklines--;
	if(y >= yscrmax) {
		y = yscrmax;
		if(pagemode && olines >= yscrmax) {
			blocked = 1;
			return;
		}
		scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
	} else
		y++;
	olines++;
}

void
curson(int bl)
{
	Image *col;

	draw(cursback, cursback->r, screen, nil, subpt(pt(x, y),Pt(1,1)));
	if(bl)
		col = red;
	else
		col = bordercol;
	border(screen, Rpt(subpt(pt(x, y), Pt(1, 1)), addpt(pt(x, y), Pt(CW,NS))),
		2, col, ZP);
}

void
cursoff(void)
{
	draw(screen, Rpt(subpt(pt(x, y), Pt(1, 1)), addpt(pt(x, y), Pt(CW,NS))),
		cursback, nil, cursback->r.min);
}

int
get_next_char(void)
{
	int c = peekc;
	peekc = 0;
	if(c > 0)
		return(c);
	while(c <= 0) {
		if(backp) {
			c = *backp;
			if(c && nbacklines >= 0) {
				backp++;
				if(backp >= &hist[HISTSIZ])
					backp = hist;
				return(c);
			}
			backp = 0;
		}
		c = waitchar();
	}
	*histp++ = c;
	if(histp >= &hist[HISTSIZ])
		histp = hist;
	*histp = '\0';
	return(c);
}

int
canon(char *ep, int c)
{
	if(c&0200)
		return(SCROLL);
	switch(c) {
		case '\b':
			if(sendp > sendbuf)
				sendp--;
			*ep++ = '\b';
			*ep++ = ' ';
			*ep++ = '\b';
			break;
		case 0x15:	/* ^U line kill */
			sendp = sendbuf;
			*ep++ = '^';
			*ep++ = 'U';
			*ep++ = '\n';
			break;
		case 0x17:	/* ^W word kill */
			while(sendp > sendbuf && !alnum(*sendp)) {
				*ep++ = '\b';
				*ep++ = ' ';
				*ep++ = '\b';
				sendp--;
			}
			while(sendp > sendbuf && alnum(*sendp)) {
				*ep++ = '\b';
				*ep++ = ' ';
				*ep++ = '\b';
				sendp--;
			}
			break;
		case '\177':	/* interrupt */
			sendp = sendbuf;
			send_interrupt();
			return(NEWLINE);
		case '\021':	/* quit */
		case '\r':
		case '\n':
			if(sendp < &sendbuf[512])
				*sendp++ = '\n';
			sendnchars((int)(sendp-sendbuf), sendbuf);
			sendp = sendbuf;
			if(c == '\n' || c == '\r') {
				*ep++ = '\n';
			}
			*ep = 0;
			return(NEWLINE);
		case '\004':	/* EOT */
			if(sendp == sendbuf) {
				sendnchars(0,sendbuf);
				*ep = 0;
				return(NEWLINE);
			}
			/* fall through */
		default:
			if(sendp < &sendbuf[512])
				*sendp++ = c;
			*ep++ = c;
			break;
		
	}
	*ep = 0;
	return(OTHER);
}

void
sendfk(char *name)
{
	int i;
	static int fd;

	for(i=0; fk[i].name; i++)
		if(strcmp(name, fk[i].name)==0){
			sendnchars2(strlen(fk[i].sequence), fk[i].sequence);
			return;
		}
}

int
waitchar(void)
{
	Event e;
	int c;
	char c2;
	int newmouse;
	int wasblocked;
	int kbdchar = -1;
	char echobuf[3*BSIZE];
	static int lastc = -1;


	for(;;) {
		if(resize_flag)
			resize();
		wasblocked = blocked;
		if(backp)
			return(0);
		if(ecanmouse() && (button2() || button3()))
			readmenu();
		if(snarffp) {
			if((c = Bgetc(snarffp)) < 0) {
				if(lastc != '\n')
					write(outfd,"\n",1);
				Bterm(snarffp);
				snarffp = 0;
				if(lastc != '\n') {
					lastc = -1;
					return('\n');
				}
				lastc = -1;
				continue;
			}
			lastc = c;
			c2 = c;
			write(outfd, &c2, 1);
			return(c);
		}
		if(!blocked && host_avail())
			return(rcvchar());
		if(kbdchar > 0) {
			if(blocked)
				resize();
			if(cs->raw) {
				switch(kbdchar){
				case Kup:
					sendfk("up key");
					break;
				case Kdown:
					sendfk("down key");
					break;
				case Kleft:
					sendfk("left key");
					break;
				case Kright:
					sendfk("right key");
					break;
				default:
					echobuf[0] = kbdchar;
					sendnchars(1, echobuf);
					break;
				}
			} else if(canon(echobuf,kbdchar) == SCROLL) {
				if(!blocked)
					bigscroll();
			} else
				strcat(echo_input,echobuf);
			blocked = 0;
			kbdchar = -1;
			continue;
		}
		curson(wasblocked);	/* turn on cursor while we're waiting */
		do {
			newmouse = 0;
			switch(eread(blocked ? Emouse|Ekeyboard : 
					       Emouse|Ekeyboard|Ehost, &e)) {
			case Emouse:
				mouse = e.mouse;
				if(button2() || button3())
					readmenu();
				else if(resize_flag == 0) {
					/* eresized() is triggered by special mouse event */
					newmouse = 1;
				}
				break;
			case Ekeyboard:
				kbdchar = e.kbdc;
				break;
			case Ehost:
				set_host(&e);
				break;
			default:
				perror("protocol violation");
				exits("protocol violation");
			}
		} while(newmouse == 1);
		cursoff();	/* turn cursor back off */
	}
	return 1;		/* to shut up compiler */
}

void
eresized(int new)
{
	resize_flag = 1+new;
}

void
exportsize(void)
{
	int	fd;
	char	buf[10];

	if((fd = create("/env/LINES", OWRITE, 0644)) > 0) {
		sprint(buf,"%d",ymax+1);
		write(fd,buf,strlen(buf));
		close(fd);
	}
	if((fd = create("/env/COLS", OWRITE, 0644)) > 0) {
		sprint(buf,"%d",xmax+1);
		write(fd,buf,strlen(buf));
		close(fd);
	}
	if((fd = create("/env/TERM", OWRITE, 0644)) > 0) {
		fprint(fd, "%s", term);
		close(fd);
	}
}

void
resize(void)
{
	if(resize_flag > 1 && getwindow(display, Refnone) < 0){
		fprint(2, "can't reattach to window: %r\n");
		exits("can't reattach to window");
	}
	xmax = (Dx(screen->r)-2*XMARGIN)/CW-1;
	ymax = (Dy(screen->r)-2*YMARGIN)/NS-1;
	if(xmax == 0 || ymax == 0)
		exits("window gone");
	x = 0;
	y = 0;
	yscrmin = 0;
	yscrmax = ymax;
	olines = 0;
	exportsize();
	clear(screen->r);
	resize_flag = 0;
}

void
readmenu(void)
{
	Rectangle r;
	int fd;

	if(button3()) {
		menu3.item[1] = ttystate[cs->raw].crnl ? "cr" : "crnl";
		menu3.item[2] = ttystate[cs->raw].nlcr ? "nl" : "nlcr";
		menu3.item[3] = cs->raw ? "cooked" : "raw";

		switch(emenuhit(3, &mouse, &menu3)) {
		case 0:		/* 24x80 */
			r.min = screen->r.min;
			r.max = addpt(screen->r.min,
				Pt(80*CW+2*XMARGIN+2*INSET,
				24*NS+2*YMARGIN+2*INSET));
			fd = open("/dev/wctl", OWRITE);
			if(fd < 0 || fprint(fd, "resize -dx %d -dy %d\n", Dx(r)+2*Borderwidth, Dy(r)+2*Borderwidth) < 0){
				border(screen, r, INSET, bordercol, ZP);
				xmax = 79;
				ymax = 23;
				exportsize();
			}
			if(fd >= 0)
				close(fd);
			return;
		case 1:		/* newline after cr? */
			ttystate[cs->raw].crnl = !ttystate[cs->raw].crnl;
			return;
		case 2:		/* cr after newline? */
			ttystate[cs->raw].nlcr = !ttystate[cs->raw].nlcr;
			return;
		case 3:		/* switch raw mode */
			cs->raw = !cs->raw;
			return;
		}
		return;
	}

	menu2.item[5] = pagemode? "scroll": "page";

	switch(emenuhit(2, &mouse, &menu2)) {

	case 0:		/* back up */
		if(atend == 0) {
			backc++;
			backup(backc);
		}
		return;

	case 1:		/* move forward */
		backc--;
		if(backc >= 0)
			backup(backc);
		else
			backc = 0;
		return;

	case 2:		/* reset */
		backc = 0;
		backup(0);
		return;

	case 3:		/* clear screen */
		eresized(0);
		return;

	case 4:		/* send the snarf buffer */
		snarffp = Bopen("/dev/snarf",OREAD);
		return;

	case 5:		/* pause and clear at end of screen */
		pagemode = 1-pagemode;
		if(blocked && !pagemode) {
			eresized(0);
			blocked = 0;
		}
		return;
	}
}

void
backup(int count)
{
	register n;
	register char *cp;

	eresized(0);
	n = 3*(count+1)*ymax/4;
	cp = histp;
	atend = 0;
	while (n >= 0) {
		cp--;
		if(cp < hist)
			cp = &hist[HISTSIZ-1];
		if(*cp == '\0') {
			atend = 1;
			break;
		}
		if(*cp == '\n')
			n--;
	}
	cp++;
	if(cp >= &hist[HISTSIZ])
		cp = hist;
	backp = cp;
	nbacklines = ymax-2;
}

Point
pt(int x, int y)
{
	return addpt(screen->r.min, Pt(x*CW+XMARGIN,y*NS+YMARGIN));
}

void
scroll(int sy, int ly, int dy, int cy)	/* source, limit, dest, which line to clear */
{
	draw(screen, Rpt(pt(0, dy), pt(xmax+1, dy+ly-sy)), screen, nil, pt(0, sy));
	clear(Rpt(pt(0, cy), pt(xmax+1, cy+1)));
}

void
bigscroll(void)			/* scroll up half a page */
{
	int half = ymax/3;

	if(x == 0 && y == 0)
		return;
	if(y < half) {
		clear(Rpt(pt(0,0),pt(xmax+1,ymax+1)));
		x = y = 0;
		return;
	}
	draw(screen, Rpt(pt(0, 0), pt(xmax+1, ymax+1)), screen, nil, pt(0, half));
	clear(Rpt(pt(0,y-half+1),pt(xmax+1,ymax+1)));
	y -= half;
	if(olines)
		olines -= half;
}

int
number(char *p)
{
	int c, n = 0;

	while ((c = get_next_char()) >= '0' && c <= '9')
		n = n*10 + c - '0';
	*p = c;
	return(n);
}

/* stubs */

void
sendnchars(int n,char *p)
{
	sendnchars2(n, p);
	p[n+1] = 0;
}

void
sendnchars2(int n,char *p)
{
	if(write(outfd,p,n) < 0) {
		close(outfd);
		close(0);
		close(1);
		close(2);
		exits("write");
	}
}

int
host_avail(void)
{
	return(*echop || ((hostp - host_buf) < hostlength));
}

int
rcvchar(void)
{
	int c;
	if(*echop) {
		c = *echop++;
		if(!*echop) {
			echop = echo_input;	
			*echop = 0;
		}
		return c;
	}
	return *hostp++;
}

void
set_host(Event *e)
{
	hostlength = e->n;
	if(hostlength > host_bsize) {
		host_bsize *= 2;
		host_buf = realloc(host_buf,host_bsize);
	}
	hostp = host_buf;
	memmove(host_buf,e->data,hostlength);
	host_buf[hostlength]=0;
}

void
ringbell(void){
}

int
alnum(int c)
{
	if(c >= 'a' && c <= 'z')
		return 1;
	if(c >= 'A' && c <= 'Z')
		return 1;
	if(c >= '0' && c <= '9')
		return 1;
	return 0;
}

void
escapedump(int fd,uchar *str,int len)
{
	int i;

	for(i = 0; i < len; i++) {
		if((str[i] < ' ' || str[i] > '\177') && 
			str[i] != '\n' && str[i] != '\t') fprint(fd,"^%c",str[i]+64);
		else if(str[i] == '\177') fprint(fd,"^$");
		else if(str[i] == '\n') fprint(fd,"^J\n");
		else fprint(fd,"%c",str[i]);
	}
}

void
funckey(int key)
{
	if(key >= NKEYS)
		return;
	if(fk[key].name == 0)
		return;
	sendnchars2(strlen(fk[key].sequence), fk[key].sequence);
}

void
drawstring(Point p, char *str, int standout)
{
	Image *txt, *bg;

	txt = text;
	bg = background;
	if(standout){
		txt = background;
		bg = text;
	}
	draw(screen, Rpt(p, addpt(p, stringsize(font, str))), bg, nil, p);
	string(screen, p, txt, ZP, font, str);
}

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: vt.c --]
[-- Type: text/x-csrc, Size: 9949 bytes --]

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <bio.h>
#include <ctype.h>
#include "cons.h"

struct funckey vt100fk[NKEYS] = {
	{ "up key",		"\033OA", },
	{ "down key",		"\033OB", },
	{ "left key",		"\033OD", },
	{ "right key",		"\033OC", },
};

struct funckey vt220fk[NKEYS] = {
	{ "up key",		"\033[A", },
	{ "down key",		"\033[B", },
	{ "left key",		"\033[D", },
	{ "right key",		"\033[C", },
};

char gmap[256] = {
	['_']	' ',	/* blank */
	['\\']	'*',	/* diamond */
	['a']	'X',	/* checkerboard */
	['b']	'\t',	/* HT */
	['c']	'\x0C',	/* FF */
	['d']	'\r',	/* CR */
	['e']	'\n',	/* LF */
	['f']	'o',	/* degree */
	['g']	'+',	/* plus/minus */
	['h']	'\n',	/* NL, but close enough */
	['i']	'\v',	/* VT */
	['j']	'+',	/* lower right corner */
	['k']	'+',	/* upper right corner */
	['l']	'+',	/* upper left corner */
	['m']	'+',	/* lower left corner */
	['n']	'+',	/* crossing lines */
	['o']	'-',	/* horiz line - scan 1 */
	['p']	'-',	/* horiz line - scan 3 */
	['q']	'-',	/* horiz line - scan 5 */
	['r']	'-',	/* horiz line - scan 7 */
	['s']	'-',	/* horiz line - scan 9 */
	['t']	'+',	/* |-   */
	['u']	'+',	/* -| */
	['v']	'+',	/* upside down T */
	['w']	'+',	/* rightside up T */
	['x']	'|',	/* vertical bar */
	['y']	'<',	/* less/equal */
	['z']	'>',	/* gtr/equal */
	['{']	'p',	/* pi */
	['|']	'!',	/* not equal */
	['}']	'L',	/* pound symbol */
	['~']	'.',	/* centered dot: · */
};

void
emulate(void)
{
	char buf[BUFS+1];
	int n;
	int c;
	int standout;
	int operand, prevOperand;
	int savex, savey;
	int isgraphics;
	int g0set, g1set;

	standout = 0;
	isgraphics = 0;
	g0set = 'B';	/* US ASCII */
	g1set = 'B';	/* US ASCII */
	savex = savey = 0;
	yscrmin = 0;
	yscrmax = ymax;

	for (;;) {
		if (y > ymax) {
			x = 0;
			newline();
		}
		buf[0] = get_next_char();
		buf[1] = '\0';
		switch(buf[0]) {

		case '\000':
		case '\001':
		case '\002':
		case '\003':
		case '\004':
		case '\005':
		case '\006':
			break;

		case '\007':		/* bell */
			ringbell();
			break;

		case '\010':		/* backspace */
			if (x > 0)
				--x;
			break;

		case '\011':		/* tab modulo 8 */
			x = (x|7)+1;
			break;

		case '\012':		/* linefeed */
		case '\013':
		case '\014':
			newline();
			standout = 0;
			if (ttystate[cs->raw].nlcr)
				x = 0;
			break;

		case '\015':		/* carriage return */
			x = 0;
			standout = 0;
			if (ttystate[cs->raw].crnl)
				newline();
			break;

		case '\016':	/* SO: invoke G1 char set */
			isgraphics = (isdigit(g1set));
			break;
		case '\017':	/* SI: invoke G0 char set */
			isgraphics = (isdigit(g0set));
			break;

		case '\020':	/* DLE */
		case '\021':	/* DC1 */
		case '\022':	/* XON */
		case '\023':	/* DC3 */
		case '\024':	/* XOFF */
		case '\025':	/* NAK */
		case '\026':	/* SYN */
		case '\027':	/* ETB */
		case '\030':	/* CAN: cancel escape sequence */
		case '\031':	/* EM: cancel escape sequence, display checkerboard */
		case '\032':	/* SUB: same as CAN */
			break;
		/* ESC, \033, is handled below */
		case '\034':	/* FS */
		case '\035':	/* GS */
		case '\036':	/* RS */
		case '\037':	/* US */
			break;
		case '\177':	/* delete: ignored */
			break;

		case '\033':
			switch(get_next_char()){
			/*
			 * 7 - save cursor position.
			 */
			case '7':
				savex = x;
				savey = y;
				break;

			/*
			 * 8 - restore cursor position.
			 */
			case '8':
				x = savex;
				y = savey;
				break;

			/*
			 * Received c.  Reset terminal.
			 */
			case 'c':
				break;

			/*
			 * Received D.  Active position down a line, scroll if at bottom margin.
			 */
			case 'D':
				if(++y > yscrmax) {
					y = yscrmax;
					scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
				}
				break;

			/*
			 * Received E.  Active position to start of next line, scroll if at bottom margin.
			 */
			case 'E':
				x = 0;
				if(++y > yscrmax) {
					y = yscrmax;
					scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
				}
				break;

			/*
			 * Received M.  Active position up a line, scroll if at top margin..
			 */
			case 'M':
				if(--y < yscrmin) {
					y = yscrmin;
					scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
				}
				break;

			/*
			 * Z - Identification.  The terminal
			 * emulator will return the response
			 * code for a generic VT100.
			 */
			case 'Z':
			Ident:
				sendnchars2(5, "\033[?6c");
				break;

			/*
			 * H - go home. (No, I think this sets a horizontal tab stop.)
			 */
			case 'H':
				// x = y = 0;
				break;

			/*
			 * > - set numeric keypad mode on
			 */
			case '>':
				break;

			/*
			 * = - set numeric keypad mode off
			 */
			case '=':
				break;

			/*
			 * # - Takes a one-digit argument that 
			 * we need to snarf away.
			 */
			case '#':
				get_next_char();
				break;

			/*
			 * ( - switch G0 character set
			 */
			case '(':
				g0set = get_next_char();
				break;

			/*
			 * - switch G1 character set
			 */
			case ')':
				g1set = get_next_char();
				break;

			/*
			 * Received left bracket.
			 */
			case '[':
				/*
				 * A semi-colon or ? delimits arguments.  Only keep one
				 * previous argument (plus the current one) around.
				 */
				operand = number(buf);
				prevOperand = 0;
				while(buf[0] == ';' || buf[0] == '?'){
					prevOperand = operand;
					operand = number(buf);
				}

				/*
				 * do escape2 stuff
				 */
				switch(buf[0]){
					/*
					 * c - same as ESC Z: who are you?
					 */
					case 'c':
						goto Ident;

					/*
					 * l - clear various options.
					 */
					case 'l':
						break;

					/*
					 * h - set various options.
					 */
					case 'h':
						break;

					/*
					 * A - cursor up.
					 */
					case 'A':
						if(operand == 0)
							operand = 1;
						y -= operand;
						if(y < 0)
							y = 0;
						olines -= operand;
						if(olines < 0)
							olines = 0;
						break;

					/*
					 * B - cursor down
					 */
					case 'B':
						if(operand == 0)
							operand = 1;
						y += operand;
						if(y > ymax)
							y=ymax;
						break;
					
					/*
					 * C - cursor right.
					 */
					case 'C':
						if(operand == 0)
							operand = 1;
						x += operand;
						/*
						 * VT-100-UG says not to go past the
						 * right margin.
						 */
						if(x > xmax)
							x=xmax;
						break;

					/*
					 * D - cursor left
					 */
					case 'D':
						if(operand == 0)
							operand = 1;
						x -= operand;
						if(x < 0)
							x = 0;
						break;

					/*
					 * H and f - cursor motion.  operand is the column
					 * and prevOperand is the row, origin 1.
					 */
					case 'H':
					case 'f':
						x = operand - 1;
						if(x < 0)
							x = 0;
						if(x > xmax)
							x = xmax;
						y = prevOperand - 1;
						if(y < 0)
							y = 0;
						if(y > ymax)
							y = ymax;
						break;

					/*
					 * J - clear some or all of the display.
					 */
					case 'J':
						switch (operand) {
							/*
							 * operand 2:  whole screen.
							 */
							case 2:
								clear(Rpt(pt(0, 0), pt(xmax+1, ymax+1)));
								break;
							/*
							 * operand 1: start of screen to active position, inclusive.
							 */
							case 1:
								clear(Rpt(pt(0, 0), pt(x, ymax+1)));
								clear(Rpt(pt(0, y), pt(x+1, y+1)));
								break;
							/*
							 * Default:  active position to end of screen, inclusive.
							 */
							default:
								clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
								clear(Rpt(pt(0, y+1), pt(xmax+1, ymax+1)));
								break;
						}
						break;

					/*
					 * K - clear some or all of the line.
					 */
					case 'K':
						switch (operand) {
							/*
							 * operand 2: whole line.
							 */
							case 2:
								clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
								break;
							/*
							 * operand 1: start of line to active position, inclusive.
							 */
							case 1:
								clear(Rpt(pt(0, y), pt(x+1, y+1)));
								break;
							/*
							 * Default: active position to end of line, inclusive.
							 */
							default:
								clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
								break;
						}
						break;

					/*
					 * L - insert a line at cursor position
					 */
					case 'L':
						scroll(y, yscrmax, y+1, y);
						break;

					/*
					 * M - delete a line at the cursor position
					 */
					case 'M':
						scroll(y+1, yscrmax+1, y, yscrmax);
						break;

					/*
					 * m - change character attributes.
					 *	Attributes are:
					 *	0	Attributes off
					 *	1	Bold or increased intensity
					 *	4	Underscore
					 *	5	Blink
					 *	7	Negative (reverse) image
					 */
					case 'm':
						standout = operand;
						break;

					/*
					 * r - change scrolling region.  prevOperand is
					 * min scrolling region and operand is max
					 * scrolling region.
					 */
					case 'r':
						yscrmin = prevOperand-1;
						yscrmax = operand-1;
						if (yscrmax == 0)
							yscrmax = ymax;
						break;

					/*
					 * Anything else we ignore for now...
					 */
					default:
						break;
				}

				break;

			/*
			 * Ignore other commands.
			 */
			default:
				break;

			}
			break;

		default:		/* ordinary char */
			if(isgraphics && gmap[(uchar) buf[0]])
				buf[0] = gmap[(uchar) buf[0]];

			/* line wrap */
			if (x > xmax){
				x = 0;
				newline();
			}
			n = 1;
			c = 0;
			while (!cs->raw && host_avail() && x+n<=xmax && n<BUFS
			    && (c = get_next_char())>=' ' && c<'\177') {
				buf[n++] = c;
				c = 0;
			}
			buf[n] = 0;
//			clear(Rpt(pt(x,y), pt(x+n, y+1)));
			drawstring(pt(x, y), buf, standout);
			x += n;
			peekc = c;
			break;
		}
	}
}

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] The VT saga
@ 2000-11-10 14:37 presotto
  0 siblings, 0 replies; 9+ messages in thread
From: presotto @ 2000-11-10 14:37 UTC (permalink / raw)
  To: 9fans

I have your diff but I seem to have misplaced your previous
version.  Want to send me a pointer?


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] The VT saga
  2000-11-10  1:05   ` Micah Stetson
@ 2000-11-10  4:14     ` Lucio De Re
  0 siblings, 0 replies; 9+ messages in thread
From: Lucio De Re @ 2000-11-10  4:14 UTC (permalink / raw)
  To: 9fans

On Thu, Nov 09, 2000 at 05:05:30PM -0800, Micah Stetson wrote:
> 
> > Surely Rob should be arbitrator.  I have not had time to look at the
> > patch, but I'd like to point out one issue I have not examined and I
> > don't think the patch addressed: the highlight termination does not work,
> > vt (-2 is what I always use) waits for the end of line to turn highlight
> > off.
> 
> Hmmn, I hadn't paid any attention to vt -2.  I don't have
> the problem without it and not always with it.  Maybe
> there's an unimplemented VT220 escape sequence that does
> that.  Let me grab the manual...  (Incidentally, if you

To answer Presotto's comment (was it private mail?) I bow to superior
knowledge :-)  Micah is doing a spectacular job, and I'm dying to see the
final product.

++L


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] The VT saga
  2000-11-09  4:27 ` Lucio De Re
@ 2000-11-10  1:05   ` Micah Stetson
  2000-11-10  4:14     ` Lucio De Re
  0 siblings, 1 reply; 9+ messages in thread
From: Micah Stetson @ 2000-11-10  1:05 UTC (permalink / raw)
  To: 9fans

[-- Attachment #1: Type: text/plain, Size: 1378 bytes --]

> Surely Rob should be arbitrator.  I have not had time to look at the
> patch, but I'd like to point out one issue I have not examined and I
> don't think the patch addressed: the highlight termination does not work,
> vt (-2 is what I always use) waits for the end of line to turn highlight
> off.

Hmmn, I hadn't paid any attention to vt -2.  I don't have
the problem without it and not always with it.  Maybe
there's an unimplemented VT220 escape sequence that does
that.  Let me grab the manual...  (Incidentally, if you
want a user's guide, you can download one from vt100.net.
They have the manuals for several of the VT models including
the 100 102 and 220.)  Hmmn...It looks like the VT220 uses
some nonzero arguments to the SGR control sequence (ESC[m)
to set certain kinds of standout to off.  The current
implementation will not support this properly.

Attached is a diff against the version of vt.c that I posted
here a couple of days ago.  This is still problematic as it
only handles the last option to the control sequence, but if
I'm going to fix that, I may as well do it for all of the
escape sequences.  Also, it interprets the vt220 options
even when in vt100 mode which it probably shouldn't do, but
it does fix the problem for me.

There's still a lot to fix here, especially in vt220 mode,
so I'll get back to work.

Micah


[-- Attachment #2: vt.c.diff --]
[-- Type: text/plain, Size: 972 bytes --]

56a57,63
> enum SGR {
> 	SGR_BOLD = 1,
> 	SGR_UNDER = 2,
> 	SGR_BLINK = 4,
> 	SGR_NEG = 8,
> };
> 
439a447,451
> 					 *	Also for VT220:
> 					 *	22	Normal intensity
> 					 *	24	Not underlined
> 					 *	25	Not blinking
> 					 *	27	Positive image
442c454,482
< 						standout = operand;
---
> 						switch (operand) {
> 							case 0:
> 								standout = 0;
> 								break;
> 							case 1:
> 								standout |= SGR_BOLD;
> 								break;
> 							case 4:
> 								standout |= SGR_UNDER;
> 								break;
> 							case 5:
> 								standout |= SGR_BLINK;
> 								break;
> 							case 7:
> 								standout |= SGR_NEG;
> 								break;
> 							case 22:
> 								standout &= ~SGR_BOLD;
> 								break;
> 							case 24:
> 								standout &= ~SGR_UNDER;
> 								break;
> 							case 25:
> 								standout &= ~SGR_BLINK;
> 								break;
> 							case 27:
> 								standout &= ~SGR_NEG;
> 								break;
> 						}

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] The VT saga
  2000-11-08 22:57 presotto
@ 2000-11-09  4:27 ` Lucio De Re
  2000-11-10  1:05   ` Micah Stetson
  0 siblings, 1 reply; 9+ messages in thread
From: Lucio De Re @ 2000-11-09  4:27 UTC (permalink / raw)
  To: 9fans

On Wed, Nov 08, 2000 at 05:57:36PM -0500, presotto@plan9.bell-labs.com wrote:
> 
> if you and lucio can agree on a version, I stick it in the distribution.

Surely Rob should be arbitrator.  I have not had time to look at the
patch, but I'd like to point out one issue I have not examined and I
don't think the patch addressed: the highlight termination does not work,
vt (-2 is what I always use) waits for the end of line to turn highlight
off.

I'm going through a bad patch, so Dave please bear with me for a couple
of days.

++L


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] The VT saga
@ 2000-11-08 22:57 presotto
  2000-11-09  4:27 ` Lucio De Re
  0 siblings, 1 reply; 9+ messages in thread
From: presotto @ 2000-11-08 22:57 UTC (permalink / raw)
  To: 9fans

if you and lucio can agree on a version, I stick it in the distribution.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] The VT saga
  2000-09-10 16:25 Lucio De Re
@ 2000-09-10 16:37 ` Lucio De Re
  0 siblings, 0 replies; 9+ messages in thread
From: Lucio De Re @ 2000-09-10 16:37 UTC (permalink / raw)
  To: 9fans mailing list

On Sun, Sep 10, 2000 at 06:25:00PM +0200, Lucio De Re wrote:
> 
> There was no follow up on VT implementation errors.  I fixed one of
> these, leaving two for some other occasion.
> 
I see there's another point of confusion.  It seems that after
resizing (I used hide-and-restore, at first, but actual resizing
has a similar effect), the emulator reports three columns more than
are actually represented.

Composing this message demonstrated it quite effectively, the long
lines lost the three characters at the end of each line, consistently.
I may well be able to identify and fix this problem myself.

++L



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [9fans] The VT saga
@ 2000-09-10 16:25 Lucio De Re
  2000-09-10 16:37 ` Lucio De Re
  0 siblings, 1 reply; 9+ messages in thread
From: Lucio De Re @ 2000-09-10 16:25 UTC (permalink / raw)
  To: 9fans mailing list

There was no follow up on VT implementation errors.  I fixed one of
these, leaving two for some other occasion.

This one was particular annoying as it caused progressively smaller
portions of the screen to get updated, the closer one got to the middle
of the screen, the more obvious its effect became.

In /sys/src/cmd/vt/main.c, the draw() call in scroll() has ly-sy
as the endpoint of the scrolled rectangle.  It should instead be
ly+1.  I'm not sure how the ly-sy got in there, but it does explain
the effect mentioned above.  As you scroll the bottom of the screen
from locations progressively closer to the middle (by either deleting
or inserting a line), the effect is diminished by the "-sy" factor,
where "sy" is y-coordinate of the line at which scroll is intended
to start.  Scroll should not occur at all, when the source line is
below the middle (I'm not going to try this, it seems consistent with
my recollections).

I can't seem to be able to pinpoint where clearing to end of line
fails.  It seems responsible for the bottom line not being cleared,
but apparently only when it is the only line being cleared.  I'd
hazard that it is precisely when _one_ line is being zapped that the
process fails, it is coincidental that this is most obvious on the
bottom line, wait a minute...

Yep, it's the clear to EOP that needs fixing (maybe - opinion sought
on this): in vt.c, I took the "+1" out of the clear to EOP start
point, and the problem seems to have been cured: MUTT now removes the
status line once it no longer applies.

That leaves a lingering highlight: in "less", the filename is highlit
at the end of the first screen; pressing space causes the highlight to
be applied to the line next displayed _over_ the "prompt".  Pity this
is not a feature :-) as it makes a nice indicator of where the
previous screen ended (does anyone remember which NetNews reader - was
it TIN? - used underline to this end?), unfortunately, it affects
trailing highlights in a somewhat arbitrary fashion.

++L



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2000-11-10 14:37 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-09-11  9:41 [9fans] The VT saga lucio
2000-11-07 14:32 ` Micah Stetson
  -- strict thread matches above, loose matches on Subject: below --
2000-11-10 14:37 presotto
2000-11-08 22:57 presotto
2000-11-09  4:27 ` Lucio De Re
2000-11-10  1:05   ` Micah Stetson
2000-11-10  4:14     ` Lucio De Re
2000-09-10 16:25 Lucio De Re
2000-09-10 16:37 ` Lucio De Re

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).