[comp.sources.misc] v02i055: Diffs for a tag stack in vi

michael@garfield.UUCP (Mike Rendell) (02/11/88)

Comp.sources.misc: Volume 2, Issue 55
Submitted-By: "Mike Rendell" <michael@garfield.UUCP>
Archive-Name: vi-tag-stack

[I held on to this while trying to post to comp.bugs.4bsd on r$'s suggestion.
Alas, ncoast never heard of it and our news admin isn't interested.  ++bsa]

After using vi on the sun, which has a tag stack, I decided to hack it into
our vaxen's vi (4.3bsd).  The following are the resulting patches for
ex_tagio.c, ex_vmain.c, ex_cmds.c and ex_cmdsub.c.

For those of you who don't have suns and don't know what I'm talking about
[and probably most of you with suns, as this feature seems to be
undocumented] this is what the tag stack does:  When you tag something, your
current file (and your current position) are saved on a stack.  When you
want to get back to the previous file(s) you hit ^T.  This is similar to
^^ except that you can go back multiple levels.  Also I have added a ":push"
command that acts like ":next" except that it pushes the current file on the
tag stack. ":pop" is the same as ^T (really visa versa, for those who know
how vi does these things...). By the way, ^T can take a count to indicate
how many levels to pop.

This feature is invaluable when poking around large programs with many
source files.

				Mike Rendell
				cdnnet: michael@garfield.mun.cdn
				uucp: michael@garfield
					{uunet,utai}!garfield!michael

Index: ex_tagio.c

*** /tmp/,RCSt1014586	Thu Nov  5 17:45:30 1987
--- /tmp/,RCSt2014586	Thu Nov  5 17:45:34 1987
***************
*** 14,19 ****
--- 14,23 ----
  
  #include <sys/file.h>
  #include "ex.h"
+ #ifdef	TAGSTACK
+ #include "ex_temp.h"
+ #include "ex_vis.h"
+ #endif	/* TAGSTACK */
  
  static long offset = -1;
  static long block = -1;
***************
*** 102,105 ****
--- 106,242 ----
  	block = -1;
  	bcnt = 0;
  }
+ # ifdef	TAGSTACK
+ 
+ #define	TSTACKMEMSIZE	(10*1024)		/* 10k should suffice */
+ 
+ typedef struct tstack_str Tstack;
+ struct tstack_str {
+ 	char	*t_file;
+ 	line	t_dot;
+ 	int	t_cursor;
+ 	Tstack	*t_prev;
+ };
+ 
+ int		tstack_cnt = 1;
+ static char	tstack_mem[TSTACKMEMSIZE];
+ static char	*tstack_ptr = tstack_mem;
+ static Tstack	*tstack = (Tstack *) 0;
+ 
+ /*
+  * save current file/lineno/cursor
+  */
+ tag_push(fname)
+ 	char	*fname;
+ {
+ 	int		len;
+ 	Tstack		*tp;
+ 
+ 	/* Don't bother if there is no current file */
+ 	if (fname[0] == '\0')
+ 		return;
+ 
+ 	/* See how much space we will need */
+ 	len = sizeof(Tstack) + strlen(fname) + 1;
+ 	/* keep things word aligned */
+ 	len += len & 3;
+ 	if (tstack_ptr + len >= &tstack_mem[TSTACKMEMSIZE]) {
+ 		lprintf("[Tag stack full] ");
+ 		return;
+ 	}
+ 	tp = (Tstack *) tstack_ptr;
+ 	tp->t_prev = tstack;
+ 	tp->t_file = tstack_ptr + sizeof(Tstack);
+ 	(void) strcpy(tp->t_file, fname);
+ 	tp->t_dot = lineDOT();
+ 	tp->t_cursor = inopen ? cursor - linebuf : 0;
+ 	tstack_ptr += len;
+ 	tstack = tp;
+ }
+ 
+ tag_pop(bang)
+ 	int	bang;
+ {
+ 	Tstack		*tp;
+ 	line		*addr;
+ 	bool		samef = 1;
+ 	int		i;
+ 
+ 	/* Do this first so tstack_cnt will be reset regardless */
+ 	i = tstack_cnt;
+ 	tstack_cnt = 1;
+ 
+ 	if (!tstack)
+ 		error("Tag stack empty");
+ 
+ 	for (tp = tstack ; --i > 0 && tp ; tp = tp->t_prev)
+ 		;
+ 	if (!tp)
+ 		error("Tag stack not that deep");
+ 
+ 	if (strcmp(tp->t_file, savedfile) || !edited) {
+ 		char cmdbuf2[sizeof(savedfile) + 10];
+ 		char *oglobp;
+ 		int omagic;
+ 		char opeek;
+ 
+ 		if (!bang) {
+ 			ckaw();
+ 			if (chng && dol > zero)
+ 				error("No write@since last change (:pop! overrides)");
+ 		}
+ 		omagic = value(MAGIC);
+ 		oglobp = globp;
+ 		strcpy(cmdbuf2, "e! ");
+ 		strcat(cmdbuf2, tp->t_file);
+ 		globp = cmdbuf2;
+ 		opeek = peekc; ungetchar(0);
+ 		commands(1, 1);
+ 		peekc = opeek;
+ 		globp = oglobp;
+ 		value(MAGIC) = omagic;
+ 		samef = 0;
+ 	}
+ 	/*
+ 	 * Update these now that we know everything is ok
+ 	 */
+ 	tstack = tp->t_prev;
+ 	tstack_ptr = (char *) tp;
+ 
+ 	/*
+ 	 *	Try to find the line that we were on
+ 	 */
+ 	addr = zero + tp->t_dot;
+ 
+ 	/*
+ 	 *	Line is gone?
+ 	 */
+ 	if (addr <= zero || addr > dol)
+ 		addr = one;
+ 	/*
+ 	 * Try to find position on the line
+ 	 */
+ 	if (inopen) {
+ 		char	*s;
+ 
+ 		if (samef && addr != dot)
+ 			markDOT();
+ 		getline(*addr);
+ 		s = linebuf + (inopen ? tp->t_cursor : 0);
+ 		if (s >= linebuf && s < strend(linebuf)) {
+ 			char	tbuf[8]; /* 001024 (max line) + ' ' + \0 */
+ 
+ 			if (s != linebuf)
+ 				(void) sprintf(tbuf, "00%d ", s - linebuf);
+ 			else
+ 				tbuf[0] = '0', tbuf[1] = '0', tbuf[2] = '\0';
+ 			macpush(tbuf, 0);
+ 		}
+ 	}
+ 	dot = addr;
+ 	if (ospeed > B300)
+ 		hold |= HOLDWIG;
+ 	return;
+ }
+ # endif	TAGSTACK
  #endif

