@@ -95,38 +95,10 @@ struct erow {
int rsize ;
int rsize ;
int cap ;
int cap ;
int dirty ;
} ;
} ;
typedef enum undo_flag {
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 * child ;
} 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.
@@ -151,7 +123,6 @@ 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 ,
@@ -173,7 +144,6 @@ struct editor_t {
. mark_cury = 0 ,
. mark_cury = 0 ,
. uarg = 0 ,
. uarg = 0 ,
. ucount = 0 ,
. ucount = 0 ,
. undo = NULL ,
} ;
} ;
@@ -187,6 +157,8 @@ size_t kstrnlen(const char *buf, const size_t max);
void ab_init ( struct abuf * buf ) ;
void ab_init ( struct abuf * buf ) ;
void ab_appendch ( struct abuf * buf , char c ) ;
void ab_appendch ( struct abuf * buf , char c ) ;
void ab_append ( struct abuf * buf , const char * s , size_t len ) ;
void ab_append ( struct abuf * buf , const char * s , size_t len ) ;
void ab_prependch ( struct abuf * buf , char c ) ;
void ab_prepend ( struct abuf * buf , const char * s , size_t len ) ;
void ab_free ( struct abuf * buf ) ;
void ab_free ( struct abuf * buf ) ;
char nibble_to_hex ( char c ) ;
char nibble_to_hex ( char c ) ;
void swap_int ( int * a , int * b ) ;
void swap_int ( int * a , int * b ) ;
@@ -199,67 +171,6 @@ 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 ) ;
void undo_node_free_branch ( undo_node_t * node ) ;
undo_tree_t * undo_tree_new ( void ) ;
void undo_tree_free ( undo_tree_t * ut ) ;
int undo_continue_pending ( undo_flag_t type ) ;
void undo_begin ( undo_flag_t type ) ;
void undo_append_char ( char c ) ;
void undo_append ( const char * data , size_t len ) ;
void undo_commit ( void ) ;
void undo_discard_redo_branches ( struct undo_node * from ) ;
undo_node_t * undo_parent_of ( undo_node_t * node ) ;
void undo_apply ( const undo_node_t * node , int direction ) ;
// void editor_undo(void);
// void editor_redo(void);
// void undo_mark_saved(void);
// int undo_depth(const undo_tree_t *t);
// int undo_can_undo(const undo_tree_t *t);
// int undo_can_redo(const undo_tree_t *t);
// void undo_tree_debug_dump(const undo_tree_t *t);
/* kill ring, marking, etc... */
/* kill ring, marking, etc... */
void killring_flush ( void ) ;
void killring_flush ( void ) ;
@@ -281,8 +192,12 @@ 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_delete_ch ( struct erow * row , int at ) ;
void row_delete_ch ( struct erow * row , int at ) ;
void insertch ( int16_t c ) ;
void insertch ( int16_t c ) ;
@@ -452,13 +367,6 @@ 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 ( ) ;
}
}
@@ -478,10 +386,6 @@ reset_editor(void)
editor . filename = NULL ;
editor . filename = NULL ;
}
}
if ( editor . undo ! = NULL ) {
undo_tree_free ( editor . undo ) ;
editor . undo = NULL ;
}
init_editor ( ) ;
init_editor ( ) ;
}
}
@@ -527,6 +431,27 @@ ab_append(struct abuf *buf, const char *s, size_t len)
}
}
void
ab_prependch ( struct abuf * buf , const char c )
{
ab_prepend ( buf , & c , 1 ) ;
}
void
ab_prepend ( struct abuf * buf , const char * s , const size_t len )
{
char * nc = realloc ( buf - > b , buf - > len + len ) ;
assert ( nc ! = NULL ) ;
memmove ( nc + len , nc , buf - > len ) ;
memcpy ( nc , s , len ) ;
buf - > b = nc ;
buf - > len + = len ;
}
void
void
ab_free ( struct abuf * buf )
ab_free ( struct abuf * buf )
{
{
@@ -676,6 +601,7 @@ 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 ) ;
@@ -775,366 +701,6 @@ erow_free(struct erow *row)
}
}
undo_node_t *
undo_node_new ( 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 - > child = NULL ;
ab_init ( & node - > text ) ;
return node ;
}
void
undo_node_free ( undo_node_t * node )
{
if ( node = = NULL ) {
return ;
}
ab_free ( & node - > text ) ;
undo_node_free ( node - > child ) ;
undo_node_free ( node - > next ) ;
free ( node ) ;
}
void
undo_node_free_branch ( undo_node_t * node )
{
undo_node_t * next = NULL ;
if ( node = = NULL ) {
return ;
}
while ( node ! = NULL ) {
next = node - > next ;
undo_node_free ( node - > child ) ;
ab_free ( & node - > text ) ;
free ( node ) ;
node = next ;
}
}
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 * ut )
{
if ( ut = = NULL ) {
return ;
}
undo_node_free ( ut - > root ) ;
undo_node_free ( ut - > pending ) ;
if ( debug_log = = NULL ) {
ut - > root = NULL ;
ut - > current = NULL ;
ut - > saved = NULL ;
ut - > pending = NULL ;
} else {
ut - > root =
ut - > current =
ut - > saved =
ut - > pending =
( void * ) 0xDEADBEEF ;
}
free ( ut ) ;
}
int
undo_continue_pending ( undo_flag_t type )
{
undo_tree_t * tree = editor . undo ;
undo_node_t * node = tree - > pending ;
/* no pending node, so we need to start anew. */
if ( node = = NULL ) {
return 0 ;
}
if ( node - > type ! = type ) {
return 0 ;
}
if ( node - > row ! = editor . cury | | node - > col ! = editor . curx ) {
return 0 ;
}
return 1 ;
}
/*
* 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 ( const undo_flag_t type )
{
undo_tree_t * tree = editor . undo ;
undo_node_t * node = tree - > pending ;
if ( undo_continue_pending ( type ) ) {
return ;
}
if ( tree - > pending ! = NULL ) {
undo_commit ( ) ;
}
node = undo_node_new ( type ) ;
assert ( node ! = NULL ) ;
node - > type = type ;
node - > row = editor . cury ;
node - > col = editor . curx ;
tree - > pending = node ;
}
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 ) ;
}
/* Finish the current batch and link it into the tree */
void
undo_commit ( void )
{
undo_tree_t * tree = editor . undo ;
undo_node_t * node = NULL ;
if ( tree - > pending = = NULL ) {
return ; /* nothing to commit */
}
node = tree - > pending ;
tree - > pending = NULL ;
if ( tree - > current & & tree - > current - > child ) {
undo_node_free_branch ( tree - > current - > child ) ;
tree - > current - > child = NULL ;
}
if ( tree - > root = = NULL ) {
/* First edit ever */
tree - > root = node ;
tree - > current = node ;
} else if ( tree - > current = = NULL ) {
/* this shouldn't happen, so throw an
* assert to catch it.
*/
assert ( tree - > current ! = NULL ) ;
tree - > root = tree - > current = node ;
} else {
tree - > current - > child = node ;
tree - > current = node ;
}
if ( tree - > saved & & tree - > current ! = tree - > saved ) {
tree - > saved = NULL ;
}
editor . dirty = 1 ;
}
void
undo_discard_redo_branches ( struct undo_node * from )
{
undo_node_free ( from - > child ) ;
from - > child = NULL ;
undo_node_free ( from - > next ) ;
from - > next = NULL ;
}
undo_node_t *
undo_parent_of ( undo_node_t * node )
{
undo_tree_t * tree = editor . undo ;
undo_node_t * parent = tree - > root ;
if ( tree - > root = = node ) {
return NULL ;
}
parent = tree - > root ;
while ( parent ! = NULL & & parent - > child ! = node ) {
parent = parent - > child ;
}
if ( parent = = NULL ) {
return NULL ;
}
return parent ;
}
void
editor_undo ( void )
{
undo_tree_t * tree = editor . undo ;
undo_node_t * node = tree - > current ;
undo_node_t * parent = NULL ;
if ( node = = NULL | | node = = tree - > root ) {
editor_set_status ( " Nothing to undo. " ) ;
return ;
}
parent = undo_parent_of ( node ) ;
assert ( parent ! = NULL ) ;
undo_apply ( node , - 1 ) ;
tree - > current = parent ;
display_refresh ( ) ;
}
void
editor_redo ( void )
{
undo_tree_t * tree = editor . undo ;
undo_node_t * node = tree - > current ;
if ( node = = NULL | | node - > child = = NULL ) {
editor_set_status ( " Nothing to redo. " ) ;
return ;
}
tree - > current = node - > child ;
undo_apply ( node - > child , 1 ) ;
display_refresh ( ) ;
}
void
undo_apply ( const struct undo_node * node , const int direction )
{
int row = node - > row ;
int col = node - > col ;
const char * data = node - > text . b ;
size_t len = node - > text . len ;
jump_to_position ( col , row ) ;
switch ( node - > type ) {
case UNDO_PASTE :
case UNDO_INSERT :
if ( direction > 0 ) {
for ( size_t i = 0 ; i < len ; i + + ) {
insertch ( ( unsigned char ) data [ i ] ) ;
}
} else {
for ( size_t i = 0 ; i < len ; i + + ) {
deletech ( KILLRING_NO_OP ) ;
}
}
break ;
case UNDO_DELETE :
if ( direction > 0 ) {
for ( size_t i = 0 ; i < len ; i + + ) {
deletech ( KILLRING_NO_OP ) ;
}
} else {
for ( size_t i = 0 ; i < len ; i + + ) {
insertch ( ( unsigned char ) data [ i ] ) ;
}
}
break ;
case UNDO_NEWLINE :
if ( direction > 0 ) {
newline ( ) ;
} else {
if ( editor . cury > 0 ) {
editor . curx = editor . row [ editor . cury - 1 ] . size ;
row_append_row ( & editor . row [ editor . cury - 1 ] ,
editor . row [ editor . cury ] . line ,
editor . row [ editor . cury ] . size ) ;
delete_row ( editor . cury ) ;
}
}
break ;
case UNDO_DELETE_ROW :
if ( direction > 0 ) {
/* redo = delete the whole row again */
delete_row ( editor . cury ) ;
} else {
/* undo = re-insert the saved row (including final '\n') */
if ( len > 0 & & data [ len - 1 ] = = ' \n ' ) len - - ;
erow_insert ( editor . cury , ( char * ) data , len ) ;
/* cursor goes to start of re-inserted row */
editor . curx = 0 ;
}
break ;
case UNDO_INDENT :
case UNDO_KILL_REGION :
/* These are more complex – you can implement later */
/* For now just move cursor and say "not implemented yet" */
editor_set_status ( " Undo of %s not implemented yet " ,
direction > 0 ? " redo " : " complex op " ) ;
break ;
default :
editor_set_status ( " Unknown undo type: %d " , node - > type ) ;
break ;
}
editor . dirty = 1 ;
}
void
void
killring_flush ( void )
killring_flush ( void )
{
{
@@ -1191,7 +757,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 ' ;
e row_update ( row ) ;
row- > dirty = 1 ;
}
}
@@ -1211,7 +777,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 ' ;
e row_update ( row ) ;
row- > dirty = 1 ;
}
}
@@ -1229,7 +795,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 + + ;
e row_update ( row ) ;
row- > dirty = 1 ;
}
}
@@ -1437,7 +1003,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 ;
e row_update ( row ) ;
row- > dirty = 1 ;
}
}
}
}
}
}
@@ -1596,6 +1162,13 @@ 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 )
{
{
@@ -1603,7 +1176,7 @@ find_next_word(void)
move_cursor ( ARROW_RIGHT , 1 ) ;
move_cursor ( ARROW_RIGHT , 1 ) ;
}
}
if ( isalnum ( editor . row [ editor . cury ] . line [ editor . curx ] ) ) {
if ( iswordchar ( 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 ) ;
@@ -1630,7 +1203,7 @@ delete_next_word(void)
deletech ( KILLRING_APPEND ) ;
deletech ( KILLRING_APPEND ) ;
}
}
if ( isalnum ( editor . row [ editor . cury ] . line [ editor . curx ] ) ) {
if ( iswordchar ( 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 ) ;
@@ -1767,7 +1340,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 ' ;
e row_update ( row ) ;
row- > dirty = 1 ;
editor . dirty + + ;
editor . dirty + + ;
}
}
@@ -1789,7 +1362,7 @@ 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 ;
e row_update ( row ) ;
row- > dirty = 1 ;
}
}
@@ -1802,7 +1375,7 @@ 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 - - ;
e row_update ( row ) ;
row- > dirty = 1 ;
editor . dirty + + ;
editor . dirty + + ;
}
}
@@ -2261,7 +1834,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 */
e row_update ( row ) ;
row- > dirty = 1 ;
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 ) {
@@ -2379,7 +1952,7 @@ void
move_cursor_once ( int16_t c , int interactive )
move_cursor_once ( int16_t c , int interactive )
{
{
struct erow * row ;
struct erow * row ;
int reps ;
int reps = 0 ;
row = ( editor . cury > = editor . nrows ) ? NULL : & editor . row [ editor . cury ] ;
row = ( editor . cury > = editor . nrows ) ? NULL : & editor . row [ editor . cury ] ;
@@ -2516,7 +2089,7 @@ 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 ' ;
e row_update ( row ) ;
row- > dirty = 1 ;
editor . cury + + ;
editor . cury + + ;
editor . curx = 0 ;
editor . curx = 0 ;
}
}
@@ -2741,10 +2314,12 @@ process_kcommand(int16_t c)
case ' x ' :
case ' x ' :
exit ( save_file ( ) ) ;
exit ( save_file ( ) ) ;
case ' u ' :
case ' u ' :
editor_undo ( ) ;
reps = uarg_get ( ) ;
while ( reps - - ) ;
editor_set_status ( " Undo not implemented. " ) ;
break ;
break ;
case ' U ' :
case ' U ' :
editor_redo ( ) ;
break ;
break ;
case ' y ' :
case ' y ' :
reps = uarg_get ( ) ;
reps = uarg_get ( ) ;
@@ -3140,7 +2715,11 @@ 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 ;
@@ -3244,11 +2823,15 @@ 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 ) {
editor . rx = erow_render_to_cursor (
row = & editor . row [ editor . cury ] ;
& editor . row [ e ditor . cury ] ,
if ( row - > dirty = = 1 ) {
editor . curx ) ;
erow_update ( row ) ;
}
editor . rx = erow_render_to_cursor ( row , editor . curx ) ;
}
}
if ( editor . cury < editor . rowoffs ) {
if ( editor . cury < editor . rowoffs ) {
@@ -3278,6 +2861,7 @@ 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 ) ;
@@ -3291,7 +2875,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 " ?25h " , 6 ) ;
ab_append ( & ab , ESCSEQ " ?25l " , 6 ) ;
kwrite ( STDOUT_FILENO , ab . b , ab . len ) ;
kwrite ( STDOUT_FILENO , ab . b , ab . len ) ;
ab_free ( & ab ) ;
ab_free ( & ab ) ;
@@ -3311,6 +2895,15 @@ 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 )
{
{
@@ -3327,7 +2920,9 @@ loop(void)
*
*
*/
*/
if ( ( up = process_keypress ( ) ) ! = 0 ) {
if ( ( up = process_keypress ( ) ) ! = 0 ) {
while ( process_keypress ( ) ) ;
while ( kbhit ( ) ) {
process_keypress ( ) ;
}
}
}
}
}
}
}