home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
vile-src.zip
/
vile-8.1
/
basic.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-07-02
|
27KB
|
1,291 lines
/*
* The routines in this file move the cursor around on the screen. They
* compute a new value for the cursor, then adjust ".". The display code
* always updates the cursor location, so only moves between lines, or
* functions that adjust the top line in the window and invalidate the
* framing, are hard.
*
* $Header: /usr/build/vile/vile/RCS/basic.c,v 1.99 1998/07/03 00:07:41 tom Exp $
*
*/
#include "estruct.h"
#include "edef.h"
#define RegexpLen(exp) ((exp->mlen) ? (int)(exp->mlen) : 1)
static int getnmmarkname ( int *cp );
static void skipblanksb (void);
static void skipblanksf (void);
/* utility routine for 'forwpage()' and 'backpage()' */
static int
full_pages(int f, int n)
{
if (f == FALSE) {
n = curwp->w_ntrows - 2; /* Default scroll. */
if (n <= 0) /* Don't blow up if the */
n = 1; /* window is tiny. */
}
#if OPT_CVMVAS
else if (n > 0) /* Convert from pages */
n *= curwp->w_ntrows; /* to lines. */
#endif
return n;
}
/* utility routine for 'forwhpage()' and 'backhpage()' */
static int
half_pages(int f, int n)
{
if (f == FALSE) {
n = curwp->w_ntrows / 2; /* Default scroll. */
if (n <= 0) /* Forget the overlap */
n = 1; /* if tiny window. */
}
#if OPT_CVMVAS
else if (n > 0) /* Convert from pages */
n *= curwp->w_ntrows/2; /* to lines. */
#endif
return n;
}
/*
* Implements the vi "0" command.
*
* Move the cursor to the beginning of the current line.
*/
/* ARGSUSED */
int
gotobol(int f GCC_UNUSED, int n GCC_UNUSED)
{
DOT.o = w_left_margin(curwp);
return mvleftwind(TRUE, -w_val(curwp,WVAL_SIDEWAYS));
}
/*
* Move the cursor backwards by "n" characters. If "n" is less than zero call
* "forwchar" to actually do the move. Otherwise compute the new cursor
* location. Error if you try and move out of the buffer. Set the flag if the
* line pointer for dot changes.
*/
int
backchar(int f, int n)
{
register LINE *lp;
if (f == FALSE) n = 1;
if (n < 0)
return (forwchar(f, -n));
while (n--) {
if (DOT.o == w_left_margin(curwp)) {
if ((lp=lback(DOT.l)) == buf_head(curbp))
return (FALSE);
DOT.l = lp;
DOT.o = llength(lp);
curwp->w_flag |= WFMOVE;
} else
DOT.o--;
}
return (TRUE);
}
/*
* Implements the vi "h" command.
*
* Move the cursor backwards by "n" characters. Stop at beginning of line.
*/
int
backchar_to_bol(int f, int n)
{
if (f == FALSE) n = 1;
if (n < 0)
return forwchar_to_eol(f, -n);
while (n--) {
if (DOT.o == w_left_margin(curwp))
return doingopcmd;
else
DOT.o--;
}
return TRUE;
}
/*
* Implements the vi "$" command.
*
* Move the cursor to the end of the current line. Trivial.
*/
int
gotoeol(int f, int n)
{
if (f == TRUE) {
if (n > 0)
--n;
else if (n < 0)
++n;
if (forwline(f,n) != TRUE)
return FALSE;
}
DOT.o = llength(DOT.l);
curgoal = HUGE;
return (TRUE);
}
/*
* Move the cursor forwards by "n" characters. If "n" is less than zero call
* "backchar" to actually do the move. Otherwise compute the new cursor
* location, and move ".". Error if you try and move off the end of the
* buffer. Set the flag if the line pointer for dot changes.
*/
int
forwchar(int f, int n)
{
if (f == FALSE) n = 1;
if (n < 0)
return (backchar(f, -n));
while (n--) {
/* if an explicit arg was given, allow us to land
on the newline, else skip it */
if (is_at_end_of_line(DOT) ||
(f == FALSE && !insertmode &&
llength(DOT.l) && DOT.o == llength(DOT.l) - 1)
) {
if (is_header_line(DOT, curbp) ||
is_last_line(DOT,curbp))
return (FALSE);
DOT.l = lforw(DOT.l);
DOT.o = w_left_margin(curwp);
curwp->w_flag |= WFMOVE;
} else
DOT.o++;
}
return (TRUE);
}
/*
* Implements the vi "l" command.
*
* Move the cursor forwards by "n" characters. Don't go past end-of-line
*
* If the flag 'doingopcmd' is set, implements a vi "l"-like motion for
* internal use. The end-of-line test is off-by-one from the true "l" command
* to allow for substitutions at the end of a line.
*/
int
forwchar_to_eol(int f, int n)
{
int nwas = n;
int lim;
if (f == FALSE) n = 1;
if (n < 0) return backchar_to_bol(f, -n);
if (n == 0) return TRUE;
/* normally, we're confined to the text on the line itself. if
we're doing an opcmd, then we're allowed to move to the newline
as well, to take care of the internal cases: 's', 'x', and '~'. */
if (doingopcmd || insertmode)
lim = llength(DOT.l);
else
lim = llength(DOT.l) - 1;
do {
if (DOT.o >= lim)
return n != nwas; /* return ok if we moved at all */
else
DOT.o++;
} while (--n);
return TRUE;
}
/*
* Implements the vi "G" command.
*
* Move to a particular line (the argument). Count from bottom of file if
* argument is negative.
*/
int
gotoline(int f, int n)
{
register int status; /* status return */
MARK odot;
if (f == FALSE) {
return(gotoeob(f,n));
}
if (n == 0) /* if a bogus argument...then leave */
return(FALSE);
odot = DOT;
DOT.o = w_left_margin(curwp);
if (n < 0) {
DOT.l = lback(buf_head(curbp));
status = backline(f, -n - 1 );
} else {
DOT.l = lforw(buf_head(curbp));
status = forwline(f, n-1);
}
if (status != TRUE) {
DOT = odot;
return status;
}
(void)firstnonwhite(FALSE,1);
curwp->w_flag |= WFMOVE;
return TRUE;
}
/*
* Goto the beginning of the buffer. Massive adjustment of dot. This is
* considered to be hard motion; it really isn't if the original value of dot
* is the same as the new value of dot.
*/
/* ARGSUSED */
int
gotobob(int f GCC_UNUSED, int n GCC_UNUSED)
{
DOT.l = lforw(buf_head(curbp));
DOT.o = w_left_margin(curwp);
curwp->w_flag |= WFMOVE;
return (TRUE);
}
/*
* Move to the end of the buffer. Dot is always put at the end of the file.
*/
/* ARGSUSED */
int
gotoeob(int f GCC_UNUSED, int n GCC_UNUSED)
{
DOT.l = lback(buf_head(curbp));
curwp->w_flag |= WFMOVE;
return firstnonwhite(FALSE,1);
}
/*
* Implements the vi "H" command.
*
* Move to first (or nth) line in window
*/
int
gotobos(int f, int n)
{
int nn = curwp->w_ntrows;
if (!f || n <= 0)
n = 1;
DOT.l = curwp->w_line.l;
while (--n) {
if (is_last_line(DOT,curbp))
break;
nn -= line_height(curwp, DOT.l);
DOT.l = lforw(DOT.l);
}
if (nn <= 0) /* we went past the end of window */
curwp->w_flag |= WFMOVE;
return firstnonwhite(FALSE,1);
}
/*
* Implements the vi "M" command.
*
* Move to the middle of lines displayed in window
*/
/* ARGSUSED */
int
gotomos(int f GCC_UNUSED, int n)
{
register LINEPTR lp, head;
int half = (curwp->w_ntrows+1) / 2;
head = buf_head(curbp);
for (n = 0, lp = curwp->w_line.l; lp != head; lp = lforw(lp)) {
if (n < half)
DOT.l = lp;
if ((n += line_height(curwp, lp)) >= curwp->w_ntrows)
break;
}
if (n < curwp->w_ntrows) { /* then we hit eof before eos */
half = (n+1) / 2; /* go back up */
for (n = 0, lp = curwp->w_line.l; lp != head; lp = lforw(lp)) {
DOT.l = lp;
if ((n += line_height(curwp, lp)) >= half)
break;
}
}
return firstnonwhite(FALSE,1);
}
/*
* Implements the vi "L" command.
*
* Move to the last (or nth last) line in window
*/
int
gotoeos(int f, int n)
{
int nn;
if (f == FALSE || n <= 0)
n = 1;
/* first get to the end */
DOT.l = curwp->w_line.l;
nn = curwp->w_ntrows;
while ((nn -= line_height(curwp,DOT.l)) > 0) {
if (is_last_line(DOT,curbp))
break;
DOT.l = lforw(DOT.l);
}
#ifdef WMDLINEWRAP
/* adjust if we pointed to a line-fragment */
if (w_val(curwp,WMDLINEWRAP)
&& nn < 0
&& DOT.l != curwp->w_line.l)
DOT.l = lback(DOT.l);
#endif
/* and then go back up */
/* (we're either at eos or eof) */
while (--n) {
if (sameline(DOT, curwp->w_line))
break;
DOT.l = lback(DOT.l);
}
return firstnonwhite(FALSE,1);
}
/*
* Implements the vi "j" command.
*
* Move forward by full lines. If the number of lines to move is less than
* zero, call the backward line function to actually do it. The last command
* controls how the goal column is set.
*/
int
forwline(int f, int n)
{
register LINE *dlp;
if (f == FALSE) n = 1;
if (n < 0) return (backline(f, -n));
if (n == 0) return TRUE;
/* if the last command was not a line move,
reset the goal column */
if (curgoal < 0)
curgoal = getccol(FALSE);
/* and move the point down */
dlp = DOT.l;
do {
register LINE *nlp = lforw(dlp);
if (nlp == buf_head(curbp)) {
return FALSE;
}
dlp = nlp;
} while (--n);
/* resetting the current position */
DOT.l = dlp;
DOT.o = getgoal(dlp);
curwp->w_flag |= WFMOVE;
return TRUE;
}
/*
* Implements the vi "^" command.
*
* Move to the first nonwhite character on the current line. No errors are
* returned.
*/
/* ARGSUSED */
int
firstnonwhite(int f GCC_UNUSED, int n GCC_UNUSED)
{
DOT.o = firstchar(DOT.l);
if (DOT.o < w_left_margin(curwp)) {
if (llength(DOT.l) <= w_left_margin(curwp))
DOT.o = w_left_margin(curwp);
else
DOT.o = llength(DOT.l) - 1;
}
return TRUE;
}
/* ARGSUSED */
#if !SMALLER
int
lastnonwhite(int f GCC_UNUSED, int n GCC_UNUSED)
{
DOT.o = lastchar(DOT.l);
if (DOT.o < w_left_margin(curwp))
DOT.o = w_left_margin(curwp);
return TRUE;
}
#endif
/* return the offset of the first non-white character on the line,
or -1 if there are no non-white characters on the line */
int
firstchar(LINE *lp)
{
int off = w_left_margin(curwp);
while ( off < llength(lp) && isBlank(lgetc(lp, off)) )
off++;
if (off == llength(lp))
return -1;
return off;
}
/* return the offset of the next non-white character on the line,
or -1 if there are no more non-white characters on the line */
int
nextchar(LINE *lp, int off)
{
while (off < llength(lp)) {
if (!isSpace(lgetc(lp,off)))
return off;
off++;
}
return -1;
}
/* return the offset of the last non-white character on the line
or -1 if there are no non-white characters on the line */
int
lastchar(LINE *lp)
{
int off = llength(lp)-1;
while ( off >= 0 && isSpace(lgetc(lp, off)) )
off--;
return off;
}
/*
* Implements the vi "^M" command.
*
* Like 'forwline()', but goes to the first non-white character position.
*/
int
forwbline(int f, int n)
{
int s;
if (f == FALSE) n = 1;
if ((s = forwline(f,n)) != TRUE)
return (s);
return firstnonwhite(FALSE,1);
}
/*
* Implements the vi "-" command.
*
* Like 'backline()', but goes to the first non-white character position.
*/
int
backbline(int f, int n)
{
int s;
if (f == FALSE) n = 1;
if ((s = backline(f,n)) != TRUE)
return (s);
return firstnonwhite(FALSE,1);
}
/*
* Implements the vi "k" command.
*
* This function is like "forwline", but goes backwards.
*/
int
backline(int f, int n)
{
register LINE *dlp;
if (f == FALSE) n = 1;
if (n < 0)
return (forwline(f, -n));
/* if we are on the first line as we start....fail the command */
if (is_first_line(DOT, curbp))
return(FALSE);
/* if the last command was not note a line move,
reset the goal column */
if (curgoal < 0)
curgoal = getccol(FALSE);
/* and move the point up */
dlp = DOT.l;
while (n-- && lback(dlp) != buf_head(curbp))
dlp = lback(dlp);
/* reseting the current position */
DOT.l = dlp;
DOT.o = getgoal(dlp);
curwp->w_flag |= WFMOVE;
return (TRUE);
}
/*
* Go to the beginning of the current paragraph.
*/
int
gotobop(int f, int n)
{
MARK odot;
int was_on_empty;
int fc;
if (!f) n = 1;
was_on_empty = is_empty_line(DOT);
odot = DOT;
fc = firstchar(DOT.l);
if (doingopcmd &&
((fc >= 0 && DOT.o <= fc) || fc < 0) &&
!is_first_line(DOT,curbp)) {
backchar(TRUE,DOT.o+1);
pre_op_dot = DOT;
}
while (n) {
if (findpat(TRUE, 1, b_val_rexp(curbp,VAL_PARAGRAPHS)->reg,
REVERSE) != TRUE) {
(void)gotobob(f,n);
} else if (is_empty_line(DOT)) {
/* special case -- if we found an empty line,
and it's adjacent to where we started,
skip all adjacent empty lines, and try again */
if ( (was_on_empty && lforw(DOT.l) == odot.l) ||
(n > 0 && llength(lforw(DOT.l)) == 0) ) {
/* then we haven't really found what we
wanted. keep going */
skipblanksb();
continue;
}
}
n--;
}
if (doingopcmd) {
fc = firstchar(DOT.l);
if (!sameline(DOT,odot) &&
(pre_op_dot.o > lastchar(pre_op_dot.l)) &&
((fc >= 0 && DOT.o <= fc) || fc < 0)) {
regionshape = FULLLINE;
}
}
return TRUE;
}
/*
* Go to the end of the current paragraph.
*/
int
gotoeop(int f, int n)
{
MARK odot;
int was_at_bol;
int was_on_empty;
int fc;
if (!f) n = 1;
fc = firstchar(DOT.l);
was_on_empty = is_empty_line(DOT);
was_at_bol = ((fc >= 0 && DOT.o <= fc) || fc < 0);
odot = DOT;
while (n) {
if (findpat(TRUE, 1, b_val_rexp(curbp,VAL_PARAGRAPHS)->reg,
FORWARD) != TRUE) {
DOT = curbp->b_line;
} else if (is_empty_line(DOT)) {
/* special case -- if we found an empty line. */
/* either as the very next line, or at the end of
our search */
if ( (was_on_empty && lback(DOT.l) == odot.l) ||
(n > 0 && llength(lback(DOT.l)) == 0) ) {
/* then we haven't really found what we
wanted. keep going */
skipblanksf();
continue;
}
}
n--;
}
if (doingopcmd) {
/* if we're now at the beginning of a line and we can back up,
do so to avoid eating the newline and leading whitespace */
fc = firstchar(DOT.l);
if (((fc >= 0 && DOT.o <= fc) || fc < 0) &&
!is_first_line(DOT,curbp) &&
!sameline(DOT,odot) ) {
backchar(TRUE,DOT.o+1);
}
/* if we started at the start of line, eat the whole line */
if (!sameline(DOT,odot) && was_at_bol)
regionshape = FULLLINE;
}
return TRUE;
}
static void
skipblanksf(void)
{
while (lforw(DOT.l) != buf_head(curbp) && is_empty_line(DOT))
DOT.l = lforw(DOT.l);
}
static void
skipblanksb(void)
{
while (lback(DOT.l) != buf_head(curbp) && is_empty_line(DOT))
DOT.l = lback(DOT.l);
}
#if OPT_STUTTER_SEC_CMD
getstutter(void)
{
int thiskey;
if (!clexec) {
thiskey = lastkey;
kbd_seq();
if (thiskey != lastkey) {
return FALSE;
}
}
return TRUE;
}
#endif
/*
* Go to the beginning of the current section (or paragraph if no section
* marker found).
*/
int
gotobosec(int f, int n)
{
#if OPT_STUTTER_SEC_CMD
if (!getstutter())
return FALSE;
#endif
if (findpat(f, n, b_val_rexp(curbp,VAL_SECTIONS)->reg,
REVERSE) != TRUE) {
(void)gotobob(f,n);
}
return TRUE;
}
/*
* Go to the end of the current section (or paragraph if no section marker
* found).
*/
int
gotoeosec(int f, int n)
{
#if OPT_STUTTER_SEC_CMD
if (!getstutter())
return FALSE;
#endif
if (findpat(f, n, b_val_rexp(curbp,VAL_SECTIONS)->reg,
FORWARD) != TRUE) {
DOT = curbp->b_line;
}
return TRUE;
}
/*
* Go to the beginning of the current sentence. If we skip into an empty line
* (from a non-empty line), return at that point -- that's what vi does.
*/
int
gotobosent(int f, int n)
{
MARK savepos;
int looped = 0;
int extra;
int empty = is_empty_line(DOT);
register regexp *exp;
register int s = TRUE;
savepos = DOT;
exp = b_val_rexp(curbp,VAL_SENTENCES)->reg;
while (s && (is_at_end_of_line(DOT) || isSpace(char_at(DOT)))) {
s = backchar(TRUE,1);
if (is_at_end_of_line(DOT) && !empty)
return TRUE;
}
top:
extra = 0;
if (findpat(f, n, exp, REVERSE) != TRUE) {
return gotobob(f,n);
}
s = forwchar(TRUE, RegexpLen(exp));
while (s && (is_at_end_of_line(DOT) || isSpace(char_at(DOT)))) {
s = forwchar(TRUE,1);
extra++;
}
if (n == 1 && samepoint(savepos,DOT)) { /* try again */
if (looped > 10)
return FALSE;
s = backchar(TRUE, RegexpLen(exp) + extra + looped);
while (s && is_at_end_of_line(DOT)) {
if (!empty && is_empty_line(DOT))
return TRUE;
s = backchar(TRUE,1);
}
looped++;
goto top;
}
return TRUE;
}
/*
* Go to the end of the current sentence. Like gotobosent(), if we skip into
* an empty line, return at that point.
*/
int
gotoeosent(int f, int n)
{
register regexp *exp;
register int s;
int empty = is_empty_line(DOT);
exp = b_val_rexp(curbp,VAL_SENTENCES)->reg;
/* if we're on the end of a sentence now, don't bother scanning
further, or we'll miss the immediately following sentence */
if (!(lregexec(exp, DOT.l, DOT.o, llength(DOT.l)) &&
exp->startp[0] - DOT.l->l_text == DOT.o)) {
if (findpat(f, n, exp, FORWARD) != TRUE) {
DOT = curbp->b_line;
return TRUE;
} else {
if (!empty && is_at_end_of_line(DOT))
return TRUE;
}
}
s = forwchar(TRUE, RegexpLen(exp));
while (s && (is_at_end_of_line(DOT) || isSpace(char_at(DOT)))) {
s = forwchar(TRUE,1);
}
return TRUE;
}
/*
* This routine, given a pointer to a LINE, and the current cursor goal
* column, return the best choice for the offset. The offset is returned.
* Used by "C-N" and "C-P".
*/
int
getgoal(LINE *dlp)
{
register int c;
register int col;
register int newcol;
register int dbo;
col = 0;
dbo = w_left_margin(curwp);
while (dbo < llength(dlp)) {
c = lgetc(dlp, dbo);
newcol = next_column(c,col);
if (newcol > curgoal)
break;
col = newcol;
++dbo;
}
return (dbo);
}
int
next_sw(int col)
{
int width = shiftwid_val(curbp);
return (((col / width) + 1) * width);
}
/* return the next column index, given the current char and column */
int
next_column(int c, int col)
{
if (c == '\t')
return nextab(col);
else if (!isPrint(c))
return col+2;
else
return col+1;
}
/*
* Implements the vi "^F" command.
*
* Scroll forward by a specified number of lines, or by a full page if no
* argument.
*/
int
forwpage(int f, int n)
{
register LINEPTR lp;
int status;
if ((n = full_pages(f,n)) < 0)
return backpage(f, -n);
if ((status = (lforw(DOT.l) != buf_head(curbp))) == TRUE) {
lp = curwp->w_line.l;
n -= line_height(curwp,lp);
while (lp != buf_head(curbp)) {
lp = lforw(lp);
if ((n -= line_height(curwp,lp)) < 0)
break;
}
if (n < 0)
curwp->w_line.l = lp;
DOT.l = lp;
(void)firstnonwhite(FALSE,1);
curwp->w_flag |= WFHARD|WFMODE;
}
return status;
}
/*
* Implements the vi "^B" command.
*
* This command is like "forwpage", but it goes backwards.
*/
int
backpage(int f, int n)
{
register LINEPTR lp;
int status;
if ((n = full_pages(f,n)) < 0)
return forwpage(f, -n);
lp = curwp->w_line.l;
if (lback(lp) != buf_head(curbp)) {
while ((n -= line_height(curwp,lp)) >= 0
&& lback(lp) != buf_head(curbp))
lp = lback(lp);
curwp->w_line.l = lp;
(void)gotoeos(FALSE,1);
curwp->w_flag |= WFHARD|WFMODE;
status = TRUE;
} else if (DOT.l != lp) {
DOT.l = lp;
curwp->w_flag |= WFHARD|WFMODE;
status = TRUE;
} else {
status = FALSE;
}
return status;
}
/*
* Implements the vi "^D" command.
*
* Scroll forward by a half-page. If a repeat count is given, interpret that
* as the number of half-pages to scroll.
*
* Unlike vi, the OPT_CVMVAS option causes the repeat-count to be interpreted as
* half-page, rather than lines.
*/
int
forwhpage(int f, int n)
{
register LINEPTR llp, dlp;
int status;
if ((n = half_pages(f,n)) < 0)
return backhpage(f, -n);
llp = curwp->w_line.l;
dlp = DOT.l;
if ((status = (lforw(dlp) != buf_head(curbp))) == TRUE) {
n -= line_height(curwp,dlp);
while (lforw(dlp) != buf_head(curbp)) {
llp = lforw(llp);
dlp = lforw(dlp);
if ((n -= line_height(curwp,dlp)) < 0)
break;
}
curwp->w_line.l = llp;
DOT.l = dlp;
curwp->w_flag |= WFHARD|WFKILLS;
}
(void)firstnonwhite(FALSE,1);
return status;
}
/*
* Implements the vi "^U" command.
*
* This command is like "forwpage", but it goes backwards. It returns false
* only if the cursor is on the first line of the buffer.
*
* Unlike vi, the OPT_CVMVAS option causes the repeat-count to be interpreted as
* half-pages, rather than lines.
*/
int
backhpage(int f, int n)
{
register LINEPTR llp, dlp;
int status;
if ((n = half_pages(f,n)) < 0)
return forwhpage(f, -n);
llp = curwp->w_line.l;
dlp = DOT.l;
if ((status = (lback(dlp) != buf_head(curbp))) == TRUE) {
n -= line_height(curwp,dlp);
while (lback(dlp) != buf_head(curbp)) {
llp = lback(llp);
dlp = lback(dlp);
if ((n -= line_height(curwp,dlp)) < 0)
break;
}
curwp->w_line.l = llp;
DOT.l = dlp;
curwp->w_flag |= WFHARD|WFINS;
}
(void)firstnonwhite(FALSE,1);
return status;
}
/*
* Implements the vi "m" command.
*
* Set the named mark in the current window to the value of "." in the window.
*/
/* ARGSUSED */
int
setnmmark(int f GCC_UNUSED, int n GCC_UNUSED)
{
int c,i;
if (clexec || isnamedcmd) {
int status;
static char cbuf[2];
if ((status=mlreply("Set mark: ", cbuf, 2)) != TRUE)
return status;
c = cbuf[0];
} else {
c = keystroke();
if (ABORTED(c))
return ABORT;
}
if (c < 'a' || c > 'z') {
mlforce("[Invalid mark name]");
return FALSE;
}
if (curbp->b_nmmarks == NULL) {
curbp->b_nmmarks = typeallocn(struct MARK,26);
if (curbp->b_nmmarks == NULL)
return no_memory("named-marks");
for (i = 0; i < 26; i++) {
curbp->b_nmmarks[i] = nullmark;
}
}
curbp->b_nmmarks[c-'a'] = DOT;
mlwrite("[Mark %c set]",c);
return TRUE;
}
/* ARGSUSED */
int
golinenmmark(int f GCC_UNUSED, int n GCC_UNUSED)
{
int c;
register int s;
s = getnmmarkname(&c);
if (s != TRUE)
return s;
s = gonmmark(c);
if (s != TRUE)
return s;
return firstnonwhite(FALSE,1);
}
/* ARGSUSED */
int
goexactnmmark(int f GCC_UNUSED, int n GCC_UNUSED)
{
int c;
register int s;
s = getnmmarkname(&c);
if (s != TRUE)
return s;
return gonmmark(c);
}
/* ARGSUSED */
int
gorectnmmark(int f GCC_UNUSED, int n GCC_UNUSED)
{
int c;
register int s;
s = getnmmarkname(&c);
if (s != TRUE)
return s;
regionshape = RECTANGLE;
return gonmmark(c);
}
/* get the name of the mark to use. interactively, "last dot" is
represented by stuttering the goto-mark command. from
the command line, it's always named ' or `. I suppose
this is questionable. */
static int
getnmmarkname(int *cp)
{
int c;
int thiskey;
int useldmark;
if (clexec || isnamedcmd) {
int status;
static char cbuf[2];
if ((status=mlreply("Goto mark: ", cbuf, 2)) != TRUE)
return status;
c = cbuf[0];
useldmark = (c == '\'' || c == '`');
} else {
thiskey = lastkey;
c = keystroke();
if (ABORTED(c))
return ABORT;
useldmark = (lastkey == thiskey); /* usually '' or `` */
}
if (useldmark)
c = '\'';
*cp = c;
return TRUE;
}
int
gonmmark(int c)
{
register MARK *markp;
MARK tmark;
int found;
if (!isLower(c) && c != '\'') {
mlforce("[Invalid mark name]");
return FALSE;
}
markp = NULL;
if (c == '\'') { /* use the 'last dot' mark */
markp = &(curwp->w_lastdot);
} else if (curbp->b_nmmarks != NULL) {
markp = &(curbp->b_nmmarks[c-'a']);
}
found = FALSE;
/* if we have any named marks, and the one we want isn't null */
if (markp != NULL && !samepoint((*markp), nullmark)) {
register LINE *lp;
for_each_line(lp, curbp) {
if ((*markp).l == lp) {
found = TRUE;
break;
}
}
}
if (!found) {
mlforce("[Mark not set]");
return (FALSE);
}
/* save current dot */
tmark = DOT;
/* move to the selected mark */
DOT = *markp;
if (!doingopcmd) /* reset last-dot-mark to old dot */
curwp->w_lastdot = tmark;
curwp->w_flag |= WFMOVE;
return (TRUE);
}
/*
* Set the mark in the current window to the value of "." in the window. No
* errors are possible.
*/
int
setmark(void)
{
MK = DOT;
return (TRUE);
}
/* ARGSUSED */
int
gomark(int f GCC_UNUSED, int n GCC_UNUSED)
{
DOT = MK;
curwp->w_flag |= WFMOVE;
return (TRUE);
}
/* this odd routine puts us at the internal mark, plus an offset of lines */
/* n == 1 leaves us at mark, n == 2 one line down, etc. */
/* this is for the use of stuttered commands, and line oriented regions */
int
godotplus(int f, int n)
{
int s;
if (!f || n == 1) {
return firstnonwhite(FALSE,1);
}
if (n < 1)
return (FALSE);
s = forwline(TRUE,n-1);
if (s && is_header_line(DOT, curbp))
s = backline(FALSE,1);
if (s == TRUE)
(void)firstnonwhite(FALSE,1);
return s;
}
/*
* Swap the values of "." and "mark" in the current window. This is pretty
* easy, because all of the hard work gets done by the standard routine
* that moves the mark about. The only possible error is "no mark".
*/
void
swapmark(void)
{
MARK odot;
if (samepoint(MK, nullmark)) {
mlforce("BUG: No mark ");
return;
}
odot = DOT;
DOT = MK;
MK = odot;
curwp->w_flag |= WFMOVE;
return;
}
#if OPT_MOUSE
/*
* Given row & column from the screen, set the MK value.
* The resulting position will not be past end-of-buffer unless the buffer
* is empty.
*/
int
setwmark(int row, int col)
{
MARK save;
register LINEPTR dlp;
save = DOT;
if (row == mode_row(curwp)) {
(void) gotoeos(FALSE,1);
DOT.l = lforw(DOT.l);
DOT.o = w_left_margin(curwp);
} else { /* move to the right row */
row -= curwp->w_toprow + curwp->w_line.o;
/*
* In the statement above, wp->w_line.o will
* normally be zero. But when the top line of the
* window is wrapped and the beginning of the line
* is not visible, it will have the number of
* lines that would appear before the top line
* negated. (E.g, if the wrapped line occupied
* 2 lines before the top window line, then wp->w_line.o
* will have the value -2.)
*/
dlp = curwp->w_line.l; /* get pointer to 1st line */
while ((row -= line_height(curwp,dlp)) >= 0
&& dlp != buf_head(curbp))
dlp = lforw(dlp);
DOT.l = dlp; /* set dot line pointer */
/* now move the dot over until near the requested column */
#ifdef WMDLINEWRAP
if (w_val(curwp,WMDLINEWRAP))
col += term.t_ncol * (row+line_height(curwp,dlp));
#endif
DOT.o = col2offs(curwp, dlp, col);
#ifdef OPT_MOUSE_NEWLINE
/* don't allow the cursor to be set past end of line unless we
* are in insert mode
*/
if (DOT.o >= llength(dlp) && DOT.o > w_left_margin(curwp) &&
!insertmode)
DOT.o--;
#endif
}
if (is_header_line(DOT, curwp->w_bufp)) {
DOT.l = lback(DOT.l);
DOT.o = llength(DOT.l);
}
MK = DOT;
DOT = save;
return TRUE;
}
/*
* Given row & column from the screen, set the curwp and DOT values.
*/
int
setcursor (int row, int col)
{
register WINDOW *wp0 = curwp;
register WINDOW *wp1;
MARK saveMK;
if ((wp1 = row2window(row)) == 0)
return FALSE;
if (doingsweep && curwp != wp1)
return FALSE;
saveMK = MK;
if (set_curwp(wp1)
&& setwmark(row, col)) {
if (insertmode != FALSE
&& b_val(wp1->w_bufp, MDVIEW)
&& b_val(wp1->w_bufp, MDSHOWMODE)) {
if (b_val(wp0->w_bufp, MDSHOWMODE))
wp0->w_flag |= WFMODE;
if (b_val(wp1->w_bufp, MDSHOWMODE))
wp1->w_flag |= WFMODE;
insertmode = FALSE;
}
DOT = MK;
if (wp0 == wp1)
MK = saveMK;
curwp->w_flag |= WFMOVE;
return TRUE;
}
return FALSE;
}
#endif