@ -135,6 +135,11 @@ enum selection_type {
SEL_RECTANGULAR = 2
SEL_RECTANGULAR = 2
} ;
} ;
enum selection_snap {
SNAP_WORD = 1 ,
SNAP_LINE = 2
} ;
/* bit macro */
/* bit macro */
# undef B0
# undef B0
enum { B0 = 1 , B1 = 2 , B2 = 4 , B3 = 8 , B4 = 16 , B5 = 32 , B6 = 64 , B7 = 128 } ;
enum { B0 = 1 , B1 = 2 , B2 = 4 , B3 = 8 , B4 = 16 , B5 = 32 , B6 = 64 , B7 = 128 } ;
@ -232,6 +237,7 @@ typedef struct {
typedef struct {
typedef struct {
int mode ;
int mode ;
int type ;
int type ;
int snap ;
int bx , by ;
int bx , by ;
int ex , ey ;
int ex , ey ;
struct {
struct {
@ -372,6 +378,7 @@ static void selinit(void);
static inline bool selected ( int , int ) ;
static inline bool selected ( int , int ) ;
static void selcopy ( void ) ;
static void selcopy ( void ) ;
static void selscroll ( int , int ) ;
static void selscroll ( int , int ) ;
static void selsnap ( int , int * , int * , int ) ;
static int utf8decode ( char * , long * ) ;
static int utf8decode ( char * , long * ) ;
static int utf8encode ( long * , char * ) ;
static int utf8encode ( long * , char * ) ;
@ -657,6 +664,25 @@ selected(int x, int y) {
& & ( x < = sel . e . x | | sel . b . y ! = sel . e . y ) ) ;
& & ( x < = sel . e . x | | sel . b . y ! = sel . e . y ) ) ;
}
}
void
selsnap ( int mode , int * x , int * y , int direction ) {
switch ( mode ) {
case SNAP_WORD :
while ( * x > 0 & & * x < term . col - 1 & & term . line [ * y ] [ * x + direction ] . c [ 0 ] ! = ' ' ) {
* x + = direction ;
}
break ;
case SNAP_LINE :
* x = ( direction < 0 ) ? 0 : term . col - 1 ;
break ;
default :
/* do nothing */
break ;
}
}
void
void
getbuttoninfo ( XEvent * e ) {
getbuttoninfo ( XEvent * e ) {
int type ;
int type ;
@ -667,6 +693,15 @@ getbuttoninfo(XEvent *e) {
sel . ex = x2col ( e - > xbutton . x ) ;
sel . ex = x2col ( e - > xbutton . x ) ;
sel . ey = y2row ( e - > xbutton . y ) ;
sel . ey = y2row ( e - > xbutton . y ) ;
if ( sel . by < sel . ey
| | ( sel . by = = sel . ey & & sel . bx < sel . ex ) ) {
selsnap ( sel . snap , & sel . bx , & sel . by , - 1 ) ;
selsnap ( sel . snap , & sel . ex , & sel . ey , + 1 ) ;
} else {
selsnap ( sel . snap , & sel . ex , & sel . ey , - 1 ) ;
selsnap ( sel . snap , & sel . bx , & sel . by , + 1 ) ;
}
sel . b . x = sel . by < sel . ey ? sel . bx : sel . ex ;
sel . b . x = sel . by < sel . ey ? sel . bx : sel . ex ;
sel . b . y = MIN ( sel . by , sel . ey ) ;
sel . b . y = MIN ( sel . by , sel . ey ) ;
sel . e . x = sel . by < sel . ey ? sel . ex : sel . bx ;
sel . e . x = sel . by < sel . ey ? sel . ex : sel . bx ;
@ -730,9 +765,13 @@ mousereport(XEvent *e) {
void
void
bpress ( XEvent * e ) {
bpress ( XEvent * e ) {
struct timeval now ;
if ( IS_SET ( MODE_MOUSE ) ) {
if ( IS_SET ( MODE_MOUSE ) ) {
mousereport ( e ) ;
mousereport ( e ) ;
} else if ( e - > xbutton . button = = Button1 ) {
} else if ( e - > xbutton . button = = Button1 ) {
gettimeofday ( & now , NULL ) ;
/* Clear previous selection, logically and visually. */
if ( sel . bx ! = - 1 ) {
if ( sel . bx ! = - 1 ) {
sel . bx = - 1 ;
sel . bx = - 1 ;
tsetdirt ( sel . b . y , sel . e . y ) ;
tsetdirt ( sel . b . y , sel . e . y ) ;
@ -742,6 +781,30 @@ bpress(XEvent *e) {
sel . type = SEL_REGULAR ;
sel . type = SEL_REGULAR ;
sel . ex = sel . bx = x2col ( e - > xbutton . x ) ;
sel . ex = sel . bx = x2col ( e - > xbutton . x ) ;
sel . ey = sel . by = y2row ( e - > xbutton . y ) ;
sel . ey = sel . by = y2row ( e - > xbutton . y ) ;
/*
* Snap handling .
* If user clicks are fasst enough ( e . g . below timeouts ) ,
* we ignore if his hand slipped left or down and accidentally selected more ;
* we are just snapping to whatever we ' re snapping .
*/
if ( TIMEDIFF ( now , sel . tclick2 ) < = tripleclicktimeout ) {
/* Snap to line */
sel . snap = SNAP_LINE ;
} else if ( TIMEDIFF ( now , sel . tclick1 ) < = doubleclicktimeout ) {
sel . snap = SNAP_WORD ;
} else {
sel . snap = 0 ;
}
selsnap ( sel . snap , & sel . bx , & sel . by , - 1 ) ;
selsnap ( sel . snap , & sel . ex , & sel . ey , 1 ) ;
sel . b . x = sel . bx , sel . b . y = sel . by , sel . e . x = sel . ex , sel . e . y = sel . ey ;
/* Draw selection, unless it's regular and we don't want to make clicks visible */
if ( sel . snap ! = 0 ) {
tsetdirt ( sel . b . y , sel . e . y ) ;
draw ( ) ;
}
sel . tclick2 = sel . tclick1 ;
sel . tclick1 = now ;
} else if ( e - > xbutton . button = = Button4 ) {
} else if ( e - > xbutton . button = = Button4 ) {
ttywrite ( " \031 " , 1 ) ;
ttywrite ( " \031 " , 1 ) ;
} else if ( e - > xbutton . button = = Button5 ) {
} else if ( e - > xbutton . button = = Button5 ) {
@ -907,8 +970,6 @@ xsetsel(char *str) {
void
void
brelease ( XEvent * e ) {
brelease ( XEvent * e ) {
struct timeval now ;
if ( IS_SET ( MODE_MOUSE ) ) {
if ( IS_SET ( MODE_MOUSE ) ) {
mousereport ( e ) ;
mousereport ( e ) ;
return ;
return ;
@ -922,35 +983,10 @@ brelease(XEvent *e) {
term . dirty [ sel . ey ] = 1 ;
term . dirty [ sel . ey ] = 1 ;
if ( sel . bx = = sel . ex & & sel . by = = sel . ey ) {
if ( sel . bx = = sel . ex & & sel . by = = sel . ey ) {
sel . bx = - 1 ;
sel . bx = - 1 ;
gettimeofday ( & now , NULL ) ;
if ( TIMEDIFF ( now , sel . tclick2 ) < = tripleclicktimeout ) {
/* triple click on the line */
sel . b . x = sel . bx = 0 ;
sel . e . x = sel . ex = term . col ;
sel . b . y = sel . e . y = sel . ey ;
selcopy ( ) ;
} else if ( TIMEDIFF ( now , sel . tclick1 ) < = doubleclicktimeout ) {
/* double click to select word */
sel . bx = sel . ex ;
while ( sel . bx > 0 & & term . line [ sel . ey ] [ sel . bx - 1 ] . c [ 0 ] ! = ' ' ) {
sel . bx - - ;
}
sel . b . x = sel . bx ;
while ( sel . ex < term . col - 1 & & term . line [ sel . ey ] [ sel . ex + 1 ] . c [ 0 ] ! = ' ' ) {
sel . ex + + ;
}
sel . e . x = sel . ex ;
sel . b . y = sel . e . y = sel . ey ;
selcopy ( ) ;
}
} else {
} else {
selcopy ( ) ;
selcopy ( ) ;
}
}
}
}
memcpy ( & sel . tclick2 , & sel . tclick1 , sizeof ( struct timeval ) ) ;
gettimeofday ( & sel . tclick1 , NULL ) ;
}
}
void
void