Adding visual selector
This commit is contained in:
		@ -255,6 +255,7 @@ static Shortcut shortcuts[] = {
 | 
			
		||||
	{ MODKEY,               XK_l,           copyurl,        {.i =  0} },
 | 
			
		||||
	{ ShiftMask,            XK_Page_Up,     kscrollup,      {.i = -1} },
 | 
			
		||||
	{ ShiftMask,            XK_Page_Down,   kscrolldown,    {.i = -1} },
 | 
			
		||||
	{ TERMMOD,              XK_Escape,      keyboard_select,{.i =  0} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										223
									
								
								st.c
									
									
									
									
									
								
							
							
						
						
									
										223
									
								
								st.c
									
									
									
									
									
								
							@ -16,6 +16,8 @@
 | 
			
		||||
#include <termios.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <wchar.h>
 | 
			
		||||
#include <X11/keysym.h>
 | 
			
		||||
#include <X11/X.h>
 | 
			
		||||
 | 
			
		||||
#include "st.h"
 | 
			
		||||
#include "win.h"
 | 
			
		||||
@ -2609,6 +2611,9 @@ tresize(int col, int row)
 | 
			
		||||
	int *bp;
 | 
			
		||||
	TCursor c;
 | 
			
		||||
 | 
			
		||||
	if ( row < term.row  || col < term.col )
 | 
			
		||||
		toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0));
 | 
			
		||||
 | 
			
		||||
	if (col < 1 || row < 1) {
 | 
			
		||||
		fprintf(stderr,
 | 
			
		||||
		        "tresize: error resizing to %dx%d\n", col, row);
 | 
			
		||||
@ -2832,3 +2837,221 @@ copyurl(const Arg *arg) {
 | 
			
		||||
		xclipcopy();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void set_notifmode(int type, KeySym ksym) {
 | 
			
		||||
	static char *lib[] = { " MOVE ", " SEL  "};
 | 
			
		||||
	static Glyph *g, *deb, *fin;
 | 
			
		||||
	static int col, bot;
 | 
			
		||||
 | 
			
		||||
	if ( ksym == -1 ) {
 | 
			
		||||
		free(g);
 | 
			
		||||
		col = term.col, bot = term.bot;
 | 
			
		||||
		g = xmalloc(col * sizeof(Glyph));
 | 
			
		||||
		memcpy(g, term.line[bot], col * sizeof(Glyph));
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	else if ( ksym == -2 )
 | 
			
		||||
		memcpy(term.line[bot], g, col * sizeof(Glyph));
 | 
			
		||||
 | 
			
		||||
	if ( type < 2 ) {
 | 
			
		||||
		char *z = lib[type];
 | 
			
		||||
		for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++)
 | 
			
		||||
			deb->mode = ATTR_REVERSE,
 | 
			
		||||
				deb->u = *z,
 | 
			
		||||
				deb->fg = defaultfg, deb->bg = defaultbg;
 | 
			
		||||
	}
 | 
			
		||||
	else if ( type < 5 )
 | 
			
		||||
		memcpy(term.line[bot], g, col * sizeof(Glyph));
 | 
			
		||||
	else {
 | 
			
		||||
		for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++)
 | 
			
		||||
			deb->mode = ATTR_REVERSE,
 | 
			
		||||
				deb->u = ' ',
 | 
			
		||||
				deb->fg = defaultfg, deb->bg = defaultbg;
 | 
			
		||||
		term.line[bot][0].u = ksym;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	term.dirty[bot] = 1;
 | 
			
		||||
	drawregion(0, bot, col, bot + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void select_or_drawcursor(int selectsearch_mode, int type) {
 | 
			
		||||
	int done = 0;
 | 
			
		||||
 | 
			
		||||
	if ( selectsearch_mode & 1 ) {
 | 
			
		||||
		selextend(term.c.x, term.c.y, type, done);
 | 
			
		||||
		xsetsel(getsel());
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
 | 
			
		||||
			    term.ocx, term.ocy, term.line[term.ocy][term.ocx],
 | 
			
		||||
				term.line[term.ocy], term.col);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) {
 | 
			
		||||
	Rune *r;
 | 
			
		||||
	int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr;
 | 
			
		||||
 | 
			
		||||
	for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) {
 | 
			
		||||
		for (r = target; r - target < ptarget; r++) {
 | 
			
		||||
			if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) {
 | 
			
		||||
				if ( r - target == ptarget - 1 )     break;
 | 
			
		||||
			} else {
 | 
			
		||||
				r = NULL;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if ( r != NULL )    break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( i != bound ) {
 | 
			
		||||
		term.c.y = i / term.col, term.c.x = i % term.col;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int trt_kbdselect(KeySym ksym, char *buf, int len) {
 | 
			
		||||
	static TCursor cu;
 | 
			
		||||
	static Rune target[64];
 | 
			
		||||
	static int type = 1, ptarget, in_use;
 | 
			
		||||
	static int sens, quant;
 | 
			
		||||
	static char selectsearch_mode;
 | 
			
		||||
	int i, bound, *xy;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if ( selectsearch_mode & 2 ) {
 | 
			
		||||
		if ( ksym == XK_Return ) {
 | 
			
		||||
			selectsearch_mode ^= 2;
 | 
			
		||||
			set_notifmode(selectsearch_mode, -2);
 | 
			
		||||
			if ( ksym == XK_Escape )    ptarget = 0;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( ksym == XK_BackSpace ) {
 | 
			
		||||
			if ( !ptarget )     return 0;
 | 
			
		||||
			term.line[term.bot][ptarget--].u = ' ';
 | 
			
		||||
		}
 | 
			
		||||
		else if ( len < 1 ) {
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( ptarget == term.col  || ksym == XK_Escape ) {
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			utf8decode(buf, &target[ptarget++], len);
 | 
			
		||||
			term.line[term.bot][ptarget].u = target[ptarget - 1];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ( ksym != XK_BackSpace )
 | 
			
		||||
			search(selectsearch_mode, &target[0], ptarget, sens, type, &cu);
 | 
			
		||||
 | 
			
		||||
		term.dirty[term.bot] = 1;
 | 
			
		||||
		drawregion(0, term.bot, term.col, term.bot + 1);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch ( ksym ) {
 | 
			
		||||
	case -1 :
 | 
			
		||||
		in_use = 1;
 | 
			
		||||
		cu.x = term.c.x, cu.y = term.c.y;
 | 
			
		||||
		set_notifmode(0, ksym);
 | 
			
		||||
		return MODE_KBDSELECT;
 | 
			
		||||
	case XK_s :
 | 
			
		||||
		if ( selectsearch_mode & 1 )
 | 
			
		||||
			selclear();
 | 
			
		||||
		else
 | 
			
		||||
			selstart(term.c.x, term.c.y, 0);
 | 
			
		||||
		set_notifmode(selectsearch_mode ^= 1, ksym);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_t :
 | 
			
		||||
		selextend(term.c.x, term.c.y, type ^= 3, i = 0);  /* 2 fois */
 | 
			
		||||
		selextend(term.c.x, term.c.y, type, i = 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_slash :
 | 
			
		||||
	case XK_KP_Divide :
 | 
			
		||||
	case XK_question :
 | 
			
		||||
		ksym &= XK_question;                /* Divide to slash */
 | 
			
		||||
		sens = (ksym == XK_slash) ? -1 : 1;
 | 
			
		||||
		ptarget = 0;
 | 
			
		||||
		set_notifmode(15, ksym);
 | 
			
		||||
		selectsearch_mode ^= 2;
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_Escape :
 | 
			
		||||
		if ( !in_use )  break;
 | 
			
		||||
		selclear();
 | 
			
		||||
	case XK_Return :
 | 
			
		||||
		set_notifmode(4, ksym);
 | 
			
		||||
		term.c.x = cu.x, term.c.y = cu.y;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode = 0, type);
 | 
			
		||||
		in_use = quant = 0;
 | 
			
		||||
		return MODE_KBDSELECT;
 | 
			
		||||
	case XK_n :
 | 
			
		||||
	case XK_N :
 | 
			
		||||
		if ( ptarget )
 | 
			
		||||
			search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_BackSpace :
 | 
			
		||||
		term.c.x = 0;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_dollar :
 | 
			
		||||
		term.c.x = term.col - 1;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_Home :
 | 
			
		||||
		term.c.x = 0, term.c.y = 0;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_End :
 | 
			
		||||
		term.c.x = cu.x, term.c.y = cu.y;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_Page_Up :
 | 
			
		||||
	case XK_Page_Down :
 | 
			
		||||
		term.c.y = (ksym == XK_Prior ) ? 0 : cu.y;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_exclam :
 | 
			
		||||
		term.c.x = term.col >> 1;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_asterisk :
 | 
			
		||||
	case XK_KP_Multiply :
 | 
			
		||||
		term.c.x = term.col >> 1;
 | 
			
		||||
	case XK_underscore :
 | 
			
		||||
		term.c.y = cu.y >> 1;
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
		break;
 | 
			
		||||
	default :
 | 
			
		||||
		if ( ksym >= XK_0 && ksym <= XK_9 ) {               /* 0-9 keyboard */
 | 
			
		||||
			quant = (quant * 10) + (ksym ^ XK_0);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) {    /* 0-9 numpad */
 | 
			
		||||
			quant = (quant * 10) + (ksym ^ XK_KP_0);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( ksym == XK_k || ksym == XK_h )
 | 
			
		||||
			i = ksym & 1;
 | 
			
		||||
		else if ( ksym == XK_l || ksym == XK_j )
 | 
			
		||||
			i = ((ksym & 6) | 4) >> 1;
 | 
			
		||||
		else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 )
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		xy = (i & 1) ? &term.c.y : &term.c.x;
 | 
			
		||||
		sens = (i & 2) ? 1 : -1;
 | 
			
		||||
		bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot;
 | 
			
		||||
 | 
			
		||||
		if ( quant == 0 )
 | 
			
		||||
			quant++;
 | 
			
		||||
 | 
			
		||||
		if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) )
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		*xy += quant * sens;
 | 
			
		||||
		if ( *xy < 0 || ( bound > 0 && *xy > bound) )
 | 
			
		||||
			*xy = bound;
 | 
			
		||||
 | 
			
		||||
		select_or_drawcursor(selectsearch_mode, type);
 | 
			
		||||
	}
 | 
			
		||||
	quant = 0;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										65
									
								
								st.h
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								st.h
									
									
									
									
									
								
							@ -12,45 +12,45 @@
 | 
			
		||||
#define DEFAULT(a, b)		(a) = (a) ? (a) : (b)
 | 
			
		||||
#define LIMIT(x, a, b)		(x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
 | 
			
		||||
#define ATTRCMP(a, b)		(((a).mode & (~ATTR_WRAP)) != ((b).mode & (~ATTR_WRAP)) || \
 | 
			
		||||
				(a).fg != (b).fg || \
 | 
			
		||||
				(a).bg != (b).bg)
 | 
			
		||||
			(a).fg != (b).fg || \
 | 
			
		||||
			(a).bg != (b).bg)
 | 
			
		||||
#define TIMEDIFF(t1, t2)	((t1.tv_sec-t2.tv_sec)*1000 + \
 | 
			
		||||
				(t1.tv_nsec-t2.tv_nsec)/1E6)
 | 
			
		||||
			(t1.tv_nsec-t2.tv_nsec)/1E6)
 | 
			
		||||
#define MODBIT(x, set, bit)	((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 | 
			
		||||
 | 
			
		||||
#define TRUECOLOR(r,g,b)	(1 << 24 | (r) << 16 | (g) << 8 | (b))
 | 
			
		||||
#define IS_TRUECOL(x)		(1 << 24 & (x))
 | 
			
		||||
 | 
			
		||||
enum glyph_attribute {
 | 
			
		||||
	ATTR_NULL       = 0,
 | 
			
		||||
	ATTR_BOLD       = 1 << 0,
 | 
			
		||||
	ATTR_FAINT      = 1 << 1,
 | 
			
		||||
	ATTR_ITALIC     = 1 << 2,
 | 
			
		||||
	ATTR_UNDERLINE  = 1 << 3,
 | 
			
		||||
	ATTR_BLINK      = 1 << 4,
 | 
			
		||||
	ATTR_REVERSE    = 1 << 5,
 | 
			
		||||
	ATTR_INVISIBLE  = 1 << 6,
 | 
			
		||||
	ATTR_STRUCK     = 1 << 7,
 | 
			
		||||
	ATTR_WRAP       = 1 << 8,
 | 
			
		||||
	ATTR_WIDE       = 1 << 9,
 | 
			
		||||
	ATTR_WDUMMY     = 1 << 10,
 | 
			
		||||
	ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
 | 
			
		||||
ATTR_NULL       = 0,
 | 
			
		||||
ATTR_BOLD       = 1 << 0,
 | 
			
		||||
ATTR_FAINT      = 1 << 1,
 | 
			
		||||
ATTR_ITALIC     = 1 << 2,
 | 
			
		||||
ATTR_UNDERLINE  = 1 << 3,
 | 
			
		||||
ATTR_BLINK      = 1 << 4,
 | 
			
		||||
ATTR_REVERSE    = 1 << 5,
 | 
			
		||||
ATTR_INVISIBLE  = 1 << 6,
 | 
			
		||||
ATTR_STRUCK     = 1 << 7,
 | 
			
		||||
ATTR_WRAP       = 1 << 8,
 | 
			
		||||
ATTR_WIDE       = 1 << 9,
 | 
			
		||||
ATTR_WDUMMY     = 1 << 10,
 | 
			
		||||
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum selection_mode {
 | 
			
		||||
	SEL_IDLE = 0,
 | 
			
		||||
	SEL_EMPTY = 1,
 | 
			
		||||
	SEL_READY = 2
 | 
			
		||||
SEL_IDLE = 0,
 | 
			
		||||
SEL_EMPTY = 1,
 | 
			
		||||
SEL_READY = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum selection_type {
 | 
			
		||||
	SEL_REGULAR = 1,
 | 
			
		||||
	SEL_RECTANGULAR = 2
 | 
			
		||||
SEL_REGULAR = 1,
 | 
			
		||||
SEL_RECTANGULAR = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum selection_snap {
 | 
			
		||||
	SNAP_WORD = 1,
 | 
			
		||||
	SNAP_LINE = 2
 | 
			
		||||
SNAP_WORD = 1,
 | 
			
		||||
SNAP_LINE = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef unsigned char uchar;
 | 
			
		||||
@ -62,20 +62,20 @@ typedef uint_least32_t Rune;
 | 
			
		||||
 | 
			
		||||
#define Glyph Glyph_
 | 
			
		||||
typedef struct {
 | 
			
		||||
	Rune u;           /* character code */
 | 
			
		||||
	ushort mode;      /* attribute flags */
 | 
			
		||||
	uint32_t fg;      /* foreground  */
 | 
			
		||||
	uint32_t bg;      /* background  */
 | 
			
		||||
Rune u;           /* character code */
 | 
			
		||||
ushort mode;      /* attribute flags */
 | 
			
		||||
uint32_t fg;      /* foreground  */
 | 
			
		||||
uint32_t bg;      /* background  */
 | 
			
		||||
} Glyph;
 | 
			
		||||
 | 
			
		||||
typedef Glyph *Line;
 | 
			
		||||
 | 
			
		||||
typedef union {
 | 
			
		||||
	int i;
 | 
			
		||||
	uint ui;
 | 
			
		||||
	float f;
 | 
			
		||||
	const void *v;
 | 
			
		||||
	const char *s;
 | 
			
		||||
int i;
 | 
			
		||||
uint ui;
 | 
			
		||||
float f;
 | 
			
		||||
const void *v;
 | 
			
		||||
const char *s;
 | 
			
		||||
} Arg;
 | 
			
		||||
 | 
			
		||||
void die(const char *, ...);
 | 
			
		||||
@ -114,6 +114,7 @@ size_t utf8encode(Rune, char *);
 | 
			
		||||
void *xmalloc(size_t);
 | 
			
		||||
void *xrealloc(void *, size_t);
 | 
			
		||||
char *xstrdup(const char *);
 | 
			
		||||
int  trt_kbdselect(KeySym, char *, int);
 | 
			
		||||
 | 
			
		||||
/* config.h globals */
 | 
			
		||||
extern char *utmp;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								win.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								win.h
									
									
									
									
									
								
							@ -21,6 +21,7 @@ enum win_mode {
 | 
			
		||||
	MODE_NUMLOCK     = 1 << 17,
 | 
			
		||||
	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
 | 
			
		||||
	                  |MODE_MOUSEMANY,
 | 
			
		||||
	MODE_KBDSELECT   = 1 << 18,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void xbell(void);
 | 
			
		||||
@ -38,4 +39,6 @@ void xsetmode(int, unsigned int);
 | 
			
		||||
void xsetpointermotion(int);
 | 
			
		||||
void xsetsel(char *);
 | 
			
		||||
int xstartdraw(void);
 | 
			
		||||
void toggle_winmode(int);
 | 
			
		||||
void keyboard_select(const Arg *);
 | 
			
		||||
void xximspot(int, int);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								x.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								x.c
									
									
									
									
									
								
							@ -1951,6 +1951,12 @@ kpress(XEvent *ev)
 | 
			
		||||
	} else {
 | 
			
		||||
		len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if ( IS_SET(MODE_KBDSELECT) ) {
 | 
			
		||||
		if ( match(XK_NO_MOD, e->state) ||
 | 
			
		||||
			 (XK_Shift_L | XK_Shift_R) & e->state )
 | 
			
		||||
			win.mode ^= trt_kbdselect(ksym, buf, len);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	/* 1. shortcuts */
 | 
			
		||||
	for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
 | 
			
		||||
		if (ksym == bp->keysym && match(bp->mod, e->state)) {
 | 
			
		||||
@ -2181,6 +2187,14 @@ usage(void)
 | 
			
		||||
	    " [stty_args ...]\n", argv0, argv0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void toggle_winmode(int flag) {
 | 
			
		||||
	win.mode ^= flag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void keyboard_select(const Arg *dummy) {
 | 
			
		||||
	win.mode ^= trt_kbdselect(-1, NULL, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user