1
0
mirror of https://github.com/rfivet/uemacs.git synced 2024-06-10 14:00:41 +00:00

Fix: avoid extra NL when newline/yank/insert-file at end of last line of non empty buffer.

Refactor yank.
Detab before commit.
This commit is contained in:
Renaud 2024-04-04 12:03:24 +08:00
parent 12d307b5b4
commit 1ee0ebf4b9

204
line.c
View File

@ -38,11 +38,11 @@ static int ldelnewline( void) ;
* was taken up by the keycode structure). * was taken up by the keycode structure).
*/ */
#define KBLOCK 248 /* sizeof kill buffer chunks */ #define KBLOCK 248 /* sizeof kill buffer chunks */
typedef struct kill { typedef struct kill {
struct kill *d_next ; /* Link to next chunk, NULL if last. */ struct kill *d_next ; /* Link to next chunk, NULL if last. */
char d_chunk[ KBLOCK] ; /* Deleted text. */ unsigned char d_chunk[ KBLOCK] ; /* Deleted text. */
} *kill_p ; } *kill_p ;
static kill_p kbufp = NULL ; /* current kill buffer chunk pointer */ static kill_p kbufp = NULL ; /* current kill buffer chunk pointer */
@ -57,7 +57,7 @@ static char *value = NULL ; /* temp buffer for value */
const char *getkill( void) { const char *getkill( void) {
/* no kill buffer or no memory .... just return a null string */ /* no kill buffer or no memory .... just return a null string */
if( kbufh == NULL if( kbufh == NULL
|| (value = realloc( value, klen + 1)) == NULL) || (value = realloc( value, klen + 1)) == NULL)
return "" ; return "" ;
char *cp = value ; char *cp = value ;
@ -94,26 +94,26 @@ BBINDABLE( backchar) {
curwp->w_doto = llength( lp) ; curwp->w_doto = llength( lp) ;
curwp->w_flag |= WFMOVE ; curwp->w_flag |= WFMOVE ;
} else { } else {
unsigned pos ; unsigned pos ;
/* move back over combining unicode */ /* move back over combining unicode */
combined: combined:
pos = curwp->w_doto -= 1 ; pos = curwp->w_doto -= 1 ;
/* check if at end of unicode */ /* check if at end of unicode */
if( pos > 0) { if( pos > 0) {
unsigned delta = utf8_revdelta( unsigned delta = utf8_revdelta(
(unsigned char *) &( (curwp->w_dotp)->l_text[ pos]), pos) ; (unsigned char *) &( (curwp->w_dotp)->l_text[ pos]), pos) ;
if( delta != 0) { if( delta != 0) {
pos = curwp->w_doto -= delta ; pos = curwp->w_doto -= delta ;
if( pos > 0) { /* check if on combining unicode */ if( pos > 0) { /* check if on combining unicode */
unicode_t unc ; unicode_t unc ;
utf8_to_unicode( curwp->w_dotp->l_text, pos, utf8_to_unicode( curwp->w_dotp->l_text, pos,
llength( curwp->w_dotp), &unc) ; llength( curwp->w_dotp), &unc) ;
if( utf8_width( unc) == 0) if( utf8_width( unc) == 0)
goto combined ; goto combined ;
} }
} }
} }
} }
} }
@ -270,7 +270,7 @@ boolean linstr( char *instr) {
while( (c = (unsigned char) *instr++)) { while( (c = (unsigned char) *instr++)) {
status = (c == '\n') ? lnewline() : linsert_byte( 1, c) ; status = (c == '\n') ? lnewline() : linsert_byte( 1, c) ;
if( status != TRUE) { /* Insertion error? */ if( status != TRUE) { /* Insertion error? */
mloutstr( "%Out of memory while inserting") ; mloutstr( "%Out of memory while inserting") ;
break ; break ;
} }
@ -294,12 +294,12 @@ boolean linsert_byte( int n, int c) {
char *cp1; char *cp1;
char *cp2; char *cp2;
line_p lp2 ; line_p lp2 ;
int i ; int i ;
assert( (curbp->b_mode & MDVIEW) == 0) ; assert( (curbp->b_mode & MDVIEW) == 0) ;
lchange( WFEDIT) ; lchange( WFEDIT) ;
line_p lp1 = curwp->w_dotp ; /* Current line */ line_p lp1 = curwp->w_dotp ; /* Current line */
if( lp1 == curbp->b_linep) { /* At the end: special */ if( lp1 == curbp->b_linep) { /* At the end: special */
if( curwp->w_doto != 0) if( curwp->w_doto != 0)
return mloutfail( "bug: linsert") ; return mloutfail( "bug: linsert") ;
@ -308,7 +308,7 @@ boolean linsert_byte( int n, int c) {
if( lp2 == NULL) if( lp2 == NULL)
return FALSE ; return FALSE ;
/* Insert after previous line */ /* Insert after previous line */
lp1->l_bp->l_fp = lp2 ; lp1->l_bp->l_fp = lp2 ;
lp2->l_fp = lp1 ; lp2->l_fp = lp1 ;
lp2->l_bp = lp1->l_bp ; lp2->l_bp = lp1->l_bp ;
@ -316,30 +316,30 @@ boolean linsert_byte( int n, int c) {
for( i = 0 ; i < n ; ++i) for( i = 0 ; i < n ; ++i)
lp2->l_text[ i] = c ; lp2->l_text[ i] = c ;
/* update point of current window */ /* update point of current window */
curwp->w_dotp = lp2 ; curwp->w_dotp = lp2 ;
curwp->w_doto = n ; curwp->w_doto = n ;
/* update all windows displaying current buffer */ /* update all windows displaying current buffer */
for( window_p wp = wheadp ; wp != NULL ; wp = wp->w_wndp) for( window_p wp = wheadp ; wp != NULL ; wp = wp->w_wndp)
if( wp->w_bufp == curbp) { if( wp->w_bufp == curbp) {
/* update top window line */ /* update top window line */
if( wp->w_linep == lp1) if( wp->w_linep == lp1)
wp->w_linep = lp2 ; wp->w_linep = lp2 ;
/* dot at end of buffer is now at beginning of new line */ /* dot at end of buffer is now at beginning of new line */
if( wp->w_dotp == lp1) if( wp->w_dotp == lp1)
wp->w_dotp = lp2 ; wp->w_dotp = lp2 ;
/* mark at end of buffer is now at beginning of new line */ /* mark at end of buffer is now at beginning of new line */
if( wp->w_markp == lp1) if( wp->w_markp == lp1)
wp->w_markp = lp2 ; wp->w_markp = lp2 ;
} }
return TRUE ; return TRUE ;
} }
int doto = curwp->w_doto ; /* Save for later. */ int doto = curwp->w_doto ; /* Save for later. */
if( lp1->l_used + n > lp1->l_size) { /* Hard: reallocate */ if( lp1->l_used + n > lp1->l_size) { /* Hard: reallocate */
lp2 = lalloc( lp1->l_used + n) ; lp2 = lalloc( lp1->l_used + n) ;
if( lp2 == NULL) if( lp2 == NULL)
@ -465,38 +465,48 @@ boolean lnewline( void) {
#else #else
lchange(WFHARD); lchange(WFHARD);
#endif #endif
line_p lp1 = curwp->w_dotp ; /* Get the address and */ line_p lp1 = curwp->w_dotp ; /* Get the address and */
int doto = curwp->w_doto ; /* offset of "." */ int doto = curwp->w_doto ; /* offset of "." */
line_p lp2 = lalloc( doto) ; /* New first half line */
/* at end of last line of non empty buffer */
if( lp1->l_fp == curbp->b_linep && lp1 != curbp->b_linep &&
doto == lp1->l_used) {
/* move dot at end of buffer, no nl inserted */
curwp->w_dotp = curbp->b_linep ;
curwp->w_doto = 0 ;
return TRUE ;
}
line_p lp2 = lalloc( doto) ; /* New first half line */
if( lp2 == NULL) if( lp2 == NULL)
return FALSE ; return FALSE ;
memcpy( lp2->l_text, lp1->l_text, doto) ; memcpy( lp2->l_text, lp1->l_text, doto) ;
lp1->l_used -= doto ; lp1->l_used -= doto ;
memmove( lp1->l_text, &lp1->l_text[ doto], lp1->l_used) ; memmove( lp1->l_text, &lp1->l_text[ doto], lp1->l_used) ;
lp2->l_fp = lp1 ; lp2->l_fp = lp1 ;
lp2->l_bp = lp1->l_bp ; lp2->l_bp = lp1->l_bp ;
lp1->l_bp = lp2 ; lp1->l_bp = lp2 ;
lp2->l_bp->l_fp = lp2 ; lp2->l_bp->l_fp = lp2 ;
for( window_p wp = wheadp ; wp != NULL ; wp = wp->w_wndp) for( window_p wp = wheadp ; wp != NULL ; wp = wp->w_wndp)
if( wp->w_bufp == curbp) { if( wp->w_bufp == curbp) {
if( wp->w_linep == lp1) if( wp->w_linep == lp1) /* adjust top line of window */
wp->w_linep = lp2 ; wp->w_linep = lp2 ;
if( wp->w_dotp == lp1) { if( wp->w_dotp == lp1) {
if( wp == curwp || wp->w_doto > doto) if( wp == curwp || wp->w_doto > doto)
wp->w_doto -= doto ; wp->w_doto -= doto ;
else else
wp->w_dotp = lp2 ; wp->w_dotp = lp2 ;
} }
if( wp->w_markp == lp1) { if( wp->w_markp == lp1) {
if( wp->w_marko > doto) if( wp->w_marko > doto)
wp->w_marko -= doto ; wp->w_marko -= doto ;
else else
wp->w_markp = lp2 ; wp->w_markp = lp2 ;
} }
} }
return TRUE ; return TRUE ;
} }
@ -506,7 +516,7 @@ boolean lnewline( void) {
* get unicode value and return UTF-8 size of character at dot. * get unicode value and return UTF-8 size of character at dot.
*/ */
int lgetchar( unicode_t *cp) { int lgetchar( unicode_t *cp) {
if( curwp->w_dotp->l_used == curwp->w_doto) { /* at EOL? */ if( curwp->w_dotp->l_used == curwp->w_doto) { /* at EOL? */
*cp = (curbp->b_mode & MDDOS) ? '\r' : '\n' ; *cp = (curbp->b_mode & MDDOS) ? '\r' : '\n' ;
return 1 ; return 1 ;
} else } else
@ -519,28 +529,28 @@ int lgetchar( unicode_t *cp) {
* return total UTF-8 size of combined character at dot. * return total UTF-8 size of combined character at dot.
*/ */
static int lcombinedsize( void) { static int lcombinedsize( void) {
if( curwp->w_dotp->l_used == curwp->w_doto) /* EOL? */ if( curwp->w_dotp->l_used == curwp->w_doto) /* EOL? */
return 1 ; return 1 ;
else { else {
unicode_t c ; unicode_t c ;
int pos = curwp->w_doto ; int pos = curwp->w_doto ;
unsigned bytes = utf8_to_unicode( curwp->w_dotp->l_text, pos, unsigned bytes = utf8_to_unicode( curwp->w_dotp->l_text, pos,
llength( curwp->w_dotp), &c) ; llength( curwp->w_dotp), &c) ;
/* check if followed by combining unicode character */ /* check if followed by combining unicode character */
pos += bytes ; pos += bytes ;
while( pos < llength( curwp->w_dotp) - 1) { /* at least 2 bytes */ while( pos < llength( curwp->w_dotp) - 1) { /* at least 2 bytes */
unsigned cnt = utf8_to_unicode( curwp->w_dotp->l_text, pos, unsigned cnt = utf8_to_unicode( curwp->w_dotp->l_text, pos,
llength( curwp->w_dotp), &c) ; llength( curwp->w_dotp), &c) ;
if( utf8_width( c) == 0) { if( utf8_width( c) == 0) {
bytes += cnt ; bytes += cnt ;
pos += cnt ; pos += cnt ;
} else } else
break ; break ;
} }
return bytes ; return bytes ;
} }
} }
@ -576,11 +586,11 @@ boolean ldelete( long n, boolean kflag) {
while( n > 0) { while( n > 0) {
line_p dotp = curwp->w_dotp ; line_p dotp = curwp->w_dotp ;
if( dotp == curbp->b_linep) /* Hit end of buffer. */ if( dotp == curbp->b_linep) /* Hit end of buffer. */
return FALSE ; return FALSE ;
int doto = curwp->w_doto ; int doto = curwp->w_doto ;
int chunk = dotp->l_used - doto ; /* Size of chunk. */ int chunk = dotp->l_used - doto ; /* Size of chunk. */
if( chunk == 0) { /* End of line, merge. */ if( chunk == 0) { /* End of line, merge. */
#if SCROLLCODE #if SCROLLCODE
lchange( WFHARD | WFKILLS) ; lchange( WFHARD | WFKILLS) ;
@ -597,7 +607,7 @@ boolean ldelete( long n, boolean kflag) {
chunk = n ; chunk = n ;
lchange( WFEDIT) ; lchange( WFEDIT) ;
char *cp1 = &dotp->l_text[ doto] ; /* Scrunch text. */ char *cp1 = &dotp->l_text[ doto] ; /* Scrunch text. */
char *cp2 = cp1 + chunk ; char *cp2 = cp1 + chunk ;
if( kflag != FALSE) { /* Kill? */ if( kflag != FALSE) { /* Kill? */
while( cp1 != cp2) { while( cp1 != cp2) {
@ -615,7 +625,7 @@ boolean ldelete( long n, boolean kflag) {
dotp->l_used -= chunk ; dotp->l_used -= chunk ;
/* Fix windows */ /* Fix windows */
for( window_p wp = wheadp ; wp != NULL ; wp = wp->w_wndp) { for( window_p wp = wheadp ; wp != NULL ; wp = wp->w_wndp) {
if( wp->w_dotp == dotp && wp->w_doto >= doto) { if( wp->w_dotp == dotp && wp->w_doto >= doto) {
wp->w_doto -= chunk ; wp->w_doto -= chunk ;
@ -648,7 +658,7 @@ boolean ldelete( long n, boolean kflag) {
static int ldelnewline( void) { static int ldelnewline( void) {
char *cp1; char *cp1;
char *cp2; char *cp2;
window_p wp ; window_p wp ;
assert( (curbp->b_mode & MDVIEW) == 0) ; assert( (curbp->b_mode & MDVIEW) == 0) ;
@ -738,7 +748,7 @@ static int ldelnewline( void) {
void kdelete( void) { void kdelete( void) {
if( kbufh != NULL) { if( kbufh != NULL) {
/* first, delete all the chunks */ /* first, delete all the chunks */
freelist( (list_p) kbufh) ; freelist( (list_p) kbufh) ;
/* and reset all the kill buffer pointers */ /* and reset all the kill buffer pointers */
kbufh = kbufp = NULL ; kbufh = kbufp = NULL ;
@ -789,40 +799,28 @@ int kinsert( int c) {
* check for errors. Bound to "C-Y". * check for errors. Bound to "C-Y".
*/ */
BINDABLE( yank) { BINDABLE( yank) {
int c;
int i;
char *sp; /* pointer into string to insert */
kill_p kp; /* pointer into kill buffer */
assert( !(curbp->b_mode & MDVIEW)) ; assert( !(curbp->b_mode & MDVIEW)) ;
if (n < 0) if (n < 0)
return FALSE; return FALSE;
/* make sure there is something to yank */
/* make sure there is something to yank */
if (kbufh == NULL) if (kbufh == NULL)
return TRUE; /* not an error, just nothing */ return TRUE; /* not an error, just nothing */
/* for each time.... */ /* for each time.... */
while (n--) { while (n--) {
kp = kbufh; for( kill_p kp = kbufh ; kp != NULL ; kp = kp->d_next) {
while (kp != NULL) { unsigned char *sp = kp->d_chunk ;
if (kp->d_next == NULL) int i = (kp->d_next == NULL) ? kused : KBLOCK ;
i = kused;
else
i = KBLOCK;
sp = kp->d_chunk;
while (i--) { while (i--) {
if ((c = *sp++) == '\n') { int c = *sp++ ;
if (lnewline() == FALSE) if( FALSE == (( c == '\n') ? lnewline() : linsert_byte( 1, c)))
return FALSE; return FALSE ;
} else {
if (linsert_byte(1, c) == FALSE)
return FALSE;
}
} }
kp = kp->d_next;
} }
} }
return TRUE; return TRUE;
} }