1072 lines
26 KiB
C
1072 lines
26 KiB
C
/* ELLE - Copyright 1982, 1984, 1987 by Ken Harrenstien, SRI International
|
||
* This software is quasi-public; it may be used freely with
|
||
* like software, but may NOT be sold or made part of licensed
|
||
* products without permission of the author.
|
||
*/
|
||
|
||
/* EEBUFF Buffer and Window functions.
|
||
* Each buffer is an independent SB-string described by a
|
||
* buffer structure. All buffer structures are allocated dynamically
|
||
* and chained together starting from buf_head.
|
||
*/
|
||
|
||
#include "elle.h"
|
||
|
||
#if FX_FILLMODE
|
||
extern int fill_mode;
|
||
#endif
|
||
#if FX_SKMAC
|
||
extern int kdef_mode;
|
||
#endif
|
||
|
||
struct buffer *make_buf(), *find_buf(), *sel_mbuf(), *sel_nbuf();
|
||
struct window *make_win();
|
||
|
||
/* EFUN: "Select Buffer" */
|
||
/* Select old buffer or create a new one. Defaults to previously
|
||
* used buffer.
|
||
*/
|
||
f_selbuffer()
|
||
{ register char *ans;
|
||
register struct buffer *b;
|
||
|
||
if((b = last_buf) == cur_buf) /* If default same as current, */
|
||
if(!(b = sel_mbuf(b))) /* try to pick a more useful one. */
|
||
b = sel_nbuf(cur_buf);
|
||
|
||
ans = ask("Select buffer (%s): ",b->b_name);
|
||
if (ans == 0) /* he aborted */
|
||
return;
|
||
if (*ans != '\0') /* Null string => use last buff */
|
||
{ b = find_buf (ans); /* Else find/create one */
|
||
if (b == 0)
|
||
b = make_buf (ans);
|
||
}
|
||
sel_buf(b);
|
||
chkfree(ans);
|
||
}
|
||
|
||
#if FX_SELXBUFFER
|
||
/* EFUN: "Select Existing Buffer" (not EMACS) - from IMAGEN config */
|
||
|
||
static int findstr();
|
||
|
||
f_selxbuffer()
|
||
{ register char *ans;
|
||
register struct buffer *b;
|
||
|
||
b = last_buf; /* This is default */
|
||
ans = ask("Select existing buffer (%s): ", b->b_name);
|
||
if (ans == 0) /* Aborted */
|
||
return;
|
||
if (*ans != 0)
|
||
{ for (b = buf_head; b != 0; b = b->b_next)
|
||
if (findstr(ans, b->b_name))
|
||
break;
|
||
if (b == 0)
|
||
ding("That isn't a substring of any buffer name!");
|
||
}
|
||
chkfree(ans);
|
||
if (b != 0)
|
||
{ saytoo(" => ");
|
||
sayntoo(b->b_name);
|
||
sel_buf(b);
|
||
}
|
||
}
|
||
|
||
static int
|
||
findstr(str, instr) /* Find "str" in string "instr" */
|
||
register char *str, *instr;
|
||
{ register char *sp, *isp;
|
||
|
||
while (*instr)
|
||
{ sp = str;
|
||
isp = instr;
|
||
while (*sp)
|
||
if (*sp++ != *isp++)
|
||
goto next;
|
||
return(1);
|
||
next: ++instr;
|
||
}
|
||
return(0);
|
||
}
|
||
#endif /*FX_SELXBUFFER*/
|
||
|
||
|
||
/* EFUN: "Kill Buffer" */
|
||
/* Kill specified buffer - defaults to current buffer.
|
||
* This code assumes a killed buffer will never be on a window list unless it
|
||
* is pointed to by cur_buf or oth_win->w_buf!!!!
|
||
*/
|
||
f_kbuffer()
|
||
{ register struct buffer *b, *ob;
|
||
register char *ans;
|
||
|
||
if((ans = ask("Kill buffer: ")) == 0)
|
||
return;
|
||
if(*ans == 0) b = cur_buf;
|
||
else if(*ans == SP) b = 0;
|
||
else b = find_buf(ans);
|
||
|
||
chkfree(ans);
|
||
if(!b)
|
||
{ ding("No such buffer");
|
||
return;
|
||
}
|
||
#if IMAGEN
|
||
if (b->b_flags & B_PERMANENT)
|
||
{ ding("Permanent buffer--cannot kill!");
|
||
return;
|
||
}
|
||
if (b->b_flags & B_MODIFIED)
|
||
{ if ((ans == ask("Buffer is modified; are you sure? ")) == 0)
|
||
return;
|
||
if(upcase(*ans) != 'Y')
|
||
{ chkfree(ans);
|
||
return;
|
||
}
|
||
chkfree(ans);
|
||
}
|
||
#endif /*IMAGEN*/
|
||
if(b == cur_buf || (oth_win && (oth_win->w_buf == b)))
|
||
{ ob = last_buf;
|
||
do
|
||
{
|
||
/* If default same as doomed buffer, try to pick
|
||
* a more useful alternative. */
|
||
if((b == ob) && !(ob = sel_mbuf(b)))
|
||
ob = sel_nbuf(b);
|
||
|
||
ans = ask("Killing in-use buffer; select which other buffer (%s): ",
|
||
ob->b_name);
|
||
if(ans == 0) return;
|
||
if(*ans)
|
||
{ if(*ans == SP) ob = 0;
|
||
else ob = find_buf(ans);
|
||
}
|
||
chkfree(ans);
|
||
if(!ob)
|
||
{ ding("No such buffer");
|
||
return;
|
||
}
|
||
} while (b == ob);
|
||
|
||
/* B is buffer to kill, OB is buffer to replace it with */
|
||
if(oth_win && (oth_win->w_buf == b))
|
||
{ f_othwind(); /* Select other one */
|
||
chg_buf(ob); /* Change to new buffer */
|
||
f_othwind();
|
||
}
|
||
if(cur_buf == b)
|
||
chg_buf(ob);
|
||
}
|
||
|
||
kill_buf(b); /* Die!!!! */
|
||
if(last_buf == b)
|
||
last_buf = cur_buf;
|
||
}
|
||
|
||
/* EFUN: "List Buffers" */
|
||
/* Display a list of all user buffers. Internal buffers, whose names
|
||
* start with a space, are not shown.
|
||
*/
|
||
f_listbufs()
|
||
{
|
||
register struct buffer *b;
|
||
register char *cp;
|
||
register int i;
|
||
struct buffer *tbuf, *savbuf;
|
||
char temp[20];
|
||
|
||
/* First must set up special buffer... */
|
||
savbuf = cur_buf;
|
||
chg_buf(tbuf = make_buf(" **SHOW**"));
|
||
e_sputz("Buffers in this ELLE:\n\n");
|
||
for(b = buf_head; b; b = b->b_next)
|
||
{ cp = b->b_name;
|
||
if(*cp == SP) continue; /* Ignore internal buffs */
|
||
e_sputz((b->b_flags&B_MODIFIED) ? "* " : " ");
|
||
e_sputz(cp); /* Insert buffer name */
|
||
dottoa(temp,ex_blen(b)); /* Get buff-length string */
|
||
if((i = ((FNAMELEN > 14) ? 30 : 20)
|
||
- strlen(cp) - strlen(temp)) > 0)
|
||
e_insn(SP, i);
|
||
e_sputz(" (");
|
||
e_sputz(temp);
|
||
e_sputz(") ");
|
||
if(cp = b->b_fn)
|
||
e_sputz(cp);
|
||
#if IMAGEN
|
||
if (b->b_flags & B_CMODE)
|
||
e_sputz(" (C)");
|
||
else if (b->b_flags & B_TEXTMODE)
|
||
e_sputz(" (Text)");
|
||
else
|
||
e_sputz(" (Fundamental)");
|
||
#endif /*IMAGEN*/
|
||
e_putc(LF);
|
||
}
|
||
mk_showin(tbuf); /* Show this buffer in temp window */
|
||
chg_buf(savbuf); /* Return to real current buffer */
|
||
kill_buf(tbuf);
|
||
}
|
||
|
||
/* EFUN: "Buffer Not Modified" */
|
||
/* Mark the current buffer as not modified.
|
||
*/
|
||
f_bufnotmod()
|
||
{
|
||
cur_buf -> b_flags &= ~B_MODIFIED;
|
||
redp(RD_MODE);
|
||
}
|
||
|
||
#if FX_EOLMODE
|
||
/* EFUN: "EOL CRLF Mode" (not EMACS) */
|
||
/* Toggle the EOL mode of the current buffer.
|
||
** LF EOL Mode means LF alone is an EOL.
|
||
** CRLF EOL Mode means CRLF together is an EOL.
|
||
*/
|
||
f_eolmode()
|
||
{
|
||
cur_buf->b_flags ^= B_EOLCRLF; /* Flip this bit */
|
||
say((cur_buf->b_flags & B_EOLCRLF)
|
||
? "EOL Mode is CRLF" /* If now on */
|
||
: "EOL Mode is LF"); /* If now off */
|
||
|
||
redp(RD_WINRES); /* Redo window for this buf */
|
||
}
|
||
#endif /*FX_EOLMODE*/
|
||
|
||
#if FX_GOBEG
|
||
/* EFUN: "Goto Beginning" */
|
||
f_gobeg()
|
||
{ e_gobob();
|
||
ed_setcur();
|
||
}
|
||
#endif /*FX_GOBEG*/
|
||
|
||
#if FX_GOEND
|
||
/* EFUN: "Goto End" */
|
||
f_goend()
|
||
{ e_goeob();
|
||
ed_setcur();
|
||
}
|
||
#endif /*FX_GOEND*/
|
||
|
||
#if FX_WHATPAGE
|
||
/* EFUN: "What Page" */
|
||
/* Extra info added as per earlier ICONOGRAPHICS "What Buffer Position"
|
||
** Reports on current position as follows:
|
||
** Dot=<n>, Page <n> Line <n> (line <n> of <m>)
|
||
*/
|
||
f_whatpage()
|
||
{
|
||
register chroff cnt;
|
||
register int c;
|
||
register int page, line;
|
||
int lineatp;
|
||
char tempstr[12], *dottoa ();
|
||
|
||
saynow("Dot=");
|
||
dottoa(tempstr, cur_dot);
|
||
sayntoo(tempstr);
|
||
|
||
e_gobob();
|
||
page = line = lineatp = 1;
|
||
for (cnt = cur_dot; --cnt >= 0;)
|
||
if ((c = e_getc()) == LF)
|
||
++line;
|
||
else if (c == FF)
|
||
{ ++page;
|
||
lineatp = line;
|
||
}
|
||
|
||
saytoo(", Page ");
|
||
dottoa(tempstr, (chroff)page);
|
||
saytoo(tempstr);
|
||
saytoo(" Line ");
|
||
dottoa(tempstr, (chroff)(1 + line - lineatp));
|
||
saytoo(tempstr);
|
||
saytoo(" Col ");
|
||
dottoa(tempstr, (chroff)indtion(cur_dot));
|
||
saytoo(tempstr);
|
||
saytoo(" [line ");
|
||
dottoa(tempstr, (chroff)line);
|
||
saytoo(tempstr);
|
||
sayntoo(" of "); /* Force out while scan rest */
|
||
|
||
for(e_gocur(); e_gonl() ; ++line) ; /* Count lines until EOF */
|
||
c = e_rgetc(); /* Remember what last char is */
|
||
dottoa(tempstr, (chroff)line);
|
||
saytoo(tempstr);
|
||
if (c != LF) /* Check last char */
|
||
saytoo(" (no EOL at EOF!)");
|
||
sayntoo("]");
|
||
e_gocur(); /* Back to original position */
|
||
}
|
||
#endif /*FX_WHATPAGE*/
|
||
|
||
init_buf () /* init buffer stuff */
|
||
{
|
||
buf_head = 0;
|
||
lines_buf = cur_buf = make_buf(" **LINES**"); /* For sep_win */
|
||
e_insn('-',scr_wid-2); /* Fill with dashes */
|
||
last_buf = cur_buf = make_buf ("Main"); /* Make Main buffer */
|
||
init_win(); /* Now can init windows */
|
||
}
|
||
|
||
struct buffer *
|
||
make_buf(bname) /* create buffer "bname" if it doesn't exist */
|
||
char *bname;
|
||
{ register struct buffer *b;
|
||
register char *name;
|
||
|
||
b = find_buf(name = bname);
|
||
if (b) /* if it exists already */
|
||
return(b);
|
||
b = (struct buffer *) memalloc(sizeof (struct buffer));
|
||
b -> b_next = buf_head; /* link it in */
|
||
buf_head = b;
|
||
b->b_name = strdup(name); /* Allocate copy of name string */
|
||
b->b_dot = 0; /* Set dot to beg */
|
||
sb_open(b,(SBSTR *)0); /* Open buffer with null initial sbstring */
|
||
b->b_fn = 0;
|
||
b->b_flags = 0;
|
||
b->b_mode = cur_mode; /* Inherit current mode */
|
||
return(b);
|
||
}
|
||
|
||
|
||
struct buffer *
|
||
find_buf(name) /* returns pointer to buffer of that name or 0 */
|
||
char *name;
|
||
{ register struct buffer *b = buf_head;
|
||
|
||
while (b && strcmp(b->b_name, name))
|
||
b = b -> b_next;
|
||
return(b);
|
||
}
|
||
|
||
sel_buf(b) /* select buffer, saving last */
|
||
struct buffer *b;
|
||
{
|
||
if(b != cur_buf) last_buf = cur_buf;
|
||
chg_buf(b);
|
||
}
|
||
|
||
chg_buf (newbuf) /* change current buffer to newbuf */
|
||
struct buffer *newbuf;
|
||
{ register struct buffer *obuf, *nbuf;
|
||
|
||
if ((nbuf = newbuf) == (obuf = cur_buf))
|
||
return; /* Do nothing if same buffers */
|
||
obuf->b_dot = cur_dot;
|
||
cur_buf = nbuf;
|
||
cur_mode = nbuf->b_mode;
|
||
e_gosetcur(nbuf->b_dot); /* Set cur_dot and go there */
|
||
cur_win->w_buf = nbuf;
|
||
cur_win->w_dot = cur_dot;
|
||
#if IMAGEN
|
||
cur_win->w_redp = RD_WINRES|RD_REDO;
|
||
#else
|
||
cur_win->w_redp = RD_WINRES; /* Reset flags - do complete update */
|
||
#endif /*-IMAGEN*/
|
||
unlk_buf(obuf); /* Unlock previous buffer if can */
|
||
mark_p = 0; /* this is lazy */
|
||
redp(RD_MODE|RD_WINRES);
|
||
}
|
||
|
||
/* See if specified buffer belongs to any active window, and
|
||
* if not then get it into an idle, unlocked state; this helps the
|
||
* edit package compact and swap stuff out while it's not being used.
|
||
* Assumes proper state of dot has been stored into b_dot.
|
||
*/
|
||
unlk_buf(bufp)
|
||
struct buffer *bufp;
|
||
{ register struct buffer *b;
|
||
register struct window *w;
|
||
|
||
b = bufp;
|
||
for(w = win_head; w; w = w->w_next)
|
||
if(b == w->w_buf)
|
||
return; /* Buffer is actively being shown */
|
||
sb_rewind((SBBUF *)b); /* Return to idle state */
|
||
}
|
||
|
||
/* SEL_NBUF(buf) - Select next user buffer. Ignores internal buffers.
|
||
* Arg of 0 starts at beg of buffer list. Always returns
|
||
* a buffer pointer - returns argument (which may be 0)
|
||
* if found no other user buffers.
|
||
*
|
||
* SEL_MBUF(buf) - Select next modified buffer.
|
||
* Returns buffer ptr to "next" modified buffer, if any.
|
||
* Arg of 0 starts at beg of buffer list and scans all of them.
|
||
* Returns 0 if no other modified buffers exist (unlike SEL_NBUF!)
|
||
* Ignores internal buffers, whose names start with a space.
|
||
*/
|
||
/* struct buffer *buf_mptr; */
|
||
#if 0
|
||
struct buffer *
|
||
sel_mbuf(buf)
|
||
struct buffer *buf;
|
||
{ register struct buffer *b;
|
||
register int sweep;
|
||
|
||
sweep = 0; /* Make 2 sweeps only */
|
||
if(b = buf) b = b->b_next;
|
||
do {
|
||
if(b == 0) /* Initialize if needed */
|
||
b = buf_head;
|
||
for(; b; b = b->b_next)
|
||
if((b->b_flags & B_MODIFIED) && (*b->b_name != SP))
|
||
return((b == buf) ? 0 : b);
|
||
} while(sweep++ != 0);
|
||
return(0);
|
||
}
|
||
#endif /*COMMENT*/
|
||
|
||
struct buffer *
|
||
sel_mbuf(buf)
|
||
register struct buffer *buf;
|
||
{ register struct buffer *b, *b2;
|
||
b = b2 = sel_nbuf(buf);
|
||
do { if(b == buf) break;
|
||
if(b->b_flags & B_MODIFIED)
|
||
return(b);
|
||
} while((b = sel_nbuf(b)) != b2);
|
||
|
||
return(0);
|
||
}
|
||
|
||
struct buffer *
|
||
sel_nbuf(buf)
|
||
register struct buffer *buf;
|
||
{ register struct buffer *b;
|
||
|
||
b = buf;
|
||
do {
|
||
if(!b || !(b = b->b_next))
|
||
b = buf_head;
|
||
if(*b->b_name != SP)
|
||
break;
|
||
} while (b != buf);
|
||
return(b);
|
||
}
|
||
|
||
|
||
kill_buf(buf)
|
||
struct buffer *buf;
|
||
{ register struct buffer *b, *b1, *bt;
|
||
|
||
b = buf;
|
||
b1 = 0;
|
||
for(bt = buf_head; bt && bt != b; bt = bt -> b_next)
|
||
b1 = bt;
|
||
if(bt == 0)
|
||
{ ring_bell();
|
||
errbarf("No such buffer"); /* Internal error */
|
||
return;
|
||
}
|
||
if (b1 == 0)
|
||
buf_head = b->b_next;
|
||
else
|
||
b1->b_next = b->b_next;
|
||
sbs_del(sb_close((SBBUF *)b)); /* Close buffer & delete sbstring */
|
||
sb_fdcls(-1); /* Make sweep for unused FD's */
|
||
if(b->b_fn)
|
||
chkfree(b->b_fn); /* Flush filename if one */
|
||
chkfree(b->b_name); /* Flush name */
|
||
chkfree((char *)b); /* Flush buffer */
|
||
}
|
||
|
||
/* ZAP_BUFFER - Delete all of the buffer, but if it's been modified,
|
||
* ask first. Returns 0 if user aborts.
|
||
*/
|
||
zap_buffer()
|
||
{
|
||
#if IMAGEN
|
||
extern struct buffer *exec_buf; /* in e_make.c */
|
||
|
||
if(cur_buf != exec_buf && cur_buf -> b_flags & B_MODIFIED)
|
||
#else
|
||
if(cur_buf -> b_flags & B_MODIFIED)
|
||
#endif /*-IMAGEN*/
|
||
if(ask_kbuf(cur_buf) <= 0)
|
||
return(0); /* Aborted */
|
||
ed_reset(); /* This takes care of redisplay too */
|
||
mark_p = 0;
|
||
#if IMAGEN
|
||
cur_buf->b_flags &= ~B_BACKEDUP; /* Clear backed-up flag */
|
||
#endif
|
||
return(1);
|
||
}
|
||
|
||
|
||
|
||
/* ASK_KBUF - Ask user "are you sure?" before killing a buffer.
|
||
* Returns +1 if user says "yes" - OK to kill.
|
||
* 0 if user aborts (^G)
|
||
* -1 if user says "no".
|
||
*/
|
||
ask_kbuf(buf)
|
||
struct buffer *buf;
|
||
{ register struct buffer *b;
|
||
register char *s;
|
||
register int ans;
|
||
|
||
b = buf;
|
||
s = ask("Buffer %s contains changes - forget them? ", b->b_name);
|
||
if(s == 0) return(0);
|
||
ans = (upcase(*s) == 'Y') ? 1 : -1;
|
||
chkfree(s);
|
||
return(ans);
|
||
}
|
||
|
||
/* Window stuff */
|
||
|
||
/* Like EMACS, ELLE only provides at most two user windows.
|
||
* The current user window is pointed to by user_win;
|
||
* the "other" one is oth_win. If oth_win == 0, there is only one user
|
||
* window.
|
||
*/
|
||
|
||
#if FX_2MODEWINDS
|
||
int sepmode_p = 0; /* Set true if separator window is a 2nd mode win */
|
||
#endif
|
||
|
||
/* EFUN: "Two Windows" */
|
||
/* Divide the current window in half, put the current buffer in the
|
||
* other window, and go to the new window.
|
||
*/
|
||
f_2winds()
|
||
{ register int h, t;
|
||
register struct window *w;
|
||
|
||
if (oth_win)
|
||
{
|
||
#if !(IMAGEN)
|
||
ding("Already 2 windows");
|
||
#endif /*-IMAGEN*/
|
||
return;
|
||
}
|
||
w = cur_win;
|
||
d_fixcur(); /* Stabilize current window */
|
||
h = (w->w_ht) / 2;
|
||
t = w->w_pos + h; /* Pos of dividing window */
|
||
sep_win = make_win(t, 1, lines_buf);
|
||
/* assume using dashes to separate */
|
||
oth_win = make_win(t + 1, w->w_ht - (h + 1), cur_buf);
|
||
/* Other window has balance */
|
||
#if FX_SOWIND
|
||
oth_win->w_flags |= cur_win->w_flags&W_STANDOUT;
|
||
sep_win->w_flags |= mode_win->w_flags&W_STANDOUT;
|
||
#endif
|
||
#if FX_2MODEWINDS
|
||
chk2modws(); /* Update 2-mode-wind status */
|
||
#endif
|
||
w->w_ht = h; /* Decrease current window to half */
|
||
|
||
/* Minimize redisplay by moving each window's dot into
|
||
* a currently displayed area */
|
||
if(cur_dot < (oth_win->w_topldot = scr[t+1]->sl_boff))
|
||
oth_win->w_dot = oth_win->w_topldot; /* Adj bottom win */
|
||
else /* Adjust top window */
|
||
{ oth_win->w_dot = cur_dot; /* Bottom keeps dot */
|
||
cur_dot = scr[t-1]->sl_boff; /* but top needs new one. */
|
||
}
|
||
f_othwind(); /* switch to other window */
|
||
redp(RD_WINDS); /* Update all windows */
|
||
}
|
||
|
||
|
||
/* EFUN: "One Window" */
|
||
/* Revert to using only one window; use the current buffer (unlike
|
||
* EMACS which always selects the top window's buffer)
|
||
* Ensures that current window's vars are correctly set for
|
||
* new dimensions (w_pos, w_ht, plus w_topldot to minimize redisplay),
|
||
* then kills unneeded windows.
|
||
*/
|
||
f_1wind()
|
||
{ register struct window *w;
|
||
|
||
if (oth_win == 0)
|
||
{
|
||
#if (!IMAGEN)
|
||
ding("Only 1 window");
|
||
#endif /*-IMAGEN*/
|
||
return;
|
||
}
|
||
w = cur_win;
|
||
if(w->w_pos) /* If not top window */
|
||
{ d_fixcur(); /* Ensure screen-line data correct */
|
||
e_go(w->w_topldot); /* Beginning from top of window, */
|
||
d_fgoloff(-w->w_pos); /* Move back enough lines */
|
||
w->w_topldot = e_dot(); /* To set new start of window */
|
||
e_gocur(); /* Then move back to orig place */
|
||
w->w_pos = 0;
|
||
}
|
||
w->w_ht += oth_win -> w_ht + 1;
|
||
kill_win (oth_win);
|
||
kill_win (sep_win);
|
||
oth_win = sep_win = 0;
|
||
#if FX_2MODEWINDS
|
||
chk2modws(); /* Update notion of whether have 2 mode winds */
|
||
#endif
|
||
redp(RD_FIXWIN|RD_WINDS|RD_MODE); /* New topldot for this window,
|
||
* and check all remaining windows */
|
||
}
|
||
|
||
/* EFUN: "Other Window" */
|
||
/* Move to the "other" user window.
|
||
*/
|
||
f_othwind ()
|
||
{ if (oth_win == 0)
|
||
{
|
||
#if !(IMAGEN)
|
||
ding("Only 1 window");
|
||
#endif /*-IMAGEN*/
|
||
return;
|
||
}
|
||
chg_win(oth_win);
|
||
oth_win = user_win;
|
||
user_win = cur_win;
|
||
redp(RD_MODE);
|
||
}
|
||
|
||
/* EFUN: "Grow Window" */
|
||
/* Grow the current window - while in two window mode,
|
||
* increase the size of the current window by the arg
|
||
* and decrease the other accordingly
|
||
*/
|
||
f_growind()
|
||
{ register struct window *cw, *ow;
|
||
register int e;
|
||
|
||
if ((ow = oth_win) == 0)
|
||
{
|
||
#if !(IMAGEN)
|
||
ding("Only 1 window");
|
||
#endif /*-IMAGEN*/
|
||
return;
|
||
}
|
||
e = exp;
|
||
if((cw = cur_win)->w_pos != 0) /* If current window is on bottom */
|
||
{ cw = ow; /* Then fake code to think it's top */
|
||
ow = cur_win;
|
||
e = -e;
|
||
}
|
||
if( cw->w_ht + e < 1
|
||
|| ow->w_ht + e < 1)
|
||
{ ding("Too much");
|
||
return;
|
||
}
|
||
cw -> w_ht += e;
|
||
ow -> w_pos += e;
|
||
ow -> w_ht -= e;
|
||
sep_win -> w_pos += e;
|
||
redp(RD_WINDS | RD_MODE); /* Update all windows */
|
||
}
|
||
|
||
#if FX_SHRINKWIND
|
||
/* EFUN: "Shrink Window" (not EMACS) - from IMAGEN config */
|
||
f_shrinkwind()
|
||
{
|
||
if (! oth_win)
|
||
return;
|
||
f_othwind();
|
||
f_growind();
|
||
f_othwind();
|
||
}
|
||
#endif /*FX_SHRINKWIND*/
|
||
|
||
#if FX_DELWIND
|
||
/* EFUN: "Delete Window" (not EMACS) - from IMAGEN config */
|
||
f_delwind()
|
||
{
|
||
if(!oth_win)
|
||
return;
|
||
f_othwind();
|
||
f_1wind();
|
||
}
|
||
#endif /*FX_DELWIND*/
|
||
|
||
#if FX_SOWIND
|
||
/* EFUN: "Standout Window" (not EMACS) */
|
||
/* Toggles the display standout mode for the current window.
|
||
** With argument of 4, toggles the standout mode for the non-buffer
|
||
** parts of the screen, such as the ELLE mode line.
|
||
** (This corresponds to FS INVMOD$ in EMACS)
|
||
** With argument of 0, turns standout mode off for all windows.
|
||
*/
|
||
/* It suffices to set the window flag bit and force a RD_WINRES for that
|
||
* window; the redisplay code will do the rest.
|
||
*/
|
||
static void tgso_wind();
|
||
|
||
f_sowind()
|
||
{
|
||
register struct window *w;
|
||
switch(exp)
|
||
{ default: /* Toggle current window */
|
||
tgso_wind(cur_win);
|
||
break;
|
||
case 4: /* Toggle mode & separator windows */
|
||
tgso_wind(mode_win);
|
||
tgso_wind(sep_win); /* This may not exist */
|
||
break;
|
||
case 0: /* Turn off standout for all winds */
|
||
for(w = win_head; w; w = w->w_next)
|
||
if(w->w_flags&W_STANDOUT)
|
||
tgso_wind(w);
|
||
}
|
||
#if FX_2MODEWINDS
|
||
chk2modws(); /* Update notion of whether have 2 mode winds */
|
||
#endif
|
||
}
|
||
|
||
static void
|
||
tgso_wind(w) /* Toggle standout mode for given window */
|
||
register struct window *w;
|
||
{
|
||
if (w == 0) return; /* For case of no sep_win */
|
||
if (w->w_flags & W_STANDOUT)
|
||
w->w_flags &= ~W_STANDOUT;
|
||
else w->w_flags |= W_STANDOUT;
|
||
w->w_redp |= RD_WINRES; /* Re-do this particular window */
|
||
redp(RD_CHKALL); /* Check all windows for changes */
|
||
}
|
||
#endif /*FX_SOWIND*/
|
||
|
||
|
||
#if FX_2MODEWINDS
|
||
/* EFUN: "Two Mode Windows" (not EMACS) */
|
||
/* With arg, sets ev_2modws to that value (0, 1, or 2).
|
||
** No arg, toggles current setting between 0 and 2.
|
||
*/
|
||
|
||
f_2modewinds()
|
||
{
|
||
ev_2modws = exp_p ? exp : (ev_2modws ? 0 : 2);
|
||
chk2modws();
|
||
}
|
||
|
||
/* CHK2MODWS - Called after anything changes which might affect
|
||
** whether 2 mode windows are in effect or not. Fixes up
|
||
** sep_win to either be or not be a mode window.
|
||
*/
|
||
chk2modws()
|
||
{ register struct window *w;
|
||
static struct buffer *sep_buf = 0;
|
||
|
||
if(!(w = sep_win))
|
||
{ sepmode_p = 0; /* Don't have 2 windows at all */
|
||
return;
|
||
}
|
||
sepmode_p = (ev_2modws == 1)
|
||
? (mode_win->w_flags&W_STANDOUT)
|
||
: ev_2modws;
|
||
|
||
if(sepmode_p) /* Turn 2-mode-winds on? */
|
||
{
|
||
if(!sep_buf)
|
||
sep_buf = make_buf(" **SEPMODE**");
|
||
w->w_buf = sep_buf;
|
||
w->w_flags |= W_MODE;
|
||
}
|
||
else /* Turn 2-mode-winds off */
|
||
{ w->w_buf = lines_buf;
|
||
w->w_flags &= ~W_MODE;
|
||
redp(RD_CHKALL); /* No longer a mode win, so must */
|
||
/* check all to ensure it's updated */
|
||
}
|
||
w->w_redp |= RD_WINRES;
|
||
redp(RD_MODE);
|
||
}
|
||
#endif /*FX_2MODEWINDS*/
|
||
|
||
init_win ()
|
||
{
|
||
win_head = 0;
|
||
oth_win = 0;
|
||
user_win = make_win(0, scr_ht - (ECHOLINES+1), cur_buf); /* Main */
|
||
mode_win = make_win(scr_ht - (ECHOLINES+1), 1, make_buf(" **MODE**"));
|
||
ask_win = make_win(scr_ht - ECHOLINES, 1, make_buf(" **ASK**"));
|
||
#if FX_SOWIND
|
||
if(ev_modwso)
|
||
mode_win->w_flags |= W_STANDOUT;
|
||
#endif
|
||
|
||
cur_win = user_win;
|
||
}
|
||
|
||
chg_win(newwin) /* change current window to newwin */
|
||
struct window *newwin;
|
||
{
|
||
cur_win->w_dot = cur_dot; /* Save window's current dot */
|
||
cur_win->w_redp |= rd_type&RDS_WINFLGS; /* and its redisplay flags */
|
||
cur_win = newwin; /* OK, switch to new current window */
|
||
cur_buf = newwin->w_buf; /* Set new buffer from win */
|
||
e_gosetcur(newwin->w_dot); /* Set new cur_dot from win too */
|
||
/* Note done this way to canonicalize the location
|
||
** (may be past new EOB) and ensure SB buffer
|
||
** internals agree with cur_dot.
|
||
*/
|
||
rd_type &= ~RDS_WINFLGS; /* Remove old per-window flags */
|
||
redp(RD_WINRES|RD_MODE); /* Maybe caller shd handle? */
|
||
/* Note WINRES must be set in case we are pointing
|
||
* to a buffer that was modified while we were in
|
||
* the other window!
|
||
*/
|
||
}
|
||
|
||
|
||
struct window *
|
||
make_win (pos, ht, buf)
|
||
int pos, ht;
|
||
struct buffer *buf;
|
||
{ register struct window *w;
|
||
register struct buffer *b;
|
||
|
||
b = buf;
|
||
w = (struct window *) memalloc(sizeof (struct window));
|
||
w->w_flags = 0;
|
||
w->w_pos = pos;
|
||
w->w_ht = ht;
|
||
w->w_buf = b;
|
||
w->w_dot = b->b_dot; /* Set dot from buffer value */
|
||
w->w_topldot = 0; /* Set top of window to beg of buffer */
|
||
w->w_pct = 200; /* Assume "ALL" */
|
||
w->w_bmod = 0;
|
||
w->w_emod = 0;
|
||
w->w_oldz = 0;
|
||
w->w_redp = RD_WINRES; /* Window will need complete update */
|
||
w->w_next = win_head; /* Done, now link it in */
|
||
win_head = w;
|
||
return (w);
|
||
}
|
||
|
||
kill_win (win)
|
||
struct window *win;
|
||
{ register struct window *w, *w1, *kw;
|
||
|
||
kw = win;
|
||
w1 = 0;
|
||
for (w = win_head; w && w != kw; w = w -> w_next)
|
||
w1 = w;
|
||
if (w == 0)
|
||
{ ring_bell();
|
||
errbarf("No such window"); /* Internal error */
|
||
return;
|
||
}
|
||
if (w1 == 0)
|
||
win_head = w -> w_next;
|
||
else
|
||
w1 -> w_next = w -> w_next;
|
||
kw->w_buf->b_dot = (kw == cur_win) ? cur_dot : kw->w_dot;
|
||
chkfree (kw);
|
||
#if IMAGEN /* Not needed? */
|
||
redp (RD_WINRES|RD_WINDS|RD_REDO);
|
||
#endif /*IMAGEN*/
|
||
}
|
||
|
||
/*
|
||
* "Show-window" routines, used to set up, step through, and close a
|
||
* temporary "show" window.
|
||
* MK_SHOWIN(bufp)
|
||
* UP_SHOWIN()
|
||
* KL_SHOWIN()
|
||
*/
|
||
|
||
/* MK_SHOWIN(bufp) - Temporarily display a buffer
|
||
*/
|
||
mk_showin(b)
|
||
struct buffer *b;
|
||
{ register struct window *w;
|
||
register int i;
|
||
int moreflg, intflg; /* Interrupt flag */
|
||
struct window *savwin;
|
||
|
||
/* First must set up special window... */
|
||
savwin = cur_win;
|
||
chg_win(w = make_win(0, scr_ht-(ECHOLINES+3), b));
|
||
redo:
|
||
d_fixcur(); /* Fix up screen image of current window */
|
||
|
||
/* Find how many lines actually used, and reduce size to that */
|
||
i = w->w_ht;
|
||
while(--i >= 0)
|
||
{
|
||
if(scr[i]->sl_boff != w->w_oldz) break;
|
||
}
|
||
if(++i <= 0)
|
||
goto skipit; /* Punt the whole thing */
|
||
if(!(moreflg = (i >= w->w_ht)))
|
||
w->w_ht = i; /* Reduce size of window */
|
||
|
||
intflg = upd_wind(w); /* Update the window! */
|
||
if(!intflg) /* Unless input waiting, add prompt. */
|
||
{
|
||
yellat( moreflg ?
|
||
"--MORE-- (type Space for more, or type any command to flush)" :
|
||
"------------------------------------------------ (Hit space to continue)--",
|
||
w->w_ht);
|
||
|
||
}
|
||
tbufls(); /* Ensure all output forced out */
|
||
i = cmd_read(); /* then wait for user to input a char */
|
||
if(i == SP)
|
||
{ if(moreflg)
|
||
{ yellat("", w->w_ht);
|
||
d_screen(1);
|
||
w->w_redp |= RD_WINRES;
|
||
goto redo;
|
||
}
|
||
}
|
||
#if !(IMAGEN) /* IMAGEN - always ignore what was typed */
|
||
else unrchf = i;
|
||
#endif /*-IMAGEN*/
|
||
skipit: chg_win(savwin);
|
||
kill_win(w);
|
||
redp(RD_WINDS); /* Update all remaining windows */
|
||
}
|
||
|
||
/* Mode Line generation */
|
||
|
||
struct window *
|
||
make_mode(bw)
|
||
register struct window *bw; /* Base window we are reporting status of */
|
||
{
|
||
register struct buffer *b; /* Buffer of this window */
|
||
struct window *mw, *savew; /* Save current window */
|
||
struct buffer *saveb; /* and current buffer (in case different) */
|
||
char temp[20];
|
||
|
||
saveb = cur_buf; /* Save values prior to context switch */
|
||
savew = cur_win;
|
||
b = bw->w_buf; /* Get buffer for that window */
|
||
|
||
#if FX_2MODEWINDS
|
||
if((mw = sep_win) && (mw->w_flags&W_MODE) &&
|
||
(bw->w_pos == 0)) /* Base window is top window? */
|
||
{ /* Use sep_win as mode wind */
|
||
}
|
||
else
|
||
#endif
|
||
mw = mode_win; /* Default is normal mode window */
|
||
chg_win(mw); /* Go to mode line window */
|
||
e_gobob(); /* go to beginning */
|
||
e_reset(); /* Flush buffer */
|
||
#if IMAGEN
|
||
e_sputz(" ");
|
||
e_sputz(b->b_name);
|
||
if (b -> b_flags & B_MODIFIED)
|
||
e_sputz("*");
|
||
e_sputz(" (");
|
||
if (b->b_flags & B_QUERYREP)
|
||
e_sputz("[Query Replace] ");
|
||
if (b->b_flags & B_CMODE)
|
||
e_sputz("C");
|
||
else if (b->b_flags & B_TEXTMODE)
|
||
e_sputz("Text");
|
||
else
|
||
e_sputz("Fundamental");
|
||
e_sputz(") ");
|
||
if (b->b_fn)
|
||
e_sputz(b->b_fn);
|
||
e_sputz(" ");
|
||
#else
|
||
e_sputz(ev_verstr); /* Editor name/version */
|
||
e_sputz(" (");
|
||
e_sputz(cur_mode->mjm_name); /* insert major mode name */
|
||
#if FX_FILLMODE
|
||
if(fill_mode) e_sputz(" Fill");
|
||
#endif /*FX_FILLMODE*/
|
||
#if FX_SKMAC
|
||
if(kdef_mode) e_sputz(" MacroDef");
|
||
#endif /*FX_SKMAC*/
|
||
e_sputz(") ");
|
||
e_sputz(b->b_name); /* buffer name */
|
||
e_sputz(": ");
|
||
if (b->b_fn)
|
||
e_sputz(b->b_fn); /* file name */
|
||
if (b->b_flags & B_MODIFIED)
|
||
e_sputz(" *");
|
||
else e_sputz(" ");
|
||
#endif /*-IMAGEN*/
|
||
if(bw->w_pct < 200) /* Not ALL? */
|
||
{ e_sputz(" --");
|
||
switch(bw->w_pct)
|
||
{ case -1:
|
||
e_sputz("TOP");
|
||
break;
|
||
case 150:
|
||
e_sputz("BOT");
|
||
break;
|
||
default:
|
||
dottoa(&temp[0],(chroff)bw->w_pct);
|
||
e_sputz(&temp[0]);
|
||
e_putc('%');
|
||
}
|
||
e_sputz("--");
|
||
}
|
||
#if FX_SOWIND
|
||
if(mw->w_flags&W_STANDOUT)
|
||
e_insn(SP, (int)(scr_wd0 - e_blen())); /* Stuff out with spaces */
|
||
#endif
|
||
|
||
redp(RD_WINRES);
|
||
chg_win(savew); /* Restore context */
|
||
chg_buf(saveb);
|
||
return(mw); /* Return mode window */
|
||
}
|
||
|
||
|
||
buf_mod()
|
||
{ register struct buffer *b;
|
||
|
||
b = cur_buf;
|
||
if((b->b_flags & B_MODIFIED) == 0)
|
||
{ b->b_flags |= B_MODIFIED;
|
||
redp(RD_MODE);
|
||
}
|
||
}
|
||
|
||
/* BUF_TMOD - called when text modified in buffer, to set all
|
||
* the appropriate indicators so that redisplay works right.
|
||
* Changed text is everything from CUR_DOT to the given offset
|
||
* from same. If stuff was deleted, offset should be 0.
|
||
* BUF_TMAT - similar but argument is location of other end of range,
|
||
* when caller knows that and wants life easy.
|
||
*/
|
||
|
||
buf_tmat(dot)
|
||
chroff dot;
|
||
{ buf_tmod(dot - cur_dot); /* Convert to offset */
|
||
}
|
||
buf_tmod(offset)
|
||
chroff offset;
|
||
{ register struct window *w;
|
||
chroff a, b, tmp;
|
||
|
||
w = cur_win;
|
||
a = cur_dot;
|
||
b = a + offset;
|
||
if(a > b) /* Get into right order */
|
||
{ tmp = a;
|
||
a = b;
|
||
b = tmp;
|
||
}
|
||
b = e_blen() - b; /* Make upper bound relative to EOB */
|
||
if(w->w_bmod < 0) /* Have range vars been set yet? */
|
||
{ w->w_bmod = a; /* Nope, so can just set 'em now. */
|
||
w->w_emod = b;
|
||
}
|
||
else
|
||
{ if(a < w->w_bmod)
|
||
w->w_bmod = a;
|
||
if(b < w->w_emod)
|
||
w->w_emod = b;
|
||
}
|
||
buf_mod(); /* Maybe later just insert here? */
|
||
redp(RD_TMOD);
|
||
}
|