@@ -95,10 +95,38 @@ struct erow {
int rsize ;
int rsize ;
int cap ;
int cap ;
int dirty ;
} ;
} ;
typedef enum undo_type {
UNDO_INSERT = 1 < < 0 , /* insertch */
UNDO_DELETE = 1 < < 1 , /* deletech */
UNDO_PASTE = 1 < < 2 , /* yank */
UNDO_NEWLINE = 1 < < 3 , /* newline duh */
UNDO_DELETE_ROW = 1 < < 4 , /* delete_row duh */
UNDO_INDENT = 1 < < 5 ,
UNDO_UNINDENT = 1 < < 6 ,
UNDO_KILL_REGION = 1 < < 7
} undo_flag_t ;
typedef struct undo_node {
undo_flag_t type ;
int row , col ;
struct abuf text ;
struct undo_node * next ;
struct undo_node * parent ;
} undo_node_t ;
typedef struct undo_tree {
undo_node_t * root ;
undo_node_t * current ;
undo_node_t * saved ;
undo_node_t * pending ;
} undo_tree_t ;
/*
/*
* editor is the global editor state; it should be broken out
* editor is the global editor state; it should be broken out
* to buffers and screen state, probably.
* to buffers and screen state, probably.
@@ -123,6 +151,7 @@ struct editor_t {
int mark_curx , mark_cury ;
int mark_curx , mark_cury ;
int uarg , ucount ; /* C-u support */
int uarg , ucount ; /* C-u support */
time_t msgtm ;
time_t msgtm ;
undo_tree_t * undo ;
} editor = {
} editor = {
. cols = 0 ,
. cols = 0 ,
. rows = 0 ,
. rows = 0 ,
@@ -144,6 +173,7 @@ struct editor_t {
. mark_cury = 0 ,
. mark_cury = 0 ,
. uarg = 0 ,
. uarg = 0 ,
. ucount = 0 ,
. ucount = 0 ,
. undo = NULL ,
} ;
} ;
@@ -171,6 +201,60 @@ void erow_update(struct erow *row);
void erow_insert ( int at , char * s , int len ) ;
void erow_insert ( int at , char * s , int len ) ;
void erow_free ( struct erow * row ) ;
void erow_free ( struct erow * row ) ;
/*
* undo ops
*
* notes:
* + undo_node_free destroys an entire timeline, including children and next.
* + undo_node_free_branch only discards next.
* + undo_discard_redo_branches kills child and next.
*
* Basic invariants of the undo system:
* + root->parent == NULL
* + root->current is reachable from root via repeated child walk
* + saved is NULL or reachable the same way
* + pending is either NULL or a brand-new node not yet linked
* + when we commit, pending becomes current->child and current moves forward
* + when we undo, current = current->parent
* + when we type after undo, we free current->child (redo branch) first
*
* Or, visually,
*
* root ──> N1 ──> N2 ──> N3 ──> N4* ──> N5 ──> N6 (main timeline)
* ^ ^ ^
* | | |
* saved pending current
*
* + root : first edit ever, never has a parent
* + current : where we are right now in history
* + saved : points to the node that matches the on-disk file
* + pending : temporary node being built (committed → becomes current->child)
*
* If I do a double undo then type something:
*
* root ──> N1 ──> N2 ──> N3* ──> N4 ──> N5 (old N4→N5→N6 discarded)
* ^ ^
* | |
* current pending (new edit)
* |
* saved
*
* All four pointers point into the same tree → and should only be memory
* managed via the root node.
*/
undo_node_t * undo_node_new ( undo_flag_t type ) ;
void undo_node_free ( undo_node_t * node ) ;
undo_tree_t * undo_tree_new ( void ) ;
void undo_tree_free ( undo_tree_t * tree ) ;
void undo_begin ( undo_flag_t type ) ;
void undo_append_char ( char c ) ;
void undo_append ( const char * data , size_t len ) ;
void undo_prepend_char ( char c ) ;
void undo_prepend ( const char * data , size_t len ) ;
void undo_commit ( void ) ;
void undo_apply ( const undo_node_t * node , int direction ) ;
void editor_undo ( void ) ;
void editor_redo ( void ) ;
/* kill ring, marking, etc... */
/* kill ring, marking, etc... */
void killring_flush ( void ) ;
void killring_flush ( void ) ;
@@ -192,14 +276,13 @@ int get_winsz(int *rows, int *cols);
void jump_to_position ( int col , int row ) ;
void jump_to_position ( int col , int row ) ;
void goto_line ( void ) ;
void goto_line ( void ) ;
int cursor_at_eol ( void ) ;
int cursor_at_eol ( void ) ;
int iswordchar ( unsigned char c ) ;
void find_next_word ( void ) ;
void delete_next_word ( void ) ;
void find_prev_word ( void ) ;
void delete_prev_word ( void ) ;
void delete_row ( int at ) ;
void delete_row ( int at ) ;
void row_append_row ( struct erow * row , char * s , int len ) ;
void row_insert_ch ( struct erow * row , int at , int16_t c ) ;
void row_insert_ch ( struct erow * row , int at , int16_t c ) ;
void row_insert_block ( struct erow * row , int at ,
const char * data , size_t len ) ;
void row_delete_ch ( struct erow * row , int at ) ;
void row_delete_ch ( struct erow * row , int at ) ;
void row_delete_block ( struct erow * row , int at , size_t len ) ;
void insertch ( int16_t c ) ;
void insertch ( int16_t c ) ;
void deletech ( uint8_t op ) ;
void deletech ( uint8_t op ) ;
void open_file ( const char * filename ) ;
void open_file ( const char * filename ) ;
@@ -367,6 +450,13 @@ init_editor(void)
editor . dirty = 0 ;
editor . dirty = 0 ;
editor . mark_set = 0 ;
editor . mark_set = 0 ;
editor . mark_cury = editor . mark_curx = 0 ;
editor . mark_cury = editor . mark_curx = 0 ;
if ( editor . undo ! = NULL ) {
undo_tree_free ( editor . undo ) ;
editor . undo = NULL ;
}
editor . undo = undo_tree_new ( ) ;
}
}
@@ -380,12 +470,17 @@ reset_editor(void)
erow_free ( & editor . row [ i ] ) ;
erow_free ( & editor . row [ i ] ) ;
}
}
free ( editor . row ) ;
free ( editor . row ) ;
editor . row = NULL ;
if ( editor . filename ! = NULL ) {
if ( editor . filename ! = NULL ) {
free ( editor . filename ) ;
free ( editor . filename ) ;
editor . filename = NULL ;
editor . filename = NULL ;
}
}
if ( editor . undo ! = NULL ) {
undo_tree_free ( editor . undo ) ;
editor . undo = NULL ;
}
init_editor ( ) ;
init_editor ( ) ;
}
}
@@ -601,7 +696,6 @@ erow_init(struct erow *row, int len)
row - > render = NULL ;
row - > render = NULL ;
row - > line = NULL ;
row - > line = NULL ;
row - > cap = cap_growth ( 0 , len ) + 1 ; /* extra byte for NUL end */
row - > cap = cap_growth ( 0 , len ) + 1 ; /* extra byte for NUL end */
row - > dirty = 1 ;
row - > line = malloc ( row - > cap ) ;
row - > line = malloc ( row - > cap ) ;
assert ( row - > line ! = NULL ) ;
assert ( row - > line ! = NULL ) ;
@@ -698,6 +792,241 @@ erow_free(struct erow *row)
free ( row - > line ) ;
free ( row - > line ) ;
row - > render = NULL ;
row - > render = NULL ;
row - > line = NULL ;
row - > line = NULL ;
row - > cap = 0 ;
row - > size = 0 ;
}
undo_node_t *
undo_node_new ( const undo_flag_t type )
{
undo_node_t * node = calloc1 ( sizeof ( undo_node_t ) ) ;
node - > type = type ;
node - > row = node - > col = 0 ;
node - > next = NULL ;
node - > parent = NULL ;
ab_init ( & node - > text ) ;
return node ;
}
void
undo_node_free ( undo_node_t * node )
{
if ( node = = NULL ) {
return ;
}
assert ( node - > next - > parent = = node ) ;
ab_free ( & node - > text ) ;
node = node - > next ;
free ( node - > parent ) ;
node - > parent = NULL ;
free ( node ) ;
}
undo_tree_t *
undo_tree_new ( void )
{
undo_tree_t * tree = NULL ;
tree = calloc1 ( sizeof ( undo_tree_t ) ) ;
tree - > root = NULL ;
tree - > current = NULL ;
tree - > saved = NULL ;
tree - > pending = NULL ;
return tree ;
}
void
undo_tree_free ( undo_tree_t * tree )
{
if ( tree = = NULL ) {
return ;
}
undo_node_free ( tree - > root ) ;
if ( tree - > pending ! = NULL ) {
undo_node_free ( tree - > pending ) ;
}
if ( debug_log = = NULL ) {
tree - > root = NULL ;
tree - > current = NULL ;
tree - > saved = NULL ;
tree - > pending = NULL ;
} else {
tree - > root =
tree - > current =
tree - > saved =
tree - > pending =
( void * ) 0xDEADBEEF ;
}
free ( tree ) ;
}
/*
* undo_begin starts a new undo sequence. Note that it is a non-op
* if a new pending sequence doesn't need to be created.
*/
void
undo_begin ( undo_flag_t type )
{
struct undo_tree * tree = editor . undo ;
assert ( tree ! = NULL ) ;
if ( tree - > pending ! = NULL ) {
if ( tree - > pending - > type = = type ) {
return ;
}
undo_commit ( ) ;
}
tree - > pending = undo_node_new ( type ) ;
tree - > pending - > row = editor . cury ;
tree - > pending - > col = editor . curx ;
}
void
undo_append_char ( const char c )
{
undo_node_t * node = editor . undo - > pending ;
assert ( node ! = NULL ) ;
ab_appendch ( & node - > text , c ) ;
}
void
undo_append ( const char * data , const size_t len )
{
undo_node_t * node = editor . undo - > pending ;
assert ( node ! = NULL ) ;
ab_append ( & node - > text , data , len ) ;
}
void
undo_prepend_char ( const char c )
{
undo_node_t * node = editor . undo - > pending ;
assert ( node ! = NULL ) ;
ab_prependch ( & node - > text , c ) ;
}
void
undo_prepend ( const char * data , const size_t len )
{
undo_node_t * node = editor . undo - > pending ;
assert ( node ! = NULL ) ;
ab_prepend ( & node - > text , data , len ) ;
}
/*
* undo_commit commits the current pending tree into the root.
*
* Finish the current batch and link it into the tree.
* */
void
undo_commit ( void )
{
undo_tree_t * tree = editor . undo ;
assert ( tree ! = NULL ) ;
if ( tree - > pending = = NULL ) {
return ; /* no pending operation */
}
if ( tree - > root = = NULL ) {
}
}
void
undo_apply ( const struct undo_node * node , const int direction )
{
int redo ;
assert ( node ! = NULL ) ;
redo = direction < 0 ? 1 : 0 ;
switch ( node - > type ) {
default :
if ( redo ) {
editor_set_status ( " Redo isn't implemented. " ) ;
} else {
editor_set_status ( " Undo isn't implemented " ) ;
}
}
}
void
undo_apply_current ( int direction )
{
undo_tree_t * tree = editor . undo ;
assert ( tree ! = NULL ) ;
undo_commit ( ) ;
if ( tree - > current = = NULL ) {
editor_set_status ( " No further undo. " ) ;
return ;
}
assert ( tree - > current - > next = = NULL ) ;
undo_apply ( tree - > current , direction ) ;
tree - > current = tree - > current - > parent ;
undo_node_free ( tree - > current - > next ) ;
}
void
editor_undo ( void )
{
/*
* pending should already have been committed, but it doesn't
* hurt to be a little paranoid.
*/
undo_commit ( ) ;
undo_apply_current ( 1 ) ;
}
void
editor_redo ( void )
{
/*
* pending should already have been committed, but it doesn't
* hurt to be a little paranoid.
*/
undo_commit ( ) ;
undo_apply_current ( - 1 ) ;
}
}
@@ -731,6 +1060,10 @@ killring_yank(void)
insertch ( ch ) ;
insertch ( ch ) ;
}
}
}
}
undo_begin ( UNDO_PASTE ) ;
undo_append ( editor . killring - > line , editor . killring - > size ) ;
undo_commit ( ) ; /* atomic */
}
}
@@ -757,7 +1090,7 @@ killring_start_with_char(unsigned char ch)
row - > line [ row - > size ] = ch ;
row - > line [ row - > size ] = ch ;
row - > size + + ;
row - > size + + ;
row - > line [ row - > size ] = ' \0 ' ;
row - > line [ row - > size ] = ' \0 ' ;
row- > dirty = 1 ;
e row_update ( row ) ;
}
}
@@ -777,7 +1110,7 @@ killring_append_char(unsigned char ch)
row - > line [ row - > size ] = ch ;
row - > line [ row - > size ] = ch ;
row - > size + + ;
row - > size + + ;
row - > line [ row - > size ] = ' \0 ' ;
row - > line [ row - > size ] = ' \0 ' ;
row- > dirty = 1 ;
e row_update ( row ) ;
}
}
@@ -795,7 +1128,7 @@ killring_prepend_char(unsigned char ch)
memmove ( & row - > line [ 1 ] , & row - > line [ 0 ] , row - > size + 1 ) ;
memmove ( & row - > line [ 1 ] , & row - > line [ 0 ] , row - > size + 1 ) ;
row - > line [ 0 ] = ch ;
row - > line [ 0 ] = ch ;
row - > size + + ;
row - > size + + ;
row- > dirty = 1 ;
e row_update ( row ) ;
}
}
@@ -1003,7 +1336,7 @@ unindent_region(void)
if ( del > 0 ) {
if ( del > 0 ) {
memmove ( row - > line , row - > line + del , row - > size - del + 1 ) ; /* +1 for NUL */
memmove ( row - > line , row - > line + del , row - > size - del + 1 ) ; /* +1 for NUL */
row - > size - = del ;
row - > size - = del ;
row- > dirty = 1 ;
e row_update ( row ) ;
}
}
}
}
}
}
@@ -1162,13 +1495,6 @@ cursor_at_eol(void)
}
}
int
iswordchar ( unsigned char c )
{
return isalnum ( c ) | | c = = ' _ ' | | strchr ( " /!@#$%^&*+-=~ " , c ) ! = NULL ;
}
void
void
find_next_word ( void )
find_next_word ( void )
{
{
@@ -1176,7 +1502,7 @@ find_next_word(void)
move_cursor ( ARROW_RIGHT , 1 ) ;
move_cursor ( ARROW_RIGHT , 1 ) ;
}
}
if ( iswordchar ( editor . row [ editor . cury ] . line [ editor . curx ] ) ) {
if ( isalnum ( editor . row [ editor . cury ] . line [ editor . curx ] ) ) {
while ( ! isspace ( editor . row [ editor . cury ] . line [ editor . curx ] ) & & !
while ( ! isspace ( editor . row [ editor . cury ] . line [ editor . curx ] ) & & !
cursor_at_eol ( ) ) {
cursor_at_eol ( ) ) {
move_cursor ( ARROW_RIGHT , 1 ) ;
move_cursor ( ARROW_RIGHT , 1 ) ;
@@ -1203,7 +1529,7 @@ delete_next_word(void)
deletech ( KILLRING_APPEND ) ;
deletech ( KILLRING_APPEND ) ;
}
}
if ( iswordchar ( editor . row [ editor . cury ] . line [ editor . curx ] ) ) {
if ( isalnum ( editor . row [ editor . cury ] . line [ editor . curx ] ) ) {
while ( ! isspace ( editor . row [ editor . cury ] . line [ editor . curx ] ) & & !
while ( ! isspace ( editor . row [ editor . cury ] . line [ editor . curx ] ) & & !
cursor_at_eol ( ) ) {
cursor_at_eol ( ) ) {
move_cursor ( ARROW_RIGHT , 1 ) ;
move_cursor ( ARROW_RIGHT , 1 ) ;
@@ -1340,7 +1666,7 @@ row_append_row(struct erow *row, char *s, int len)
memcpy ( & row - > line [ row - > size ] , s , len ) ;
memcpy ( & row - > line [ row - > size ] , s , len ) ;
row - > size + = len ;
row - > size + = len ;
row - > line [ row - > size ] = ' \0 ' ;
row - > line [ row - > size ] = ' \0 ' ;
row- > dirty = 1 ;
e row_update ( row ) ;
editor . dirty + + ;
editor . dirty + + ;
}
}
@@ -1362,7 +1688,39 @@ row_insert_ch(struct erow *row, int at, int16_t c)
row - > size + + ;
row - > size + + ;
row - > line [ at ] = c & 0xff ;
row - > line [ at ] = c & 0xff ;
row- > dirty = 1 ;
e row_update ( row ) ;
}
void
row_insert_block ( struct erow * row , int at , const char * data , size_t len )
{
if ( at < 0 ) {
at = 0 ;
}
if ( at > row - > size ) {
at = row - > size ;
}
if ( len = = 0 ) {
return ;
}
if ( row - > size + ( int ) len + 1 > row - > cap ) {
row - > cap = cap_growth ( row - > cap , row - > size + len + 1 ) ;
row - > line = realloc ( row - > line , row - > cap ) ;
assert ( row - > line ! = NULL ) ;
}
memmove ( row - > line + at + len , row - > line + at ,
row - > size - at + 1 ) ; /* +1 for NUL */
memcpy ( row - > line + at , data , len ) ;
row - > size + = len ;
row - > line [ row - > size ] = ' \0 ' ;
erow_update ( row ) ;
editor . dirty + + ;
}
}
@@ -1375,7 +1733,28 @@ row_delete_ch(struct erow *row, int at)
memmove ( & row - > line [ at ] , & row - > line [ at + 1 ] , row - > size - at ) ;
memmove ( & row - > line [ at ] , & row - > line [ at + 1 ] , row - > size - at ) ;
row - > size - - ;
row - > size - - ;
row- > dirty = 1 ;
e row_update ( row ) ;
editor . dirty + + ;
}
void
row_delete_block ( struct erow * row , int at , size_t len )
{
if ( at < 0 | | at > = row - > size | | len = = 0 ) {
return ;
}
if ( at + ( int ) len > row - > size ) {
len = row - > size - at ;
}
memmove ( row - > line + at , row - > line + at + len ,
row - > size - ( at + len ) + 1 ) ;
row - > size - = len ;
row - > line [ row - > size ] = ' \0 ' ;
erow_update ( row ) ;
editor . dirty + + ;
editor . dirty + + ;
}
}
@@ -1383,6 +1762,8 @@ row_delete_ch(struct erow *row, int at)
void
void
insertch ( int16_t c )
insertch ( int16_t c )
{
{
undo_begin ( UNDO_INSERT ) ;
/*
/*
* insert_ch doesn't need to worry about how to update a
* insert_ch doesn't need to worry about how to update a
* a row; it can just figure out where the cursor is
* a row; it can just figure out where the cursor is
@@ -1399,7 +1780,12 @@ insertch(int16_t c)
row_insert_ch ( & editor . row [ editor . cury ] ,
row_insert_ch ( & editor . row [ editor . cury ] ,
editor . curx ,
editor . curx ,
( int16_t ) ( c & 0xff ) ) ;
( int16_t ) ( c & 0xff ) ) ;
undo_append_char ( ( char ) c ) ;
editor . curx + + ;
editor . curx + + ;
if ( editor . undo - > pending ! = NULL ) {
editor . undo - > pending - > col = editor . curx ;
}
editor . dirty + + ;
editor . dirty + + ;
}
}
@@ -1425,9 +1811,12 @@ deletech(uint8_t op)
dch = ' \n ' ;
dch = ' \n ' ;
}
}
undo_begin ( UNDO_DELETE ) ;
if ( editor . curx > 0 ) {
if ( editor . curx > 0 ) {
row_delete_ch ( row , editor . curx - 1 ) ;
row_delete_ch ( row , editor . curx - 1 ) ;
editor . curx - - ;
editor . curx - - ;
undo_append_char ( dch ) ;
} else {
} else {
editor . curx = editor . row [ editor . cury - 1 ] . size ;
editor . curx = editor . row [ editor . cury - 1 ] . size ;
row_append_row ( & editor . row [ editor . cury - 1 ] ,
row_append_row ( & editor . row [ editor . cury - 1 ] ,
@@ -1439,6 +1828,11 @@ deletech(uint8_t op)
delete_row ( editor . cury ) ;
delete_row ( editor . cury ) ;
editor . no_kill = prev ;
editor . no_kill = prev ;
editor . cury - - ;
editor . cury - - ;
undo_append_char ( ' \n ' ) ;
}
if ( editor . undo - > pending ! = NULL ) {
editor . undo - > pending - > col = editor . curx ;
}
}
if ( op = = KILLRING_FLUSH ) {
if ( op = = KILLRING_FLUSH ) {
@@ -1834,7 +2228,7 @@ editor_find_callback(char* query, int16_t c)
row = & editor . row [ current ] ;
row = & editor . row [ current ] ;
/* Skip rendering search on raw bytes — use line[] but respect render offsets */
/* Skip rendering search on raw bytes — use line[] but respect render offsets */
row- > dirty = 1 ;
e row_update ( row ) ;
char * search_start = row - > render ;
char * search_start = row - > render ;
if ( current = = start_row & & direction = = 1 & & last_match = = - 1 ) {
if ( current = = start_row & & direction = = 1 & & last_match = = - 1 ) {
@@ -1954,6 +2348,8 @@ move_cursor_once(int16_t c, int interactive)
struct erow * row ;
struct erow * row ;
int reps = 0 ;
int reps = 0 ;
undo_commit ( ) ;
row = ( editor . cury > = editor . nrows ) ? NULL : & editor . row [ editor . cury ] ;
row = ( editor . cury > = editor . nrows ) ? NULL : & editor . row [ editor . cury ] ;
switch ( c ) {
switch ( c ) {
@@ -2073,6 +2469,8 @@ newline(void)
{
{
struct erow * row = NULL ;
struct erow * row = NULL ;
undo_begin ( UNDO_NEWLINE ) ;
if ( editor . cury > = editor . nrows ) {
if ( editor . cury > = editor . nrows ) {
erow_insert ( editor . cury , " " , 0 ) ;
erow_insert ( editor . cury , " " , 0 ) ;
editor . cury + + ;
editor . cury + + ;
@@ -2089,13 +2487,16 @@ newline(void)
row = & editor . row [ editor . cury ] ;
row = & editor . row [ editor . cury ] ;
row - > size = editor . curx ;
row - > size = editor . curx ;
row - > line [ row - > size ] = ' \0 ' ;
row - > line [ row - > size ] = ' \0 ' ;
row- > dirty = 1 ;
e row_update ( row ) ;
editor . cury + + ;
editor . cury + + ;
editor . curx = 0 ;
editor . curx = 0 ;
}
}
/* BREAK THE KILL CHAIN \m/ */
/* BREAK THE KILL CHAIN \m/ */
editor . kill = 0 ;
editor . kill = 0 ;
/* newlines aren't batched */
undo_commit ( ) ;
}
}
@@ -2157,6 +2558,8 @@ process_kcommand(int16_t c)
int jumpy = 0 ;
int jumpy = 0 ;
int reps = 0 ;
int reps = 0 ;
undo_commit ( ) ;
switch ( c ) {
switch ( c ) {
case BACKSPACE :
case BACKSPACE :
while ( editor . curx > 0 ) {
while ( editor . curx > 0 ) {
@@ -2316,10 +2719,12 @@ process_kcommand(int16_t c)
case ' u ' :
case ' u ' :
reps = uarg_get ( ) ;
reps = uarg_get ( ) ;
while ( reps - - ) ;
while ( reps - - ) {
editor_set_status ( " Undo not implemented. " ) ;
editor_undo ( ) ;
}
break ;
break ;
case ' U ' :
case ' U ' :
editor_redo ( ) ;
break ;
break ;
case ' y ' :
case ' y ' :
reps = uarg_get ( ) ;
reps = uarg_get ( ) ;
@@ -2350,6 +2755,8 @@ process_normal(int16_t c)
{
{
int reps = 0 ;
int reps = 0 ;
undo_commit ( ) ;
/* C-u handling – must be the very first thing */
/* C-u handling – must be the very first thing */
if ( c = = CTRL_KEY ( ' u ' ) ) {
if ( c = = CTRL_KEY ( ' u ' ) ) {
uarg_start ( ) ;
uarg_start ( ) ;
@@ -2451,6 +2858,8 @@ process_escape(int16_t c)
{
{
editor_set_status ( " hi " ) ;
editor_set_status ( " hi " ) ;
undo_commit ( ) ;
switch ( c ) {
switch ( c ) {
case ' > ' :
case ' > ' :
editor . cury = editor . nrows ;
editor . cury = editor . nrows ;
@@ -2715,11 +3124,7 @@ draw_rows(struct abuf *ab)
}
}
} else {
} else {
row = & editor . row [ filerow ] ;
row = & editor . row [ filerow ] ;
if ( row - > dirty ) {
erow_update ( row ) ;
erow_update ( row ) ;
row - > dirty = 0 ;
}
len = row - > rsize - editor . coloffs ;
len = row - > rsize - editor . coloffs ;
if ( len < 0 ) {
if ( len < 0 ) {
len = 0 ;
len = 0 ;
@@ -2823,15 +3228,11 @@ draw_message_line(struct abuf *ab)
void
void
scroll ( void )
scroll ( void )
{
{
struct erow * row = NULL ;
editor . rx = 0 ;
editor . rx = 0 ;
if ( editor . cury < editor . nrows ) {
if ( editor . cury < editor . nrows ) {
row = & editor . row [ editor . cury ] ;
editor . rx = erow_render_to_cursor (
if ( row - > dirty = = 1 ) {
& editor . row [ e ditor . cury ] ,
erow_update ( row ) ;
editor . curx ) ;
}
editor . rx = erow_render_to_cursor ( row , editor . curx ) ;
}
}
if ( editor . cury < editor . rowoffs ) {
if ( editor . cury < editor . rowoffs ) {
@@ -2861,7 +3262,6 @@ display_refresh(void)
scroll ( ) ;
scroll ( ) ;
ab_append ( & ab , ESCSEQ " ?25l " , 6 ) ;
ab_append ( & ab , ESCSEQ " ?25l " , 6 ) ;
ab_append ( & ab , ESCSEQ " H " , 3 ) ;
display_clear ( & ab ) ;
display_clear ( & ab ) ;
draw_rows ( & ab ) ;
draw_rows ( & ab ) ;
@@ -2875,7 +3275,7 @@ display_refresh(void)
( editor . rx - editor . coloffs ) + 1 ) ;
( editor . rx - editor . coloffs ) + 1 ) ;
ab_append ( & ab , buf , kstrnlen ( buf , 32 ) ) ;
ab_append ( & ab , buf , kstrnlen ( buf , 32 ) ) ;
/* ab_append(&ab, ESCSEQ "1;2H", 7); */
/* ab_append(&ab, ESCSEQ "1;2H", 7); */
ab_append ( & ab , ESCSEQ " ?25l " , 6 ) ;
ab_append ( & ab , ESCSEQ " ?25h " , 6 ) ;
kwrite ( STDOUT_FILENO , ab . b , ab . len ) ;
kwrite ( STDOUT_FILENO , ab . b , ab . len ) ;
ab_free ( & ab ) ;
ab_free ( & ab ) ;
@@ -2895,15 +3295,6 @@ editor_set_status(const char *fmt, ...)
}
}
int
kbhit ( void )
{
int bytes_waiting ;
ioctl ( STDIN_FILENO , FIONREAD , & bytes_waiting ) ;
return bytes_waiting > 0 ;
}
void
void
loop ( void )
loop ( void )
{
{
@@ -2920,9 +3311,7 @@ loop(void)
*
*
*/
*/
if ( ( up = process_keypress ( ) ) ! = 0 ) {
if ( ( up = process_keypress ( ) ) ! = 0 ) {
while ( kbhit ( ) ) {
while ( process_keypress ( ) ) ;
process_keypress ( ) ;
}
}
}
}
}
}
}
@@ -2962,11 +3351,7 @@ deathknell(void)
debug_log = NULL ;
debug_log = NULL ;
}
}
if ( editor . killring ! = NULL ) {
killring_flush ( ) ;
erow_free ( editor . killring ) ;
free ( editor . killring ) ;
editor . killring = NULL ;
}
reset_editor ( ) ;
reset_editor ( ) ;
disable_termraw ( ) ;
disable_termraw ( ) ;