blob: 3a7d6f72fdbea445c09b99f637aa7b96bb652a02 [file] [log] [blame]
/* basic.c
*
* 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.
*
* modified by Petri Kutvonen
*/
#include <stdio.h>
#include "estruct.h"
#include "edef.h"
#include "efunc.h"
#include "line.h"
#include "utf8.h"
/*
* This routine, given a pointer to a struct 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".
*/
static int getgoal(struct line *dlp)
{
int c;
int col;
int newcol;
int dbo;
col = 0;
dbo = 0;
while (dbo != llength(dlp)) {
c = lgetc(dlp, dbo);
newcol = col;
if (c == '\t')
newcol |= tabmask;
else if (c < 0x20 || c == 0x7F)
++newcol;
++newcol;
if (newcol > curgoal)
break;
col = newcol;
++dbo;
}
return dbo;
}
/*
* Move the cursor to the beginning of the current line.
*/
int gotobol(int f, int n)
{
curwp->w_doto = 0;
return TRUE;
}
/*
* 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)
{
struct line *lp;
if (n < 0)
return forwchar(f, -n);
while (n--) {
if (curwp->w_doto == 0) {
if ((lp = lback(curwp->w_dotp)) == curbp->b_linep)
return FALSE;
curwp->w_dotp = lp;
curwp->w_doto = llength(lp);
curwp->w_flag |= WFMOVE;
} else {
do {
unsigned char c;
curwp->w_doto--;
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (is_beginning_utf8(c))
break;
} while (curwp->w_doto);
}
}
return TRUE;
}
/*
* Move the cursor to the end of the current line. Trivial. No errors.
*/
int gotoeol(int f, int n)
{
curwp->w_doto = llength(curwp->w_dotp);
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 (n < 0)
return backchar(f, -n);
while (n--) {
int len = llength(curwp->w_dotp);
if (curwp->w_doto == len) {
if (curwp->w_dotp == curbp->b_linep)
return FALSE;
curwp->w_dotp = lforw(curwp->w_dotp);
curwp->w_doto = 0;
curwp->w_flag |= WFMOVE;
} else {
do {
unsigned char c;
curwp->w_doto++;
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (is_beginning_utf8(c))
break;
} while (curwp->w_doto < len);
}
}
return TRUE;
}
/*
* Move to a particular line.
*
* @n: The specified line position at the current buffer.
*/
int gotoline(int f, int n)
{
int status;
char arg[NSTRING]; /* Buffer to hold argument. */
/* Get an argument if one doesnt exist. */
if (f == FALSE) {
if ((status =
mlreply("Line to GOTO: ", arg, NSTRING)) != TRUE) {
mlwrite("(Aborted)");
return status;
}
n = atoi(arg);
}
/* Handle the case where the user may be passed something like this:
* em filename +
* In this case we just go to the end of the buffer.
*/
if (n == 0)
return gotoeob(f, n);
/* If a bogus argument was passed, then returns false. */
if (n < 0)
return FALSE;
/* First, we go to the begin of the buffer. */
gotobob(f, n);
return forwline(f, n - 1);
}
/*
* 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. Normally bound to "M-<".
*/
int gotobob(int f, int n)
{
curwp->w_dotp = lforw(curbp->b_linep);
curwp->w_doto = 0;
curwp->w_flag |= WFHARD;
return TRUE;
}
/*
* Move to the end of the buffer. Dot is always put at the end of the file
* (ZJ). The standard screen code does most of the hard parts of update.
* Bound to "M->".
*/
int gotoeob(int f, int n)
{
curwp->w_dotp = curbp->b_linep;
curwp->w_doto = 0;
curwp->w_flag |= WFHARD;
return TRUE;
}
/*
* 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. Bound to "C-N". No errors are
* possible.
*/
int forwline(int f, int n)
{
struct line *dlp;
if (n < 0)
return backline(f, -n);
/* if we are on the last line as we start....fail the command */
if (curwp->w_dotp == curbp->b_linep)
return FALSE;
/* if the last command was not note a line move,
reset the goal column */
if ((lastflag & CFCPCN) == 0)
curgoal = getccol(FALSE);
/* flag this command as a line move */
thisflag |= CFCPCN;
/* and move the point down */
dlp = curwp->w_dotp;
while (n-- && dlp != curbp->b_linep)
dlp = lforw(dlp);
/* reseting the current position */
curwp->w_dotp = dlp;
curwp->w_doto = getgoal(dlp);
curwp->w_flag |= WFMOVE;
return TRUE;
}
/*
* This function is like "forwline", but goes backwards. The scheme is exactly
* the same. Check for arguments that are less than zero and call your
* alternate. Figure out the new line and call "movedot" to perform the
* motion. No errors are possible. Bound to "C-P".
*/
int backline(int f, int n)
{
struct line *dlp;
if (n < 0)
return forwline(f, -n);
/* if we are on the last line as we start....fail the command */
if (lback(curwp->w_dotp) == curbp->b_linep)
return FALSE;
/* if the last command was not note a line move,
reset the goal column */
if ((lastflag & CFCPCN) == 0)
curgoal = getccol(FALSE);
/* flag this command as a line move */
thisflag |= CFCPCN;
/* and move the point up */
dlp = curwp->w_dotp;
while (n-- && lback(dlp) != curbp->b_linep)
dlp = lback(dlp);
/* reseting the current position */
curwp->w_dotp = dlp;
curwp->w_doto = getgoal(dlp);
curwp->w_flag |= WFMOVE;
return TRUE;
}
#if WORDPRO
/*
* go back to the beginning of the current paragraph
* here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
* combination to delimit the beginning of a paragraph
*
* int f, n; default Flag & Numeric argument
*/
int gotobop(int f, int n)
{
int suc; /* success of last backchar */
if (n < 0) /* the other way... */
return gotoeop(f, -n);
while (n-- > 0) { /* for each one asked for */
/* first scan back until we are in a word */
suc = backchar(FALSE, 1);
while (!inword() && suc)
suc = backchar(FALSE, 1);
curwp->w_doto = 0; /* and go to the B-O-Line */
/* and scan back until we hit a <NL><NL> or <NL><TAB>
or a <NL><SPACE> */
while (lback(curwp->w_dotp) != curbp->b_linep)
if (llength(curwp->w_dotp) != 0 &&
#if PKCODE
((justflag == TRUE) ||
#endif
(lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
lgetc(curwp->w_dotp, curwp->w_doto) != ' '))
#if PKCODE
)
#endif
curwp->w_dotp = lback(curwp->w_dotp);
else
break;
/* and then forward until we are in a word */
suc = forwchar(FALSE, 1);
while (suc && !inword())
suc = forwchar(FALSE, 1);
}
curwp->w_flag |= WFMOVE; /* force screen update */
return TRUE;
}
/*
* Go forword to the end of the current paragraph
* here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
* combination to delimit the beginning of a paragraph
*
* int f, n; default Flag & Numeric argument
*/
int gotoeop(int f, int n)
{
int suc; /* success of last backchar */
if (n < 0) /* the other way... */
return gotobop(f, -n);
while (n-- > 0) { /* for each one asked for */
/* first scan forward until we are in a word */
suc = forwchar(FALSE, 1);
while (!inword() && suc)
suc = forwchar(FALSE, 1);
curwp->w_doto = 0; /* and go to the B-O-Line */
if (suc) /* of next line if not at EOF */
curwp->w_dotp = lforw(curwp->w_dotp);
/* and scan forword until we hit a <NL><NL> or <NL><TAB>
or a <NL><SPACE> */
while (curwp->w_dotp != curbp->b_linep) {
if (llength(curwp->w_dotp) != 0 &&
#if PKCODE
((justflag == TRUE) ||
#endif
(lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
lgetc(curwp->w_dotp, curwp->w_doto) != ' '))
#if PKCODE
)
#endif
curwp->w_dotp = lforw(curwp->w_dotp);
else
break;
}
/* and then backward until we are in a word */
suc = backchar(FALSE, 1);
while (suc && !inword()) {
suc = backchar(FALSE, 1);
}
curwp->w_doto = llength(curwp->w_dotp); /* and to the EOL */
}
curwp->w_flag |= WFMOVE; /* force screen update */
return TRUE;
}
#endif
/*
* Scroll forward by a specified number of lines, or by a full page if no
* argument. Bound to "C-V". The "2" in the arithmetic on the window size is
* the overlap; this value is the default overlap value in ITS EMACS. Because
* this zaps the top line in the display window, we have to do a hard update.
*/
int forwpage(int f, int n)
{
struct line *lp;
if (f == FALSE) {
#if SCROLLCODE
if (term.t_scroll != NULL)
if (overlap == 0)
n = curwp->w_ntrows / 3 * 2;
else
n = curwp->w_ntrows - overlap;
else
#endif
n = curwp->w_ntrows - 2; /* Default scroll. */
if (n <= 0) /* Forget the overlap. */
n = 1; /* If tiny window. */
} else if (n < 0)
return backpage(f, -n);
#if CVMVAS
else /* Convert from pages. */
n *= curwp->w_ntrows; /* To lines. */
#endif
lp = curwp->w_linep;
while (n-- && lp != curbp->b_linep)
lp = lforw(lp);
curwp->w_linep = lp;
curwp->w_dotp = lp;
curwp->w_doto = 0;
#if SCROLLCODE
curwp->w_flag |= WFHARD | WFKILLS;
#else
curwp->w_flag |= WFHARD;
#endif
return TRUE;
}
/*
* This command is like "forwpage", but it goes backwards. The "2", like
* above, is the overlap between the two windows. The value is from the ITS
* EMACS manual. Bound to "M-V". We do a hard update for exactly the same
* reason.
*/
int backpage(int f, int n)
{
struct line *lp;
if (f == FALSE) {
#if SCROLLCODE
if (term.t_scroll != NULL)
if (overlap == 0)
n = curwp->w_ntrows / 3 * 2;
else
n = curwp->w_ntrows - overlap;
else
#endif
n = curwp->w_ntrows - 2; /* Default scroll. */
if (n <= 0) /* Don't blow up if the. */
n = 1; /* Window is tiny. */
} else if (n < 0)
return forwpage(f, -n);
#if CVMVAS
else /* Convert from pages. */
n *= curwp->w_ntrows; /* To lines. */
#endif
lp = curwp->w_linep;
while (n-- && lback(lp) != curbp->b_linep)
lp = lback(lp);
curwp->w_linep = lp;
curwp->w_dotp = lp;
curwp->w_doto = 0;
#if SCROLLCODE
curwp->w_flag |= WFHARD | WFINS;
#else
curwp->w_flag |= WFHARD;
#endif
return TRUE;
}
/*
* Set the mark in the current window to the value of "." in the window. No
* errors are possible. Bound to "M-.".
*/
int setmark(int f, int n)
{
curwp->w_markp = curwp->w_dotp;
curwp->w_marko = curwp->w_doto;
mlwrite("(Mark set)");
return TRUE;
}
/*
* Swap the values of "." and "mark" in the current window. This is pretty
* easy, bacause all of the hard work gets done by the standard routine
* that moves the mark about. The only possible error is "no mark". Bound to
* "C-X C-X".
*/
int swapmark(int f, int n)
{
struct line *odotp;
int odoto;
if (curwp->w_markp == NULL) {
mlwrite("No mark in this window");
return FALSE;
}
odotp = curwp->w_dotp;
odoto = curwp->w_doto;
curwp->w_dotp = curwp->w_markp;
curwp->w_doto = curwp->w_marko;
curwp->w_markp = odotp;
curwp->w_marko = odoto;
curwp->w_flag |= WFMOVE;
return TRUE;
}