home *** CD-ROM | disk | FTP | other *** search
- /* edit.c-- Low-Level Workhorse Functions */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <ctype.h>
- #include <dos.h>
- #include <conio.h>
- #include <string.h>
- #include <tools/viewport.h>
- #include <tools/textbuf.h>
-
- #include <tools/window.h>
-
- /* Interface functions to test the edit engine. They are described
- * in engine.h
- *
- * These functions are used internally, they do not interface
- * with the edit engine:
- */
-
- static int draw (win *const p, int ask_top, int ask_left );
- static int hscroll (win *const p, int left);
- static int bottom (win *const p, int offset);
- static int del_line(win *const p, textbuf *const b,int which_line);
- static int export (win *const p, textbuf *const b,int which_line);
- static void status (win *const p, char *fmt, ... );
-
- /*------------------------------------------------------------*/
- int e_open( win *const this )
- {
- /* Called when engine for a specific window is opened.
- * Try to initialize buffer by importing the top few lines.
- * On the first call, the import function should take care
- * of both opening the file and adjusting this->bottom to hold
- * the line number of the bottom line in the file. It should
- * set up the line-number table at this time, as well.
- */
-
- textbuf *b = &this->b;
- int nrows = b_nrows(b);
- int row, i;
- char *new_line;
-
- if( this->import )
- {
- for( row = 0; row < nrows; ++row )
- {
- if( !(new_line = (*this->import)(this,row)) )
- break;
-
- bottom( this, +1 );
- b_gotorc(b, row, 0);
- for( i = b_ncols(b); --i >= 0 && *new_line ;)
- *b_advance(b) = *new_line++;
- }
- e_gotorc(this,0,0);
- draw (this,0,0);
- }
- return 1;
- }
- /*------------------------------------------------------------*/
- int e_close( win *const this )
- {
- /* Prepare for closing the window. Save the window state by
- * exporting the current buffer and various important offsets.
- * This function may be called several times.
- */
-
- textbuf *b = &this->b;
- viewport *v = &this->v;
- int nrows = b_nrows(b);
- int row;
-
- if( this->export )
- {
- for( row = 0; row < nrows && row <= this->bottom; ++row )
- {
- b_gotorc(b, row, 0);
- if( !export( this, b, this->file_off + row ) )
- break;
- }
- status( this, "%%%% row, viewport = %d %%%%",v_row(v) );
- status( this, "%%%% col, viewport = %d %%%%",v_col(v) );
- status( this, "%%%% row, offset = %d %%%%",this->row_off );
- status( this, "%%%% col, offset = %d %%%%",this->col_off );
- status( this, "%%%% file offset = %d %%%%",this->file_off);
- }
- return 1;
- }
- /*------------------------------------------------------------
- * Little stuff:
- * e_vrow Current viewport row (top == 0).
- * e_vcol Current viewport column (left == 0).
- * e_vnrows Number of rows in viewport.
- * e_vncols Number of columns in viewport.
- * e_isword True if c argument is a "word".
- * e_maxrow Largest virtual (file) row index
- * e_maxcol Largest virtual (file and buffer) column index
- * e_col Current virtual (file and buffer) cursor column
- * e_row Current virtual (file) cursor row
- * e_cur Character at current cursor position.
- * e_last Index of rightmost nonwhite character on line,
- * zero if the line is blank.
- */
-
- #pragma warn -par /* turn off warnings about arguments not used */
-
- int e_vrow (win *const w) { return v_row (&w->v); }
- int e_vcol (win *const w) { return v_col (&w->v); }
- int e_vnrows (win *const w) { return v_nrows (&w->v); }
- int e_vncols (win *const w) { return v_ncols (&w->v); }
- int e_isword (win *const w,
- int c) { return( isalnum(c) || c=='_' );}
- int e_maxrow (win *const w) { return w->bottom; }
- int e_maxcol (win *const w) { return b_ncols(&w->b) -1; }
- int e_col (win *const w) { return b_col(&w->b); }
- int e_row (win *const w) { return b_row(&w->b)
- + w->file_off;}
- int e_cur (win *const w) { return *b_current(&w->b); }
- int e_last (win *const w) { return b_last(&w->b); }
-
- #pragma warn +par
- /*------------------------------------------------------------
- * e_attention() and e_error();
- *
- * e_attention() rings the bell if not a horizontal motion. In
- * any event it sets the window's error flag.
- * e_error() returns the value of the flag and resets the
- * flag to zero.
- */
-
- void e_attention(win *const this, int h)
- {
- if(!h)
- putchar('\a');
- this->error = 1;
- }
-
- int e_error( win *const this )
- {
- int rv = this->error;
- this->error = 0;
- return rv;
- }
- /*------------------------------------------------------------*/
- int e_first (win *const this)
- {
- // Return the column index of the first nonwhite character
- // on the current line or 0 if the line is blank
-
- textbuf *const b = &this->b;
- int start_col = b_col(b);
- int start_row = b_row(b);
- int last_col = b_ncols(b) - 1;
- int col;
-
- b_gotorc(b, start_row, 0);
- for( col = 0; (col<last_col) && isspace(*b_current(b)); )
- {
- ++col;
- b_advance(b);
- }
- if( isspace(*b_current(b)) ) /* line was entirely blank */
- col = 0;
- b_gotorc( b, start_row, start_col );
- return col;
- }
- /*------------------------------------------------------------*/
- int e_find_c(win *const this, int c, int forward, int incl)
- {
- /* If the character is found on the current line (to the
- * right of the current cursor position if "forward" is true,
- * to the left otherwise) return the column index of c.
- * Otherwise return -1. If "incl" is false, return the index
- * of the character next to the c rather than the index of
- * c itself.
- */
-
- textbuf *b = &this->b;
- int row = b_row(b);
- int col = b_col(b);
- int last = b_last(b);
- int start_col = col;
- int rv = -1;
-
- if( forward ) forward = 1;
- else forward = -1;
-
- col += forward; /* start search at least one column */
- if( !incl ) /* away if not inclusive, add one more */
- col += forward;
-
- if( !(0 <= col && col <= last) ) /* col isn't on the line */
- rv = -1;
- else
- {
- b_gotorc(b, row, col);
- while( *b_current(b) != c && !b_ateol(b) )
- {
- col += forward;
- b_gotorc(b, row, col);
- }
- rv = (*b_current(b) == c) ? col : -1 ;
-
- if(rv != -1 && !incl) /* if not including, */
- if( (rv -= forward) < 0 ) /* back up a notch */
- rv = -1;
-
- b_gotorc(b, row, start_col);
- }
- return rv;
- }
- /*------------------------------------------------------------*/
- static void status( win *const this, char *fmt, ... )
- {
- /* works like fprintf, but outputs string using the
- * current window's export function. String is exported as
- * line -1.
- */
-
- char scratch[W_LINEMAX];
- va_list args;
- int len;
- if( this->export )
- {
- va_start(args, fmt);
- len = vsprintf(scratch, fmt, args);
- va_end(args);
- (*this->export)( this, -1, scratch, len+1, len );
- }
- }
- /*---------------------------------------------------------------*/
- static int export( win *const this,textbuf *const b,int which_line)
- {
- /* Export current buffer-cursor line as line which_line,
- * cursor does not move.
- */
-
- int row = b_row(b);
- int col = b_col(b);
-
- char scratch[W_LINEMAX];
- char *p;
- int i;
-
- if( this->export )
- {
- b_gotorc(b,row,0);
- for(p=scratch, i=b_ncols(b); --i >= 0; )
- *p++ = *b_advance(b);
-
- b_gotorc(b,row,col);
- (*this->export)( this, which_line, scratch, b_ncols(b),
- b_last (b)+1);
- return 1;
- }
- return 0;
- }
- /*------------------------------------------------------------*/
- static int del_line( win *const this, textbuf *const b,
- int which_line )
- {
- /* export current buffer-cursor line for delete, cursor */
- /* does not move. */
-
- int row = b_row(b);
- int col = b_col(b);
-
- char scratch[W_LINEMAX];
- char *p;
- int i;
-
- if( this->remove )
- {
- b_gotorc(b,row,0);
- for(p=scratch, i=b_ncols(b); --i >= 0; )
- *p++ = *b_advance(b);
-
- b_gotorc(b,row,col);
- (*this->remove)( this, which_line, scratch,
- b_ncols(b), b_last(b)+1);
- return 1;
- }
- return 0;
- }
- /*------------------------------------------------------------*/
- int e_vscroll( win *const this, int up, int import )
- {
- /* Scroll text up one line if if up > 0, down otherwise. If
- * import is true, the scroll won't happen unless a new top
- * or bottom line can be imported from the overflow file. If
- * it's false, the scroll always happens, no attempt is made
- * to do an import, and the bottom (or top) line will be
- * filled with blanks. Return true on success, false
- * otherwise.
- */
-
- viewport *const v = &this->v ;
- textbuf *const b = &this->b ;
- int rv = 1; /* return value */
- int brow = b_row(b); /* buffer row/column */
- int bcol = b_col(b);
- int vrow = v_row(v); /* viewport row/column */
- int vcol = v_col(v);
- int i;
- char *new_line;
-
- if( up > 0 ) /* Move text up, viewport moves down */
- { /* relative to buffer */
-
- if( (this->row_off + v_nrows(v)) < b_nrows(b) )
- {
- /* Viewport isn't banged up against bottom of
- * buffer. Slide viewport over text, but don't have
- * to modify buffer. Position buffer cursor at left
- * edge of line with which to fill the viewport's
- * opened up bottom line: the buffer line corres-
- * ponding to the one just below the viewport.
- * Slide the viewport by incrementing row_off.
- */
- b_gotorc(b, this->row_off+v_nrows(v), this->col_off);
- ++this->row_off;
- }
- else if( !import ) /* import is suppressed */
- {
- new_line = ""; /* pretend we got an empty line */
- goto got_bot;
- }
- else if( !this->import ) /* try to import bottom line */
- {
- rv = 0; /* no import function */
- goto exit;
- }
- else if( (i = this->file_off + b_nrows(b)) > this->bottom )
- {
- rv = 0; /* line doesn't exist */
- goto exit;
- }
- else if( !(new_line = (*this->import)(this,i)) )
- {
- rv = 0; /* couldn't import it */
- goto exit;
- }
- else /* got the line, add it to the buffer & viewport */
- {
- got_bot:
- b_gotorc(b, 0, 0); /* export the top line */
- export (this, b, this->file_off );
-
- ++this->file_off ;
- b_closedown (b, ' '); /* delete top line and move */
- /* following text up. */
-
- b_gotorc(b, b_nrows(b)-1, 0); /* buffer=new last line */
- for( i = b_ncols(b); --i >= 0 && *new_line ;)
- *b_advance(b) = *new_line++;
- b_gotorc(b, b_nrows(b)-1, 0); /* Cursor to line start */
- --brow; /* make cursor track previous position */
- }
-
- /* Scroll the viewport text up one line, then copy the
- * associated text for the bottom line from the buffer
- * to the viewport.
- */
-
- if( !this->update )
- {
- if( vrow == 0 ) /* Old line is gone */
- {
- /* col of new top line */
- b_gotorc(b, this->row_off, bcol);
- }
- else
- b_gotorc(b, brow, bcol );
- }
- else
- {
- v_scroll(v, 1, 0); /* scroll up one line */
- v_gotorc(v, v_nrows(v)-1, 0); /* last line, column 0 */
-
- /* copy buffer to screen */
- for(i = v_ncols(v); --i >= 0 ;)
- v_putc(v, *b_advance(b), 1 );
-
- if( vrow == 0 ) /* Old line is gone */
- { /* can't restore cursor */
- b_gotorc(b, this->row_off, bcol);
- v_gotorc(v, 0, vcol);
- }
- else /* restore original cursor position */
- {
- b_gotorc(b, brow, bcol );
- v_gotorc(v, vrow-1, vcol );
- }
- }
- }
- else /* Move text down, viewport moves up */
- { /* relative to buffer */
- if( this->row_off > 0 )
- {
- /* Viewport isn't banged up against top of buffer.
- * Slide viewport over text. Position buffer cursor
- * at left edge of line with which to fill the
- * viewport's opened-up top line. Note that b_gotorc()
- * has side effects so the -- must be done separately.
- */
- --this->row_off;
- b_gotorc(b, this->row_off, this->col_off );
- }
- else if( this->file_off <= 0 )
- {
- rv = 0; /* may not scroll past initial top line */
- goto exit;
- }
- else if( !import ) /* import is suppressed */
- {
- new_line = ""; /* pretend we got an empty line */
- goto got_top;
- }
- else if(!this->import ) /* try to import new top line */
- {
- rv = 0; /* No import function */
- goto exit;
- }
- else if( this->file_off <= 0 )
- {
- rv = 0; /* Line doesn't exist */
- goto exit;
- }
- else if(!(new_line=(*this->import)(this,this->file_off-1)))
- {
- rv = 0; /* Couldn't import new line */
- goto exit;
- }
- else /* got the line, add it to the buffer & viewport */
- {
- got_top:
- --this->file_off;
- b_gotorc (b, b_nrows(b)-1, 0); /* export bottom line */
- export (this, b, this->file_off + b_nrows(b) );
- b_closeup (b, ' ' ); /* delete bottom line */
-
- b_gotorc(b, 0, 0); /* buffer = new top line */
- for( i = b_ncols(b); --i >= 0 && *new_line ;)
- *b_advance(b) = *new_line++;
- b_gotorc(b, 0, 0); /* Cursor to start of new line */
- ++brow; /* cursor tracks previous position */
- }
-
- /* Scroll the viewport text down one line, then copy the
- * associated text for the top line from the buffer to the
- * viewport.
- */
-
- if( !this->update )
- {
- if(vrow >= v_nrows(v)-1) /* Old line is gone */
- b_gotorc(b, this->row_off + v_nrows(v)-1, bcol);
- else
- b_gotorc(b, brow, bcol );
- }
- else
- {
- v_scroll(v, -1, 0); /* scroll down 1 line */
- v_gotorc(v, 0, 0); /* first line, col. 0 */
- for(i = v_ncols(v); --i >= 0 ;) /* screen = buffer */
- v_putc(v, *b_advance(b), 1 );
-
- if(vrow >= v_nrows(v)-1) /* Old line is gone */
- {
- /* Can't restore old cursor position because the */
- /* line's not there anymore. go to the original */
- /* column, but of the new bottom line */
-
- b_gotorc(b, this->row_off + v_nrows(v)-1, bcol);
- v_gotorc(v, v_nrows(v)-1, vcol);
- }
- else /* Otherwise restore original cursor to be */
- { /* under original character */
- b_gotorc(b, brow, bcol );
- v_gotorc(v, vrow+1, vcol );
- }
- }
- }
- exit:
- monitor(this, UPDATE);
- return rv;
- }
- /*------------------------------------------------------------*/
- int draw( win *const this, int ask_top, int ask_left )
- {
- /* Fill the viewport with text from the buffer, the viewport
- * is at offset "top" from the top line of the buffer and
- * "left" from the left edge of the buffer. Cursor doesn't
- * move with respect to the viewport. Top and left are
- * truncated if necessary to prevent the viewport from
- * moving off the edge of the buffer. Return false if the
- * coordinates were modified to draw things, true otherwise.
- */
-
- viewport *const v = &this->v;
- textbuf *const b = &this->b;
- int col = 0;
- int row = 0;
- int nrows = v_nrows( v );
- int ncols = v_ncols( v );
- const int left = max(0, min(ask_left, b_ncols(b)-v_ncols(v)));
- const int top = max(0, min(ask_top, b_nrows(b)-v_nrows(v)));
- int cur_top = top;
- int start_row = v_row(v);
- int start_col = v_col(v);
-
- if( !this->update ) /* no updating, pretend we succeeded */
- return 1;
-
- while( --nrows >= 0 )
- {
- /* both b_gotorc and v_gotorc have side effects */
-
- b_gotorc( b, cur_top, left ); ++cur_top;
- v_gotorc( v, row, 0 ); ++row;
-
- for( col = ncols; --col> 0 ;) /* all but last char. */
- v_putc(v, *b_advance(b), 1 );
- v_putc(v, *b_current(b), 0 ); /* last character. */
- }
-
- this->row_off = top;
- this->col_off = left;
- v_gotorc(v, start_row, start_col );
- b_gotorc(b, start_row + top, start_col + left );
-
- monitor(this, UPDATE);
- return( top == ask_top && left == ask_left );
- }
- /*------------------------------------------------------------*/
- static int hscroll( win *const this, int left )
- {
- /* Scroll horizontally, "left" columns to the left (right if
- * negative). There's no import/export feature here, so a
- * scroll past the edge of the buffer is illegal. Return true
- * if you moved the required number of columns, false if not.
- * Note that there still might have been motion in the earlier
- * case, just not enough of it. A request of zero columns
- * to the left just does a redraw.
- */
-
- return draw( this, this->row_off, this->col_off + left);
- }
- /*------------------------------------------------------------*/
- int e_update( win *const this, int enable )
- {
- /* If "enable" is false, store a snapshot of the current
- * viewport and file states. If it's true, attempt to restore
- * previous state (cursor position and relative positions
- * of the file, buffer, and viewport).
- *
- * This routine is meant primarily to disable screen updating
- * while the file is being examined. Return 1 if you change
- * state 1 if the current state is requested.
- */
-
- if( this->update == enable ) /* nothing to do */
- return 0;
-
- if( !enable ) /* disabling */
- {
- this->update = 0;
- this->update_row_off = this->row_off;
- this->update_col_off = this->col_off;
- this->update_file_off = this->file_off;
- this->update_row = e_row(this);
- this->update_col = e_col(this);
- this->dirty = 0;
- }
- else /* enabling */
- {
- /* Get the cursor back to the original place with
- * an e_gotorc(), then scroll the screen as necessary
- * to get the cursor positioned correctly relative to
- * the viewport.
- */
-
- e_gotorc( this, this->update_row, this->update_col );
-
- while( this->file_off < this->update_file_off )
- if( !e_vscroll(this, 1, 1) )
- break;
- while( this->file_off > this->update_file_off )
- if( !e_vscroll(this, 0, 1) )
- break;
-
- while( this->row_off < this->update_row_off )
- if( !e_vscroll(this, 1, 1) )
- break;
- while( this->row_off > this->update_row_off )
- if( !e_vscroll(this, 0, 1) )
- break;
-
- this->update = 1;
- if( this->col_off != this->update_col_off )
- fprintf(stderr,"INTERNAL WINDOW ERROR: "
- "unexpected horiz motion\n");
-
- if( this->dirty )
- draw( this, this->row_off, this->col_off );
- }
- monitor(this, UPDATE);
- return 1;
- }
- /*------------------------------------------------------------*/
- int e_gotorc( win *const this, int dst_r, int dst_c )
- {
- /* Go to the indicated virtual row and column. If r and c
- * are inside the viewport, just go there. If not, scroll
- * the viewport as appropriate. New lines are imported if
- * you request a row address that is not in the buffer.
- * Note that this subroutine might be used to add lines to
- * the end of the file (by going down from the last line).
- */
-
- viewport *const v = &this->v;
- textbuf *const b = &this->b;
- int rv = 1; /* return value */
- int r, c;
- int nrows = v_nrows( v );
- int ncols = v_ncols( v );
-
- switch( dst_r )
- {
- case E_HOME: dst_r = this->row_off; break;
- case E_MID: dst_r = this->row_off + nrows/2; break;
- case E_LAST: dst_r = this->row_off + nrows-1; break;
- }
- r = dst_r;
-
- if( !(0 <= dst_c && dst_c < b_ncols(b)) || r < 0 )
- {
- rv = 0; // Illegal address
- goto exit;
- }
- c = dst_c;
-
- /* Get the desired column into the viewport, starting with
- * column index:
- * Modify c to hold the distance that c is from the right
- * of the viewport. For example, c will be 0 if it's
- * the first column past the one in the right edge of the
- * viewport. If c is -1, it's at the right edge of the
- * viewport. If it's -ncols then it's at the left edge of
- * the viewport. Then, scroll as necessary to get c into
- * the viewport.
- */
-
- c -= this->col_off + ncols;
- if( c >= 0 )
- {
- while( c-- >= 0 )
- if( !hscroll(this, 1) ) /* scroll left */
- {
- rv = 0;
- goto exit;
- }
- }
- else if( c < -ncols )
- {
- c += ncols; /* c = -1 ==> 1 col to left of viewport. */
- while( ++c <= 0 )
- if( !hscroll(this, -1) ) /* scroll right */
- {
- rv = 0;
- goto exit;
- }
- }
-
- /* Do the same thing with the vertical coordinate. The
- * situation is more complicated here, though, because the row
- * coordinate is file relative. In other words:
- *
- * r == file_off + row_off + v_row(v)
- *
- * After the subtract, below, r will hold the distance between
- * the top of the viewport and the desired row, negative if
- * the desired row is above the viewport.
- */
-
- r -= this->row_off + this->file_off;
- if( r < 0 ) /* desired row is above viewport */
- {
- while( ++r <= 0 )
- if( !e_vscroll(this, -1, 1) ) /* scroll text down */
- {
- rv = 0;
- goto exit;
- }
- }
- else if( r >= nrows )
- for( r -= (nrows-1); --r >= 0 ;)
- if( !e_vscroll(this, 1,1) ) /* scroll text up */
- {
- rv = 0;
- goto exit;
- }
-
- /* the desired cursor is now in the viewport. Go there. */
-
- b_gotorc(b, dst_r - this->file_off, dst_c);
- if( this->update )
- v_gotorc(v, dst_r - this->row_off - this->file_off,
- dst_c - this->col_off );
- exit:
- monitor(this, UPDATE);
- return rv;
- }
- /*------------------------------------------------------------*/
- static int bottom(win *const this, int offset )
- {
- /* if offset isn't zero, set bottom to it's current
- * value + offset, otherwise set it to the current line.
- */
-
- if( !offset )
- {
- int lineno = b_row(&this->b) + this->file_off;
- if( lineno > this->bottom )
- this->bottom = lineno;
- }
- else if( (this->bottom += offset) < -1 )
- this->bottom = -1;
-
- return this->bottom;
- }
- /*------------------------------------------------------------*/
- void e_replace (win *const this,int c)
- {
- bottom(this,0);
- if( c )
- {
- this->dirty = 1;
- if( this->update )
- v_putc( &this->v, c, 0 );
- *b_current(&this->b) = c;
- }
- monitor(this, UPDATE);
- }
- /*------------------------------------------------------------*/
- void e_ins(win *const this, int c )
- {
- viewport *const v = &this->v;
-
- bottom(this,0);
- b_insert_c( &this->b, 1, c ? c : ' ');
- this->dirty = 1;
- if( this->update )
- {
- v_scroll_region( v, 0, -1, v_col(v), v_row(v),
- v_ncols(v)-1, v_row(v) );
- v_putc( v, c ? c : ' ', 0 );
- }
- monitor(this, UPDATE);
- }
- /*------------------------------------------------------------*/
- void e_del(win *const this)
- {
- viewport *const v = &this->v;
- textbuf *const b = &this->b;
- int vrow = v_row(v);
- int vcol = v_col(v);
- int brow = b_row(b);
- int bcol = b_col(b);
-
- b_delete_c( &this->b, 1, ' ' );
- this->dirty = 1;
-
- if( this->update )
- {
- v_scroll_region( v, 0, 1, v_col(v), v_row(v),
- v_ncols(v)-1, v_row(v) );
- v_gotorc (v, vrow, v_ncols(v)-1);
- }
- b_gotorc (b, brow, (v_ncols(v)-1) + this->col_off);
-
- if( this->update )
- {
- v_putc (v, *b_current(b), 0);
- v_gotorc (v, vrow, vcol);
- }
- b_gotorc(b, brow, bcol);
- monitor(this, UPDATE);
- }
- /*------------------------------------------------------------*/
- int e_closeline(win *const this)
- {
- viewport *const v = &this->v;
- textbuf *const b = &this->b;
- int ecol = e_col(this); /* absolute row and column */
- int erow = e_row(this);
- char *new;
- int i, bottom_line_of_buffer;
-
- if( this->bottom < 0 )
- return 0;
-
- b_gotorc ( b, b_row(b), 0 );
- del_line ( this, b, this->file_off + b_row(b) );
- this->dirty = 1;
-
- b_closedown( b, ' ');
- if( this->update )
- v_scroll_region( v, 1, 0, 0, v_row(v), v_ncols(v)-1,
- v_nrows(v)-1 );
-
- bottom(this, -1); /* Bottom line moves up one notch
- * because of the delete.
- */
- /* Import a new bottom line into the buffer if there's an
- * import function and there is text in the file below the
- * bottom line of the buffer.
- *
- * Note that since we just deleted a buffer line, all of the
- * file-relative line numbers have changed, so the line being
- * imported is actually the last line in the buffer, not the
- * line below the last line as was the case in the vertical-
- * scroll function.
- */
-
- bottom_line_of_buffer = this->file_off + b_nrows(b) - 1;
-
- if( this->import && this->bottom > bottom_line_of_buffer )
- {
- if(new = (*this->import)(this, bottom_line_of_buffer) )
- {
- /* Move the imported line into the buffer */
-
- b_gotorc(b, b_nrows(b)-1, 0 );
- for( i = b_ncols(b); --i >= 0 && *new ;)
- *b_advance(b) = *new++;
- }
- }
-
- /* If original row is now off the bottom of the file,
- * adjust it down to compensate.
- */
-
- if( erow > this->bottom )
- erow = this->bottom < 0 ? 0 : this->bottom ;
-
- /* Update the viewport to display the imported line
- */
-
- if( this->update )
- {
- b_gotorc(b, v_nrows(v)-1 + this->row_off, this->col_off );
- v_gotorc(v, v_nrows(v)-1, 0 );
- for( i = v_ncols(v); --i >= 0; v_putc(v,*b_advance(b),1) )
- ;
- }
-
- e_gotorc(this, erow, ecol );
- e_gotorc(this, e_row(this), e_first(this) );
- monitor(this, UPDATE);
- return 1;
- }
- /*------------------------------------------------------------*/
- int e_openline(win *const this, int below)
- {
- /* open the line on which the cursor is resting by moving all
- * following lines down a notch and importing a blank line.
- * If below is true, open the line beneath the current one.
- * Cursor ends up at far left of new line.
- */
-
- textbuf *b = &this->b;
- viewport *v = &this->v;
- int line = e_row(this);
- int scrolled = 0;
- int row;
-
- this->dirty = 1;
- if( below )
- {
- /* If we're inserting below the last line of the file, and
- * the cursor's resting on the bottom line of both the
- * viewport and the buffer, force a scroll up without
- * importing. In any event, adjust the target line to be
- * the one beneath the current on.
- */
-
- if( (line == this->bottom) && v_ateob(v) && b_ateob(b) )
- scrolled = e_vscroll( this, 1, 0 );
- ++line;
- }
- e_gotorc(this, line, 0); /* go to line that will be replaced */
-
- /* export the bottom line of the buffer if it has something
- * in it
- */
-
- if( this->bottom >= b_nrows(b)-1 && !scrolled )
- {
- row = b_row(b);
- b_gotorc (b, b_nrows(b)-1, 0);
- export (this, b, this->file_off + b_row(b) );
- b_gotorc (b, row, 0);
- }
-
- /* Scroll everything below current line down a notch and
- * put cursor at start of new line.
- */
-
- b_opendown(b,' ');
- if( this->update )
- v_scroll_region(v, -1, 0, 0, v_row(v), v_ncols(v)-1,
- v_nrows(v)-1 );
- e_gotorc(this, line, 0);
-
- /* Update file size and tell file-manager to insert line at
- * current position
- */
-
- bottom(this, +1); /* update the file size */
- return (this->insert) ? (*this->insert)( this, line ) : 1 ;
- }
- /*------------------------------------------------------------*/
- void e_cleartoeol( win *const this )
- {
- this->dirty = 1;
- b_cleartoeol( &this->b,' ');
- if( this->update )
- v_cleartoeol( &this->v );
- monitor(this, UPDATE);
- }
-