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