Index: ex_cmds.c

*** /tmp/,RCSt1014564	Thu Nov  5 17:45:06 1987
--- /tmp/,RCSt2014564	Thu Nov  5 17:45:19 1987
***************
*** 410,418 ****
  		case 'P':
  			switch (peekchar()) {
  
- /* put */
  			case 'u':
  				tail("put");
  				setdot();
  				c = cmdreg();
  				eol();
--- 410,439 ----
  		case 'P':
  			switch (peekchar()) {
  
  			case 'u':
+ #ifdef	TAGSTACK
+ /* push */
+ 				ignchar();
+ 				if (peekchar() == 's') {
+ 					tail2of("push");
+ 					setnoaddr();
+ 					ckaw();
+ 					ignore(quickly());
+ 					if (getargs())
+ 						makargs();
+ 					next();
+ 					tag_push(altfile);
+ 					c = 'e';
+ 					filename(c);
+ 					goto doecmd;
+ 
+ 				}
+ /* put */
+ 				tail2of("put");
+ #else	/* TAGSTACK */
+ /* put */
  				tail("put");
+ #endif	/* TAGSTACK */
  				setdot();
  				c = cmdreg();
  				eol();
***************
*** 437,442 ****
--- 458,482 ----
  				tail2of("print");
  				break;
  
+ #ifdef	TAGSTACK	
+ 			case 'o':
+ /* pop */
+ 				{
+ 					int	bang;
+ 
+ 					tail("pop");
+ 					setnoaddr();
+ 					bang = exclam();
+ 					eol();
+ 					tag_pop(bang);
+ 					if (!inopen)
+ 						lchng = chng - 1;
+ 					else
+ 						nochng();
+ 					continue;
+ 				}
+ #endif	TAGSTACK
+ 	
  			default:
  				tail("print");
  				break;

Index: ex_cmdsub.c

*** /tmp/,RCSt1014573	Thu Nov  5 17:45:40 1987
--- /tmp/,RCSt2014573	Thu Nov  5 17:45:54 1987
***************
*** 623,628 ****
--- 623,631 ----
  				}
  			}
  			strcpy(cmdbuf, cp);
+ #ifdef	TAGSTACK
+ 			tag_push(savedfile);
+ #endif	/* TAGSTACK */
  			if (strcmp(filebuf, savedfile) || !edited) {
  				char cmdbuf2[sizeof filebuf + 10];
  

Index: ex_vmain.c

*** /tmp/,RCSt1014581	Thu Nov  5 17:45:46 1987
--- /tmp/,RCSt2014581	Thu Nov  5 17:46:02 1987
***************
*** 844,850 ****
--- 844,866 ----
  				globp = "e #";
  			goto gogo;
  
+ #ifdef	TAGSTACK
  		/*
+ 		 *	Pop a tag off the stack
+ 		 */
+ 		case CTRL(t):
+ 			if (hadcnt) {
+ 				extern int tstack_cnt;
+ 
+ 				tstack_cnt = cnt;
+ 			}
+ 			vsave();
+ 			oglobp = globp;
+ 			globp = "pop";
+ 			goto gogo;
+ #endif	/* TAGSTACK */
+ 
+ 		/*
  		 * ^]		Takes word after cursor as tag, and then does
  		 *		tag command.  Read ``go right to''.
  		 */