# st

Unnamed repository; edit this file 'description' to name the repository.

| Log | Files | Refs | README | LICENSE

    commit 872a7f18eaffd96eefb31e3dcb45fd86bc67029b
    parent 3c546ae73924804ddc6d29dc3ab2f12a93287009
    Author: Alexander Sedov <alex0player@gmail.com>
    Date:   Mon, 15 Apr 2013 10:28:31 +0400

    Added support for double/triple click+dragging.

    Now double-click+dragging automatically snaps both ends to word boundaries
    (unless on series of spaces), and triple-click selects whole lines.
    As a side effect, snapping now occurs on button press, not button release
    like it previously was, but I hope that won't be inconvenient for anyone.

    Signed-off-by: Christoph Lohmann <20h@r-36.net>

    Diffstat:
    Mst.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------

    1 file changed, 63 insertions(+), 27 deletions(-)
    diff --git a/st.c b/st.c
    @@ -135,6 +135,11 @@ enum selection_type {
     	SEL_RECTANGULAR = 2
     };

    +enum selection_snap {
    +	SNAP_WORD = 1,
    +	SNAP_LINE = 2
    +};
    +
     /* bit macro */
     #undef B0
     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 {
     	int mode;
     	int type;
    +	int snap;
     	int bx, by;
     	int ex, ey;
     	struct {
    @@ -372,6 +378,7 @@ static void selinit(void);
     static inline bool selected(int, int);
     static void selcopy(void);
     static void selscroll(int, int);
    +static void selsnap(int, int *, int *, int);

     static int utf8decode(char *, long *);
     static int utf8encode(long *, char *);
    @@ -658,6 +665,25 @@ selected(int x, int 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
     getbuttoninfo(XEvent *e) {
     	int type;
     	uint state = e->xbutton.state &~Button1Mask;
    @@ -667,6 +693,15 @@ getbuttoninfo(XEvent *e) {
     	sel.ex = x2col(e->xbutton.x);
     	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.y = MIN(sel.by, sel.ey);
     	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
    @@ -730,9 +765,13 @@ mousereport(XEvent *e) {

     void
     bpress(XEvent *e) {
    +	struct timeval now;
    +
     	if(IS_SET(MODE_MOUSE)) {
     		mousereport(e);
     	} else if(e->xbutton.button == Button1) {
    +		gettimeofday(&now, NULL);
    +		/* Clear previous selection, logically and visually. */
     		if(sel.bx != -1) {
     			sel.bx = -1;
     			tsetdirt(sel.b.y, sel.e.y);
    @@ -742,6 +781,30 @@ bpress(XEvent *e) {
     		sel.type = SEL_REGULAR;
     		sel.ex = sel.bx = x2col(e->xbutton.x);
     		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) {
     		ttywrite("\031", 1);
     	} else if(e->xbutton.button == Button5) {
    @@ -907,8 +970,6 @@ xsetsel(char *str) {

     void
     brelease(XEvent *e) {
    -	struct timeval now;
    -
     	if(IS_SET(MODE_MOUSE)) {
     		mousereport(e);
     		return;
    @@ -922,35 +983,10 @@ brelease(XEvent *e) {
     		term.dirty[sel.ey] = 1;
     		if(sel.bx == sel.ex && sel.by == sel.ey) {
     			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 {
     			selcopy();
     		}
     	}
    -
    -	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
    -	gettimeofday(&sel.tclick1, NULL);
     }

     void