/* basic.c -- implements basic.h */ #include "basic.h" /* 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 #include #include "input.h" #include "mlout.h" #include "random.h" #include "terminal.h" #include "window.h" #define CVMVAS 1 /* arguments to page forward/back in pages */ int overlap = 0 ; /* $overlap: line overlap in forw/back page */ int curgoal ; /* $target: Goal for C-P, C-N */ /* 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 unsigned getgoal( line_p dlp) { int col = 0 ; const unsigned len = llength( dlp) ; unsigned idx = 0 ; while( idx < len) { unicode_t c ; unsigned width = utf8_to_unicode( dlp->l_text, idx, len, &c) ; /* Take tabs, ^X and \xx hex characters into account */ if( c == '\t') col += tabwidth - col % tabwidth ; else if( c < 0x20 || c == 0x7F) /* ^x */ col += 2 ; else if( c >= 0x80 && c <= 0xA0) /* \xx */ col += 3 ; else { int w = utf8_width( c) ; /* work around */ col += (w < 0) ? 2 : w ; /* unknown unicode width as \u */ } if( col > curgoal) break ; else idx += width ; } return idx ; } /* Move the cursor to the beginning of the current line of active window. */ boolean gotobol( int f, int n) { curwp->w_doto = 0 ; return TRUE ; } /* Move the cursor to the end of the current line of active window. */ boolean gotoeol( int f, int n) { curwp->w_doto = llength( curwp->w_dotp) ; 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. Normally bound to "M-<". */ boolean 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->". */ boolean 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. */ boolean forwline( int f, int n) { assert( f == TRUE || n == 1) ; if( n < 0) return backline( f, -n) ; /* if we are on the last line as we start....fail the command */ if( n && curwp->w_dotp == curbp->b_linep) return FALSE ; /* if the last command was not 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 */ line_p dlp = curwp->w_dotp ; while( n && dlp != curbp->b_linep) { dlp = lforw( dlp) ; n -= 1 ; } /* reseting the current position */ curwp->w_dotp = dlp ; curwp->w_doto = getgoal( dlp) ; curwp->w_flag |= WFMOVE ; return (n == 0) ? TRUE : FALSE ; } /* 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". */ boolean backline( int f, int n) { if( n < 0) return forwline( f, -n) ; /* if we are on the first line as we start....fail the command */ if( n && lback( curwp->w_dotp) == curbp->b_linep) return FALSE ; /* if the last command was not 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 */ line_p dlp = curwp->w_dotp ; while( n && lback( dlp) != curbp->b_linep) { dlp = lback( dlp) ; n -= 1 ; } /* reseting the current position */ curwp->w_dotp = dlp ; curwp->w_doto = getgoal( dlp) ; curwp->w_flag |= WFMOVE ; return (n == 0) ? TRUE : FALSE ; } /* Move to a particular line. * * @n: The specified line position at the current buffer. */ BINDABLE( gotoline) { /* Get an argument if one doesn't exist. */ if( f == FALSE) { char *arg ; /* Buffer to hold argument. */ int status = newmlarg( &arg, "goto-line: ", 0) ; if( status != TRUE) return status ; n = atoi( arg) ; free( arg) ; f = TRUE ; } /* Handle the case where the user may be passed something like this: * ue 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 (n == 1) ? TRUE : forwline( TRUE, n - 1) ; } /* 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. */ boolean forwpage( int f, int n) { line_p lp ; if( f == FALSE) { #if SCROLLCODE if (term.t_scroll != NULL) /* $scroll == FALSE */ if (overlap == 0) /* $overlap == 0 */ n = curwp->w_ntrows * 2 / 3 ; 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; */ lp = curwp->w_dotp ; while( n && lp != curbp->b_linep) { lp = lforw( lp) ; n -= 1 ; } /* curwp->w_linep = lp; */ curwp->w_dotp = lp; curwp->w_doto = 0; reposition( TRUE, 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. */ boolean backpage( int f, int n) { line_p lp ; if( f == FALSE) { /* interactive, default n = 1 supplied */ /* in interactive mode, first move dot to top of window */ if( curwp->w_dotp != curwp->w_linep) { curwp->w_dotp = curwp->w_linep ; curwp->w_doto = 0 ; /* curwp->w_flag |= WFMOVE ; */ return TRUE ; } #if SCROLLCODE if (term.t_scroll != NULL) /* $scroll != FALSE */ if (overlap == 0) /* $overlap == 0 */ n = curwp->w_ntrows * 2 / 3 ; 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; */ lp = curwp->w_dotp ; while( n && lback( lp) != curbp->b_linep) { lp = lback( lp) ; n -= 1 ; } /* curwp->w_linep = lp; */ curwp->w_dotp = lp; curwp->w_doto = 0; reposition( TRUE, (f == FALSE) ? 1 : 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-. set-mark. */ boolean setmark( int f, int n) { curwp->w_markp = curwp->w_dotp ; curwp->w_marko = curwp->w_doto ; mloutstr( "(Mark set)") ; return TRUE ; } /* Swap the values of "." and "mark" in the current window. If no mark as been previously set, set it. Bound to C-X C-X exchange-point-and-mark. */ boolean swapmark( int f, int n) { line_p odotp = curwp->w_dotp ; int odoto = curwp->w_doto ; if( curwp->w_markp) { curwp->w_dotp = curwp->w_markp ; curwp->w_doto = curwp->w_marko ; curwp->w_flag |= WFMOVE ; } curwp->w_markp = odotp ; curwp->w_marko = odoto ; return TRUE ; } /* end of basic.c */