File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / window-copy.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (7 years ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    1: /* $OpenBSD$ */
    2: 
    3: /*
    4:  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
    5:  *
    6:  * Permission to use, copy, modify, and distribute this software for any
    7:  * purpose with or without fee is hereby granted, provided that the above
    8:  * copyright notice and this permission notice appear in all copies.
    9:  *
   10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17:  */
   18: 
   19: #include <sys/types.h>
   20: 
   21: #include <ctype.h>
   22: #include <stdlib.h>
   23: #include <string.h>
   24: 
   25: #include "tmux.h"
   26: 
   27: static const char *window_copy_key_table(struct window_pane *);
   28: static void	window_copy_command(struct window_pane *, struct client *,
   29: 		    struct session *, struct args *, struct mouse_event *);
   30: static struct screen *window_copy_init(struct window_pane *);
   31: static void	window_copy_free(struct window_pane *);
   32: static int	window_copy_pagedown(struct window_pane *, int);
   33: static void	window_copy_next_paragraph(struct window_pane *);
   34: static void	window_copy_previous_paragraph(struct window_pane *);
   35: static void	window_copy_resize(struct window_pane *, u_int, u_int);
   36: 
   37: static void	window_copy_redraw_selection(struct window_pane *, u_int);
   38: static void	window_copy_redraw_lines(struct window_pane *, u_int, u_int);
   39: static void	window_copy_redraw_screen(struct window_pane *);
   40: static void	window_copy_write_line(struct window_pane *,
   41: 		    struct screen_write_ctx *, u_int);
   42: static void	window_copy_write_lines(struct window_pane *,
   43: 		    struct screen_write_ctx *, u_int, u_int);
   44: 
   45: static void	window_copy_scroll_to(struct window_pane *, u_int, u_int);
   46: static int	window_copy_search_compare(struct grid *, u_int, u_int,
   47: 		    struct grid *, u_int, int);
   48: static int	window_copy_search_lr(struct grid *, struct grid *, u_int *,
   49: 		    u_int, u_int, u_int, int);
   50: static int	window_copy_search_rl(struct grid *, struct grid *, u_int *,
   51: 		    u_int, u_int, u_int, int);
   52: static int	window_copy_search_marks(struct window_pane *, struct screen *);
   53: static void	window_copy_clear_marks(struct window_pane *);
   54: static void	window_copy_move_left(struct screen *, u_int *, u_int *);
   55: static void	window_copy_move_right(struct screen *, u_int *, u_int *);
   56: static int	window_copy_is_lowercase(const char *);
   57: static int	window_copy_search_jump(struct window_pane *, struct grid *,
   58: 		    struct grid *, u_int, u_int, u_int, int, int, int);
   59: static int	window_copy_search(struct window_pane *, int, int);
   60: static int	window_copy_search_up(struct window_pane *, int);
   61: static int	window_copy_search_down(struct window_pane *, int);
   62: static void	window_copy_goto_line(struct window_pane *, const char *);
   63: static void	window_copy_update_cursor(struct window_pane *, u_int, u_int);
   64: static void	window_copy_start_selection(struct window_pane *);
   65: static int	window_copy_adjust_selection(struct window_pane *, u_int *,
   66: 		    u_int *);
   67: static int	window_copy_update_selection(struct window_pane *, int);
   68: static void	window_copy_synchronize_cursor(struct window_pane *wp);
   69: static void    *window_copy_get_selection(struct window_pane *, size_t *);
   70: static void	window_copy_copy_buffer(struct window_pane *, const char *,
   71: 		    void *, size_t);
   72: static void	window_copy_copy_pipe(struct window_pane *, struct session *,
   73: 		    const char *, const char *);
   74: static void	window_copy_copy_selection(struct window_pane *, const char *);
   75: static void	window_copy_append_selection(struct window_pane *,
   76: 		    const char *);
   77: static void	window_copy_clear_selection(struct window_pane *);
   78: static void	window_copy_copy_line(struct window_pane *, char **, size_t *,
   79: 		    u_int, u_int, u_int);
   80: static int	window_copy_in_set(struct window_pane *, u_int, u_int,
   81: 		    const char *);
   82: static u_int	window_copy_find_length(struct window_pane *, u_int);
   83: static void	window_copy_cursor_start_of_line(struct window_pane *);
   84: static void	window_copy_cursor_back_to_indentation(struct window_pane *);
   85: static void	window_copy_cursor_end_of_line(struct window_pane *);
   86: static void	window_copy_other_end(struct window_pane *);
   87: static void	window_copy_cursor_left(struct window_pane *);
   88: static void	window_copy_cursor_right(struct window_pane *);
   89: static void	window_copy_cursor_up(struct window_pane *, int);
   90: static void	window_copy_cursor_down(struct window_pane *, int);
   91: static void	window_copy_cursor_jump(struct window_pane *);
   92: static void	window_copy_cursor_jump_back(struct window_pane *);
   93: static void	window_copy_cursor_jump_to(struct window_pane *, int);
   94: static void	window_copy_cursor_jump_to_back(struct window_pane *, int);
   95: static void	window_copy_cursor_next_word(struct window_pane *,
   96: 		    const char *);
   97: static void	window_copy_cursor_next_word_end(struct window_pane *,
   98: 		    const char *);
   99: static void	window_copy_cursor_previous_word(struct window_pane *,
  100: 		    const char *);
  101: static void	window_copy_scroll_up(struct window_pane *, u_int);
  102: static void	window_copy_scroll_down(struct window_pane *, u_int);
  103: static void	window_copy_rectangle_toggle(struct window_pane *);
  104: static void	window_copy_move_mouse(struct mouse_event *);
  105: static void	window_copy_drag_update(struct client *, struct mouse_event *);
  106: 
  107: const struct window_mode window_copy_mode = {
  108: 	.init = window_copy_init,
  109: 	.free = window_copy_free,
  110: 	.resize = window_copy_resize,
  111: 	.key_table = window_copy_key_table,
  112: 	.command = window_copy_command,
  113: };
  114: 
  115: enum {
  116: 	WINDOW_COPY_OFF,
  117: 	WINDOW_COPY_SEARCHUP,
  118: 	WINDOW_COPY_SEARCHDOWN,
  119: 	WINDOW_COPY_JUMPFORWARD,
  120: 	WINDOW_COPY_JUMPBACKWARD,
  121: 	WINDOW_COPY_JUMPTOFORWARD,
  122: 	WINDOW_COPY_JUMPTOBACKWARD,
  123: };
  124: 
  125: enum {
  126: 	WINDOW_COPY_REL_POS_ABOVE,
  127: 	WINDOW_COPY_REL_POS_ON_SCREEN,
  128: 	WINDOW_COPY_REL_POS_BELOW,
  129: };
  130: 
  131: /*
  132:  * Copy mode's visible screen (the "screen" field) is filled from one of two
  133:  * sources: the original contents of the pane (used when we actually enter via
  134:  * the "copy-mode" command, to copy the contents of the current pane), or else
  135:  * a series of lines containing the output from an output-writing tmux command
  136:  * (such as any of the "show-*" or "list-*" commands).
  137:  *
  138:  * In either case, the full content of the copy-mode grid is pointed at by the
  139:  * "backing" field, and is copied into "screen" as needed (that is, when
  140:  * scrolling occurs). When copy-mode is backed by a pane, backing points
  141:  * directly at that pane's screen structure (&wp->base); when backed by a list
  142:  * of output-lines from a command, it points at a newly-allocated screen
  143:  * structure (which is deallocated when the mode ends).
  144:  */
  145: struct window_copy_mode_data {
  146: 	struct screen	 screen;
  147: 
  148: 	struct screen	*backing;
  149: 	int		 backing_written; /* backing display started */
  150: 
  151: 	u_int		 oy; /* number of lines scrolled up */
  152: 
  153: 	u_int		 selx; /* beginning of selection */
  154: 	u_int		 sely;
  155: 
  156: 	u_int		 endselx; /* end of selection */
  157: 	u_int		 endsely;
  158: 
  159: 	enum {
  160: 		CURSORDRAG_NONE,	/* selection is independent of cursor */
  161: 		CURSORDRAG_ENDSEL,	/* end is synchronized with cursor */
  162: 		CURSORDRAG_SEL,		/* start is synchronized with cursor */
  163: 	} cursordrag;
  164: 
  165: 	int		 rectflag;	/* in rectangle copy mode? */
  166: 	int		 scroll_exit;	/* exit on scroll to end? */
  167: 
  168: 	u_int		 cx;
  169: 	u_int		 cy;
  170: 
  171: 	u_int		 lastcx; /* position in last line w/ content */
  172: 	u_int		 lastsx; /* size of last line w/ content */
  173: 
  174: 	int		 searchtype;
  175: 	char		*searchstr;
  176: 	bitstr_t        *searchmark;
  177: 	u_int		 searchcount;
  178: 	int		 searchthis;
  179: 	int		 searchx;
  180: 	int		 searchy;
  181: 	int		 searcho;
  182: 
  183: 	int		 jumptype;
  184: 	char		 jumpchar;
  185: };
  186: 
  187: static struct screen *
  188: window_copy_init(struct window_pane *wp)
  189: {
  190: 	struct window_copy_mode_data	*data;
  191: 	struct screen			*s;
  192: 
  193: 	wp->modedata = data = xmalloc(sizeof *data);
  194: 
  195: 	data->oy = 0;
  196: 	data->cx = 0;
  197: 	data->cy = 0;
  198: 
  199: 	data->cursordrag = CURSORDRAG_NONE;
  200: 
  201: 	data->lastcx = 0;
  202: 	data->lastsx = 0;
  203: 
  204: 	data->backing_written = 0;
  205: 
  206: 	data->rectflag = 0;
  207: 	data->scroll_exit = 0;
  208: 
  209: 	data->searchtype = WINDOW_COPY_OFF;
  210: 	data->searchstr = NULL;
  211: 	data->searchmark = NULL;
  212: 	data->searchx = data->searchy = data->searcho = -1;
  213: 
  214: 	if (wp->fd != -1)
  215: 		bufferevent_disable(wp->event, EV_READ|EV_WRITE);
  216: 
  217: 	data->jumptype = WINDOW_COPY_OFF;
  218: 	data->jumpchar = '\0';
  219: 
  220: 	s = &data->screen;
  221: 	screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
  222: 	s->sel.modekeys = options_get_number(wp->window->options, "mode-keys");
  223: 
  224: 	data->backing = NULL;
  225: 
  226: 	return (s);
  227: }
  228: 
  229: void
  230: window_copy_init_from_pane(struct window_pane *wp, int scroll_exit)
  231: {
  232: 	struct window_copy_mode_data	*data = wp->modedata;
  233: 	struct screen			*s = &data->screen;
  234: 	struct screen_write_ctx	 	 ctx;
  235: 	u_int				 i;
  236: 
  237: 	if (wp->mode != &window_copy_mode)
  238: 		fatalx("not in copy mode");
  239: 
  240: 	data->backing = &wp->base;
  241: 	data->cx = data->backing->cx;
  242: 	data->cy = data->backing->cy;
  243: 	data->scroll_exit = scroll_exit;
  244: 
  245: 	s->cx = data->cx;
  246: 	s->cy = data->cy;
  247: 
  248: 	screen_write_start(&ctx, NULL, s);
  249: 	for (i = 0; i < screen_size_y(s); i++)
  250: 		window_copy_write_line(wp, &ctx, i);
  251: 	screen_write_cursormove(&ctx, data->cx, data->cy);
  252: 	screen_write_stop(&ctx);
  253: }
  254: 
  255: void
  256: window_copy_init_for_output(struct window_pane *wp)
  257: {
  258: 	struct window_copy_mode_data	*data = wp->modedata;
  259: 
  260: 	data->backing = xmalloc(sizeof *data->backing);
  261: 	screen_init(data->backing, screen_size_x(&wp->base),
  262: 	    screen_size_y(&wp->base), UINT_MAX);
  263: }
  264: 
  265: static void
  266: window_copy_free(struct window_pane *wp)
  267: {
  268: 	struct window_copy_mode_data	*data = wp->modedata;
  269: 
  270: 	if (wp->fd != -1)
  271: 		bufferevent_enable(wp->event, EV_READ|EV_WRITE);
  272: 
  273: 	free(data->searchmark);
  274: 	free(data->searchstr);
  275: 
  276: 	if (data->backing != &wp->base) {
  277: 		screen_free(data->backing);
  278: 		free(data->backing);
  279: 	}
  280: 	screen_free(&data->screen);
  281: 
  282: 	free(data);
  283: }
  284: 
  285: void
  286: window_copy_add(struct window_pane *wp, const char *fmt, ...)
  287: {
  288: 	va_list	ap;
  289: 
  290: 	va_start(ap, fmt);
  291: 	window_copy_vadd(wp, fmt, ap);
  292: 	va_end(ap);
  293: }
  294: 
  295: void
  296: window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
  297: {
  298: 	struct window_copy_mode_data	*data = wp->modedata;
  299: 	struct screen			*backing = data->backing;
  300: 	struct screen_write_ctx	 	 back_ctx, ctx;
  301: 	struct grid_cell		 gc;
  302: 	u_int				 old_hsize, old_cy;
  303: 
  304: 	if (backing == &wp->base)
  305: 		return;
  306: 
  307: 	memcpy(&gc, &grid_default_cell, sizeof gc);
  308: 
  309: 	old_hsize = screen_hsize(data->backing);
  310: 	screen_write_start(&back_ctx, NULL, backing);
  311: 	if (data->backing_written) {
  312: 		/*
  313: 		 * On the second or later line, do a CRLF before writing
  314: 		 * (so it's on a new line).
  315: 		 */
  316: 		screen_write_carriagereturn(&back_ctx);
  317: 		screen_write_linefeed(&back_ctx, 0);
  318: 	} else
  319: 		data->backing_written = 1;
  320: 	old_cy = backing->cy;
  321: 	screen_write_vnputs(&back_ctx, 0, &gc, fmt, ap);
  322: 	screen_write_stop(&back_ctx);
  323: 
  324: 	data->oy += screen_hsize(data->backing) - old_hsize;
  325: 
  326: 	screen_write_start(&ctx, wp, &data->screen);
  327: 
  328: 	/*
  329: 	 * If the history has changed, draw the top line.
  330: 	 * (If there's any history at all, it has changed.)
  331: 	 */
  332: 	if (screen_hsize(data->backing))
  333: 		window_copy_redraw_lines(wp, 0, 1);
  334: 
  335: 	/* Write the new lines. */
  336: 	window_copy_redraw_lines(wp, old_cy, backing->cy - old_cy + 1);
  337: 
  338: 	screen_write_stop(&ctx);
  339: }
  340: 
  341: void
  342: window_copy_pageup(struct window_pane *wp, int half_page)
  343: {
  344: 	struct window_copy_mode_data	*data = wp->modedata;
  345: 	struct screen			*s = &data->screen;
  346: 	u_int				 n, ox, oy, px, py;
  347: 
  348: 	oy = screen_hsize(data->backing) + data->cy - data->oy;
  349: 	ox = window_copy_find_length(wp, oy);
  350: 
  351: 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
  352: 		window_copy_other_end(wp);
  353: 
  354: 	if (data->cx != ox) {
  355: 		data->lastcx = data->cx;
  356: 		data->lastsx = ox;
  357: 	}
  358: 	data->cx = data->lastcx;
  359: 
  360: 	n = 1;
  361: 	if (screen_size_y(s) > 2) {
  362: 		if (half_page)
  363: 			n = screen_size_y(s) / 2;
  364: 		else
  365: 			n = screen_size_y(s) - 2;
  366: 	}
  367: 
  368: 	if (data->oy + n > screen_hsize(data->backing))
  369: 		data->oy = screen_hsize(data->backing);
  370: 	else
  371: 		data->oy += n;
  372: 
  373: 	if (!data->screen.sel.flag || !data->rectflag) {
  374: 		py = screen_hsize(data->backing) + data->cy - data->oy;
  375: 		px = window_copy_find_length(wp, py);
  376: 		if ((data->cx >= data->lastsx && data->cx != px) ||
  377: 		    data->cx > px)
  378: 			window_copy_cursor_end_of_line(wp);
  379: 	}
  380: 
  381: 	window_copy_update_selection(wp, 1);
  382: 	window_copy_redraw_screen(wp);
  383: }
  384: 
  385: static int
  386: window_copy_pagedown(struct window_pane *wp, int half_page)
  387: {
  388: 	struct window_copy_mode_data	*data = wp->modedata;
  389: 	struct screen			*s = &data->screen;
  390: 	u_int				 n, ox, oy, px, py;
  391: 
  392: 	oy = screen_hsize(data->backing) + data->cy - data->oy;
  393: 	ox = window_copy_find_length(wp, oy);
  394: 
  395: 	if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT && oy == data->sely)
  396: 		window_copy_other_end(wp);
  397: 
  398: 	if (data->cx != ox) {
  399: 		data->lastcx = data->cx;
  400: 		data->lastsx = ox;
  401: 	}
  402: 	data->cx = data->lastcx;
  403: 
  404: 	n = 1;
  405: 	if (screen_size_y(s) > 2) {
  406: 		if (half_page)
  407: 			n = screen_size_y(s) / 2;
  408: 		else
  409: 			n = screen_size_y(s) - 2;
  410: 	}
  411: 
  412: 	if (data->oy < n)
  413: 		data->oy = 0;
  414: 	else
  415: 		data->oy -= n;
  416: 
  417: 	if (!data->screen.sel.flag || !data->rectflag) {
  418: 		py = screen_hsize(data->backing) + data->cy - data->oy;
  419: 		px = window_copy_find_length(wp, py);
  420: 		if ((data->cx >= data->lastsx && data->cx != px) ||
  421: 		    data->cx > px)
  422: 			window_copy_cursor_end_of_line(wp);
  423: 	}
  424: 
  425: 	if (data->scroll_exit && data->oy == 0)
  426: 		return (1);
  427: 	window_copy_update_selection(wp, 1);
  428: 	window_copy_redraw_screen(wp);
  429: 	return (0);
  430: }
  431: 
  432: static void
  433: window_copy_previous_paragraph(struct window_pane *wp)
  434: {
  435: 	struct window_copy_mode_data	*data = wp->modedata;
  436: 	u_int				 oy;
  437: 
  438: 	oy = screen_hsize(data->backing) + data->cy - data->oy;
  439: 
  440: 	while (oy > 0 && window_copy_find_length(wp, oy) == 0)
  441: 		oy--;
  442: 
  443: 	while (oy > 0 && window_copy_find_length(wp, oy) > 0)
  444: 		oy--;
  445: 
  446: 	window_copy_scroll_to(wp, 0, oy);
  447: }
  448: 
  449: static void
  450: window_copy_next_paragraph(struct window_pane *wp)
  451: {
  452: 	struct window_copy_mode_data	*data = wp->modedata;
  453: 	struct screen			*s = &data->screen;
  454: 	u_int				 maxy, ox, oy;
  455: 
  456: 	oy = screen_hsize(data->backing) + data->cy - data->oy;
  457: 	maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
  458: 
  459: 	while (oy < maxy && window_copy_find_length(wp, oy) == 0)
  460: 		oy++;
  461: 
  462: 	while (oy < maxy && window_copy_find_length(wp, oy) > 0)
  463: 		oy++;
  464: 
  465: 	ox = window_copy_find_length(wp, oy);
  466: 	window_copy_scroll_to(wp, ox, oy);
  467: }
  468: 
  469: static void
  470: window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
  471: {
  472: 	struct window_copy_mode_data	*data = wp->modedata;
  473: 	struct screen			*s = &data->screen;
  474: 	struct screen_write_ctx	 	 ctx;
  475: 
  476: 	screen_resize(s, sx, sy, 1);
  477: 	if (data->backing != &wp->base)
  478: 		screen_resize(data->backing, sx, sy, 1);
  479: 
  480: 	if (data->cy > sy - 1)
  481: 		data->cy = sy - 1;
  482: 	if (data->cx > sx)
  483: 		data->cx = sx;
  484: 	if (data->oy > screen_hsize(data->backing))
  485: 		data->oy = screen_hsize(data->backing);
  486: 
  487: 	window_copy_clear_selection(wp);
  488: 
  489: 	screen_write_start(&ctx, NULL, s);
  490: 	window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1);
  491: 	screen_write_stop(&ctx);
  492: 
  493: 	if (data->searchmark != NULL)
  494: 		window_copy_search_marks(wp, NULL);
  495: 	data->searchx = data->cx;
  496: 	data->searchy = data->cy;
  497: 	data->searcho = data->oy;
  498: 
  499: 	window_copy_redraw_screen(wp);
  500: }
  501: 
  502: static const char *
  503: window_copy_key_table(struct window_pane *wp)
  504: {
  505: 	if (options_get_number(wp->window->options, "mode-keys") == MODEKEY_VI)
  506: 		return ("copy-mode-vi");
  507: 	return ("copy-mode");
  508: }
  509: 
  510: static void
  511: window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
  512:     struct args *args, struct mouse_event *m)
  513: {
  514: 	struct window_copy_mode_data	*data = wp->modedata;
  515: 	struct screen			*sn = &data->screen;
  516: 	const char			*command, *argument, *ws;
  517: 	u_int				 np = wp->modeprefix;
  518: 	int				 cancel = 0, redraw = 0;
  519: 	char				 prefix;
  520: 
  521: 	if (args->argc == 0)
  522: 		return;
  523: 	command = args->argv[0];
  524: 
  525: 	if (m != NULL && m->valid)
  526: 		window_copy_move_mouse(m);
  527: 
  528: 	if (args->argc == 1) {
  529: 		if (strcmp(command, "append-selection") == 0) {
  530: 			if (s != NULL)
  531: 				window_copy_append_selection(wp, NULL);
  532: 			window_copy_clear_selection(wp);
  533: 			redraw = 1;
  534: 		}
  535: 		if (strcmp(command, "append-selection-and-cancel") == 0) {
  536: 			if (s != NULL)
  537: 				window_copy_append_selection(wp, NULL);
  538: 			window_copy_clear_selection(wp);
  539: 			redraw = 1;
  540: 			cancel = 1;
  541: 		}
  542: 		if (strcmp(command, "back-to-indentation") == 0)
  543: 			window_copy_cursor_back_to_indentation(wp);
  544: 		if (strcmp(command, "begin-selection") == 0) {
  545: 			if (m != NULL)
  546: 				window_copy_start_drag(c, m);
  547: 			else {
  548: 				sn->sel.lineflag = LINE_SEL_NONE;
  549: 				window_copy_start_selection(wp);
  550: 				redraw = 1;
  551: 			}
  552: 		}
  553: 		if (strcmp(command, "stop-selection") == 0)
  554: 			data->cursordrag = CURSORDRAG_NONE;
  555: 		if (strcmp(command, "bottom-line") == 0) {
  556: 			data->cx = 0;
  557: 			data->cy = screen_size_y(sn) - 1;
  558: 			window_copy_update_selection(wp, 1);
  559: 			redraw = 1;
  560: 		}
  561: 		if (strcmp(command, "cancel") == 0)
  562: 			cancel = 1;
  563: 		if (strcmp(command, "clear-selection") == 0) {
  564: 			window_copy_clear_selection(wp);
  565: 			redraw = 1;
  566: 		}
  567: 		if (strcmp(command, "copy-end-of-line") == 0) {
  568: 			window_copy_start_selection(wp);
  569: 			for (; np > 1; np--)
  570: 				window_copy_cursor_down(wp, 0);
  571: 			window_copy_cursor_end_of_line(wp);
  572: 			redraw = 1;
  573: 
  574: 			if (s != NULL) {
  575: 				window_copy_copy_selection(wp, NULL);
  576: 				cancel = 1;
  577: 			}
  578: 		}
  579: 		if (strcmp(command, "copy-line") == 0) {
  580: 			window_copy_cursor_start_of_line(wp);
  581: 			window_copy_start_selection(wp);
  582: 			for (; np > 1; np--)
  583: 				window_copy_cursor_down(wp, 0);
  584: 			window_copy_cursor_end_of_line(wp);
  585: 			redraw = 1;
  586: 
  587: 			if (s != NULL) {
  588: 				window_copy_copy_selection(wp, NULL);
  589: 				cancel = 1;
  590: 			}
  591: 		}
  592: 		if (strcmp(command, "copy-selection") == 0) {
  593: 			if (s != NULL)
  594: 				window_copy_copy_selection(wp, NULL);
  595: 			window_copy_clear_selection(wp);
  596: 			redraw = 1;
  597: 		}
  598: 		if (strcmp(command, "copy-selection-and-cancel") == 0) {
  599: 			if (s != NULL)
  600: 				window_copy_copy_selection(wp, NULL);
  601: 			window_copy_clear_selection(wp);
  602: 			redraw = 1;
  603: 			cancel = 1;
  604: 		}
  605: 		if (strcmp(command, "cursor-down") == 0) {
  606: 			for (; np != 0; np--)
  607: 				window_copy_cursor_down(wp, 0);
  608: 		}
  609: 		if (strcmp(command, "cursor-left") == 0) {
  610: 			for (; np != 0; np--)
  611: 				window_copy_cursor_left(wp);
  612: 		}
  613: 		if (strcmp(command, "cursor-right") == 0) {
  614: 			for (; np != 0; np--)
  615: 				window_copy_cursor_right(wp);
  616: 		}
  617: 		if (strcmp(command, "cursor-up") == 0) {
  618: 			for (; np != 0; np--)
  619: 				window_copy_cursor_up(wp, 0);
  620: 		}
  621: 		if (strcmp(command, "end-of-line") == 0)
  622: 			window_copy_cursor_end_of_line(wp);
  623: 		if (strcmp(command, "halfpage-down") == 0) {
  624: 			for (; np != 0; np--) {
  625: 				if (window_copy_pagedown(wp, 1)) {
  626: 					cancel = 1;
  627: 					break;
  628: 				}
  629: 			}
  630: 		}
  631: 		if (strcmp(command, "halfpage-up") == 0) {
  632: 			for (; np != 0; np--)
  633: 				window_copy_pageup(wp, 1);
  634: 		}
  635: 		if (strcmp(command, "history-bottom") == 0) {
  636: 			data->cx = 0;
  637: 			data->cy = screen_size_y(sn) - 1;
  638: 			data->oy = 0;
  639: 			window_copy_update_selection(wp, 1);
  640: 			redraw = 1;
  641: 		}
  642: 		if (strcmp(command, "history-top") == 0) {
  643: 			data->cx = 0;
  644: 			data->cy = 0;
  645: 			data->oy = screen_hsize(data->backing);
  646: 			window_copy_update_selection(wp, 1);
  647: 			redraw = 1;
  648: 		}
  649: 		if (strcmp(command, "jump-again") == 0) {
  650: 			switch (data->jumptype) {
  651: 			case WINDOW_COPY_JUMPFORWARD:
  652: 				for (; np != 0; np--)
  653: 					window_copy_cursor_jump(wp);
  654: 				break;
  655: 			case WINDOW_COPY_JUMPBACKWARD:
  656: 				for (; np != 0; np--)
  657: 					window_copy_cursor_jump_back(wp);
  658: 				break;
  659: 			case WINDOW_COPY_JUMPTOFORWARD:
  660: 				for (; np != 0; np--)
  661: 					window_copy_cursor_jump_to(wp, 1);
  662: 				break;
  663: 			case WINDOW_COPY_JUMPTOBACKWARD:
  664: 				for (; np != 0; np--)
  665: 					window_copy_cursor_jump_to_back(wp, 1);
  666: 				break;
  667: 			}
  668: 		}
  669: 		if (strcmp(command, "jump-reverse") == 0) {
  670: 			switch (data->jumptype) {
  671: 			case WINDOW_COPY_JUMPFORWARD:
  672: 				for (; np != 0; np--)
  673: 					window_copy_cursor_jump_back(wp);
  674: 				break;
  675: 			case WINDOW_COPY_JUMPBACKWARD:
  676: 				for (; np != 0; np--)
  677: 					window_copy_cursor_jump(wp);
  678: 				break;
  679: 			case WINDOW_COPY_JUMPTOFORWARD:
  680: 				for (; np != 0; np--)
  681: 					window_copy_cursor_jump_to_back(wp, 1);
  682: 				break;
  683: 			case WINDOW_COPY_JUMPTOBACKWARD:
  684: 				for (; np != 0; np--)
  685: 					window_copy_cursor_jump_to(wp, 1);
  686: 				break;
  687: 			}
  688: 		}
  689: 		if (strcmp(command, "middle-line") == 0) {
  690: 			data->cx = 0;
  691: 			data->cy = (screen_size_y(sn) - 1) / 2;
  692: 			window_copy_update_selection(wp, 1);
  693: 			redraw = 1;
  694: 		}
  695: 		if (strcmp(command, "next-paragraph") == 0) {
  696: 			for (; np != 0; np--)
  697: 				window_copy_next_paragraph(wp);
  698: 		}
  699: 		if (strcmp(command, "next-space") == 0) {
  700: 			for (; np != 0; np--)
  701: 				window_copy_cursor_next_word(wp, " ");
  702: 		}
  703: 		if (strcmp(command, "next-space-end") == 0) {
  704: 			for (; np != 0; np--)
  705: 				window_copy_cursor_next_word_end(wp, " ");
  706: 		}
  707: 		if (strcmp(command, "next-word") == 0) {
  708: 			ws = options_get_string(s->options, "word-separators");
  709: 			for (; np != 0; np--)
  710: 				window_copy_cursor_next_word(wp, ws);
  711: 		}
  712: 		if (strcmp(command, "next-word-end") == 0) {
  713: 			ws = options_get_string(s->options, "word-separators");
  714: 			for (; np != 0; np--)
  715: 				window_copy_cursor_next_word_end(wp, ws);
  716: 		}
  717: 		if (strcmp(command, "other-end") == 0) {
  718: 			if ((np % 2) != 0)
  719: 				window_copy_other_end(wp);
  720: 		}
  721: 		if (strcmp(command, "page-down") == 0) {
  722: 			for (; np != 0; np--) {
  723: 				if (window_copy_pagedown(wp, 0)) {
  724: 					cancel = 1;
  725: 					break;
  726: 				}
  727: 			}
  728: 		}
  729: 		if (strcmp(command, "page-up") == 0) {
  730: 			for (; np != 0; np--)
  731: 				window_copy_pageup(wp, 0);
  732: 		}
  733: 		if (strcmp(command, "previous-paragraph") == 0) {
  734: 			for (; np != 0; np--)
  735: 				window_copy_previous_paragraph(wp);
  736: 		}
  737: 		if (strcmp(command, "previous-space") == 0) {
  738: 			for (; np != 0; np--)
  739: 				window_copy_cursor_previous_word(wp, " ");
  740: 		}
  741: 		if (strcmp(command, "previous-word") == 0) {
  742: 			ws = options_get_string(s->options, "word-separators");
  743: 			for (; np != 0; np--)
  744: 				window_copy_cursor_previous_word(wp, ws);
  745: 		}
  746: 		if (strcmp(command, "rectangle-toggle") == 0) {
  747: 			sn->sel.lineflag = LINE_SEL_NONE;
  748: 			window_copy_rectangle_toggle(wp);
  749: 		}
  750: 		if (strcmp(command, "scroll-down") == 0) {
  751: 			for (; np != 0; np--)
  752: 				window_copy_cursor_down(wp, 1);
  753: 			if (data->scroll_exit && data->oy == 0)
  754: 				cancel = 1;
  755: 		}
  756: 		if (strcmp(command, "scroll-up") == 0) {
  757: 			for (; np != 0; np--)
  758: 				window_copy_cursor_up(wp, 1);
  759: 		}
  760: 		if (strcmp(command, "search-again") == 0) {
  761: 			if (data->searchtype == WINDOW_COPY_SEARCHUP) {
  762: 				for (; np != 0; np--)
  763: 					window_copy_search_up(wp, 1);
  764: 			} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
  765: 				for (; np != 0; np--)
  766: 					window_copy_search_down(wp, 1);
  767: 			}
  768: 		}
  769: 		if (strcmp(command, "search-reverse") == 0) {
  770: 			if (data->searchtype == WINDOW_COPY_SEARCHUP) {
  771: 				for (; np != 0; np--)
  772: 					window_copy_search_down(wp, 1);
  773: 			} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
  774: 				for (; np != 0; np--)
  775: 					window_copy_search_up(wp, 1);
  776: 			}
  777: 		}
  778: 		if (strcmp(command, "select-line") == 0) {
  779: 			sn->sel.lineflag = LINE_SEL_LEFT_RIGHT;
  780: 			data->rectflag = 0;
  781: 			window_copy_cursor_start_of_line(wp);
  782: 			window_copy_start_selection(wp);
  783: 			for (; np > 1; np--)
  784: 				window_copy_cursor_down(wp, 0);
  785: 			window_copy_cursor_end_of_line(wp);
  786: 			redraw = 1;
  787: 		}
  788: 		if (strcmp(command, "select-word") == 0) {
  789: 			sn->sel.lineflag = LINE_SEL_LEFT_RIGHT;
  790: 			data->rectflag = 0;
  791: 			ws = options_get_string(s->options, "word-separators");
  792: 			window_copy_cursor_previous_word(wp, ws);
  793: 			window_copy_start_selection(wp);
  794: 			window_copy_cursor_next_word_end(wp, ws);
  795: 			redraw = 1;
  796: 		}
  797: 		if (strcmp(command, "start-of-line") == 0)
  798: 			window_copy_cursor_start_of_line(wp);
  799: 		if (strcmp(command, "top-line") == 0) {
  800: 			data->cx = 0;
  801: 			data->cy = 0;
  802: 			window_copy_update_selection(wp, 1);
  803: 			redraw = 1;
  804: 		}
  805: 	} else if (args->argc == 2 && *args->argv[1] != '\0') {
  806: 		argument = args->argv[1];
  807: 		if (strcmp(command, "copy-pipe") == 0) {
  808: 			if (s != NULL)
  809: 				window_copy_copy_pipe(wp, s, NULL, argument);
  810: 		}
  811: 		if (strcmp(command, "copy-pipe-and-cancel") == 0) {
  812: 			if (s != NULL) {
  813: 				window_copy_copy_pipe(wp, s, NULL, argument);
  814: 				cancel = 1;
  815: 			}
  816: 		}
  817: 		if (strcmp(command, "goto-line") == 0)
  818: 			window_copy_goto_line(wp, argument);
  819: 		if (strcmp(command, "jump-backward") == 0) {
  820: 			data->jumptype = WINDOW_COPY_JUMPBACKWARD;
  821: 			data->jumpchar = *argument;
  822: 			for (; np != 0; np--)
  823: 				window_copy_cursor_jump_back(wp);
  824: 		}
  825: 		if (strcmp(command, "jump-forward") == 0) {
  826: 			data->jumptype = WINDOW_COPY_JUMPFORWARD;
  827: 			data->jumpchar = *argument;
  828: 			for (; np != 0; np--)
  829: 				window_copy_cursor_jump(wp);
  830: 		}
  831: 		if (strcmp(command, "jump-to-backward") == 0) {
  832: 			data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
  833: 			data->jumpchar = *argument;
  834: 			for (; np != 0; np--)
  835: 				window_copy_cursor_jump_to_back(wp, 1);
  836: 		}
  837: 		if (strcmp(command, "jump-to-forward") == 0) {
  838: 			data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
  839: 			data->jumpchar = *argument;
  840: 			for (; np != 0; np--)
  841: 				window_copy_cursor_jump_to(wp, 1);
  842: 		}
  843: 		if (strcmp(command, "search-backward") == 0) {
  844: 			data->searchtype = WINDOW_COPY_SEARCHUP;
  845: 			free(data->searchstr);
  846: 			data->searchstr = xstrdup(argument);
  847: 			for (; np != 0; np--)
  848: 				window_copy_search_up(wp, 1);
  849: 		}
  850: 		if (strcmp(command, "search-forward") == 0) {
  851: 			data->searchtype = WINDOW_COPY_SEARCHDOWN;
  852: 			free(data->searchstr);
  853: 			data->searchstr = xstrdup(argument);
  854: 			for (; np != 0; np--)
  855: 				window_copy_search_down(wp, 1);
  856: 		}
  857: 		if (strcmp(command, "search-backward-incremental") == 0) {
  858: 			prefix = *argument++;
  859: 			if (data->searchx == -1 || data->searchy == -1) {
  860: 				data->searchx = data->cx;
  861: 				data->searchy = data->cy;
  862: 				data->searcho = data->oy;
  863: 			} else if (data->searchstr != NULL &&
  864: 			    strcmp(argument, data->searchstr) != 0) {
  865: 				data->cx = data->searchx;
  866: 				data->cy = data->searchy;
  867: 				data->oy = data->searcho;
  868: 				redraw = 1;
  869: 			}
  870: 			if (*argument == '\0') {
  871: 				window_copy_clear_marks(wp);
  872: 				redraw = 1;
  873: 			} else if (prefix == '=' || prefix == '-') {
  874: 				data->searchtype = WINDOW_COPY_SEARCHUP;
  875: 				free(data->searchstr);
  876: 				data->searchstr = xstrdup(argument);
  877: 				if (!window_copy_search_up(wp, 1)) {
  878: 					window_copy_clear_marks(wp);
  879: 					redraw = 1;
  880: 				}
  881: 			} else if (prefix == '+') {
  882: 				data->searchtype = WINDOW_COPY_SEARCHDOWN;
  883: 				free(data->searchstr);
  884: 				data->searchstr = xstrdup(argument);
  885: 				if (!window_copy_search_down(wp, 1)) {
  886: 					window_copy_clear_marks(wp);
  887: 					redraw = 1;
  888: 				}
  889: 			}
  890: 		}
  891: 		if (strcmp(command, "search-forward-incremental") == 0) {
  892: 			prefix = *argument++;
  893: 			if (data->searchx == -1 || data->searchy == -1) {
  894: 				data->searchx = data->cx;
  895: 				data->searchy = data->cy;
  896: 				data->searcho = data->oy;
  897: 			} else if (data->searchstr != NULL &&
  898: 			    strcmp(argument, data->searchstr) != 0) {
  899: 				data->cx = data->searchx;
  900: 				data->cy = data->searchy;
  901: 				data->oy = data->searcho;
  902: 				redraw = 1;
  903: 			}
  904: 			if (*argument == '\0') {
  905: 				window_copy_clear_marks(wp);
  906: 				redraw = 1;
  907: 			} else if (prefix == '=' || prefix == '+') {
  908: 				data->searchtype = WINDOW_COPY_SEARCHDOWN;
  909: 				free(data->searchstr);
  910: 				data->searchstr = xstrdup(argument);
  911: 				if (!window_copy_search_down(wp, 1)) {
  912: 					window_copy_clear_marks(wp);
  913: 					redraw = 1;
  914: 				}
  915: 			} else if (prefix == '-') {
  916: 				data->searchtype = WINDOW_COPY_SEARCHUP;
  917: 				free(data->searchstr);
  918: 				data->searchstr = xstrdup(argument);
  919: 				if (!window_copy_search_up(wp, 1)) {
  920: 					window_copy_clear_marks(wp);
  921: 					redraw = 1;
  922: 				}
  923: 			}
  924: 		}
  925: 	}
  926: 
  927: 	if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
  928: 		window_copy_clear_marks(wp);
  929: 		redraw = 1;
  930: 		data->searchx = data->searchy = -1;
  931: 	}
  932: 
  933: 	if (cancel)
  934: 		window_pane_reset_mode(wp);
  935: 	else if (redraw)
  936: 		window_copy_redraw_screen(wp);
  937: 	wp->modeprefix = 1;
  938: }
  939: 
  940: static void
  941: window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
  942: {
  943: 	struct window_copy_mode_data	*data = wp->modedata;
  944: 	struct grid			*gd = data->backing->grid;
  945: 	u_int				 offset, gap;
  946: 
  947: 	data->cx = px;
  948: 
  949: 	gap = gd->sy / 4;
  950: 	if (py < gd->sy) {
  951: 		offset = 0;
  952: 		data->cy = py;
  953: 	} else if (py > gd->hsize + gd->sy - gap) {
  954: 		offset = gd->hsize;
  955: 		data->cy = py - gd->hsize;
  956: 	} else {
  957: 		offset = py + gap - gd->sy;
  958: 		data->cy = py - offset;
  959: 	}
  960: 	data->oy = gd->hsize - offset;
  961: 
  962: 	window_copy_update_selection(wp, 1);
  963: 	window_copy_redraw_screen(wp);
  964: }
  965: 
  966: static int
  967: window_copy_search_compare(struct grid *gd, u_int px, u_int py,
  968:     struct grid *sgd, u_int spx, int cis)
  969: {
  970: 	struct grid_cell	 gc, sgc;
  971: 	const struct utf8_data	*ud, *sud;
  972: 
  973: 	grid_get_cell(gd, px, py, &gc);
  974: 	ud = &gc.data;
  975: 	grid_get_cell(sgd, spx, 0, &sgc);
  976: 	sud = &sgc.data;
  977: 
  978: 	if (ud->size != sud->size || ud->width != sud->width)
  979: 		return (0);
  980: 
  981: 	if (cis && ud->size == 1)
  982: 		return (tolower(ud->data[0]) == sud->data[0]);
  983: 
  984: 	return (memcmp(ud->data, sud->data, ud->size) == 0);
  985: }
  986: 
  987: static int
  988: window_copy_search_lr(struct grid *gd,
  989:     struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
  990: {
  991: 	u_int	ax, bx, px;
  992: 	int	matched;
  993: 
  994: 	for (ax = first; ax < last; ax++) {
  995: 		if (ax + sgd->sx >= gd->sx)
  996: 			break;
  997: 		for (bx = 0; bx < sgd->sx; bx++) {
  998: 			px = ax + bx;
  999: 			matched = window_copy_search_compare(gd, px, py, sgd,
 1000: 			    bx, cis);
 1001: 			if (!matched)
 1002: 				break;
 1003: 		}
 1004: 		if (bx == sgd->sx) {
 1005: 			*ppx = ax;
 1006: 			return (1);
 1007: 		}
 1008: 	}
 1009: 	return (0);
 1010: }
 1011: 
 1012: static int
 1013: window_copy_search_rl(struct grid *gd,
 1014:     struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
 1015: {
 1016: 	u_int	ax, bx, px;
 1017: 	int	matched;
 1018: 
 1019: 	for (ax = last + 1; ax > first; ax--) {
 1020: 		if (gd->sx - (ax - 1) < sgd->sx)
 1021: 			continue;
 1022: 		for (bx = 0; bx < sgd->sx; bx++) {
 1023: 			px = ax - 1 + bx;
 1024: 			matched = window_copy_search_compare(gd, px, py, sgd,
 1025: 			    bx, cis);
 1026: 			if (!matched)
 1027: 				break;
 1028: 		}
 1029: 		if (bx == sgd->sx) {
 1030: 			*ppx = ax - 1;
 1031: 			return (1);
 1032: 		}
 1033: 	}
 1034: 	return (0);
 1035: }
 1036: 
 1037: static void
 1038: window_copy_move_left(struct screen *s, u_int *fx, u_int *fy)
 1039: {
 1040: 	if (*fx == 0) {	/* left */
 1041: 		if (*fy == 0) /* top */
 1042: 			return;
 1043: 		*fx = screen_size_x(s) - 1;
 1044: 		*fy = *fy - 1;
 1045: 	} else
 1046: 		*fx = *fx - 1;
 1047: }
 1048: 
 1049: static void
 1050: window_copy_move_right(struct screen *s, u_int *fx, u_int *fy)
 1051: {
 1052: 	if (*fx == screen_size_x(s) - 1) { /* right */
 1053: 		if (*fy == screen_hsize(s) + screen_size_y(s)) /* bottom */
 1054: 			return;
 1055: 		*fx = 0;
 1056: 		*fy = *fy + 1;
 1057: 	} else
 1058: 		*fx = *fx + 1;
 1059: }
 1060: 
 1061: static int
 1062: window_copy_is_lowercase(const char *ptr)
 1063: {
 1064: 	while (*ptr != '\0') {
 1065: 		if (*ptr != tolower((u_char)*ptr))
 1066: 			return (0);
 1067: 		++ptr;
 1068: 	}
 1069: 	return (1);
 1070: }
 1071: 
 1072: /*
 1073:  * Search for text stored in sgd starting from position fx,fy up to endline. If
 1074:  * found, jump to it. If cis then ignore case. The direction is 0 for searching
 1075:  * up, down otherwise. If wrap then go to begin/end of grid and try again if
 1076:  * not found.
 1077:  */
 1078: static int
 1079: window_copy_search_jump(struct window_pane *wp, struct grid *gd,
 1080:     struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
 1081:     int direction)
 1082: {
 1083: 	u_int	i, px;
 1084: 	int	found;
 1085: 
 1086: 	found = 0;
 1087: 	if (direction) {
 1088: 		for (i = fy; i <= endline; i++) {
 1089: 			found = window_copy_search_lr(gd, sgd, &px, i, fx,
 1090: 			    gd->sx, cis);
 1091: 			if (found)
 1092: 				break;
 1093: 			fx = 0;
 1094: 		}
 1095: 	} else {
 1096: 		for (i = fy + 1; endline < i; i--) {
 1097: 			found = window_copy_search_rl(gd, sgd, &px, i - 1, 0,
 1098: 			    fx, cis);
 1099: 			if (found) {
 1100: 				i--;
 1101: 				break;
 1102: 			}
 1103: 			fx = gd->sx;
 1104: 		}
 1105: 	}
 1106: 
 1107: 	if (found) {
 1108: 		window_copy_scroll_to(wp, px, i);
 1109: 		return (1);
 1110: 	}
 1111: 	if (wrap) {
 1112: 		return (window_copy_search_jump(wp, gd, sgd,
 1113: 		    direction ? 0 : gd->sx - 1,
 1114: 		    direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
 1115: 		    direction));
 1116: 	}
 1117: 	return (0);
 1118: }
 1119: 
 1120: /*
 1121:  * Search in for text searchstr. If direction is 0 then search up, otherwise
 1122:  * down. If moveflag is 0 then look for string at the current cursor position
 1123:  * as well.
 1124:  */
 1125: static int
 1126: window_copy_search(struct window_pane *wp, int direction, int moveflag)
 1127: {
 1128: 	struct window_copy_mode_data	*data = wp->modedata;
 1129: 	struct screen			*s = data->backing, ss;
 1130: 	struct screen_write_ctx		 ctx;
 1131: 	struct grid			*gd = s->grid;
 1132: 	u_int				 fx, fy, endline;
 1133: 	int				 wrapflag, cis, found;
 1134: 
 1135: 	fx = data->cx;
 1136: 	fy = screen_hsize(data->backing) - data->oy + data->cy;
 1137: 
 1138: 	screen_init(&ss, screen_write_strlen("%s", data->searchstr), 1, 0);
 1139: 	screen_write_start(&ctx, NULL, &ss);
 1140: 	screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", data->searchstr);
 1141: 	screen_write_stop(&ctx);
 1142: 
 1143: 	if (moveflag) {
 1144: 		if (direction)
 1145: 			window_copy_move_right(s, &fx, &fy);
 1146: 		else
 1147: 			window_copy_move_left(s, &fx, &fy);
 1148: 	}
 1149: 	window_copy_clear_selection(wp);
 1150: 
 1151: 	wrapflag = options_get_number(wp->window->options, "wrap-search");
 1152: 	cis = window_copy_is_lowercase(data->searchstr);
 1153: 
 1154: 	if (direction)
 1155: 		endline = gd->hsize + gd->sy - 1;
 1156: 	else
 1157: 		endline = 0;
 1158: 	found = window_copy_search_jump(wp, gd, ss.grid, fx, fy, endline, cis,
 1159: 	    wrapflag, direction);
 1160: 
 1161: 	if (window_copy_search_marks(wp, &ss))
 1162: 		window_copy_redraw_screen(wp);
 1163: 
 1164: 	screen_free(&ss);
 1165: 	return (found);
 1166: }
 1167: 
 1168: static int
 1169: window_copy_search_marks(struct window_pane *wp, struct screen *ssp)
 1170: {
 1171: 	struct window_copy_mode_data	*data = wp->modedata;
 1172: 	struct screen			*s = data->backing, ss;
 1173: 	struct screen_write_ctx		 ctx;
 1174: 	struct grid			*gd = s->grid;
 1175: 	int				 found, cis, which = -1;
 1176: 	u_int				 px, py, b, nfound = 0, width;
 1177: 
 1178: 	if (ssp == NULL) {
 1179: 		width = screen_write_strlen("%s", data->searchstr);
 1180: 		screen_init(&ss, width, 1, 0);
 1181: 		screen_write_start(&ctx, NULL, &ss);
 1182: 		screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
 1183: 		    data->searchstr);
 1184: 		screen_write_stop(&ctx);
 1185: 		ssp = &ss;
 1186: 	} else
 1187: 		width = screen_size_x(ssp);
 1188: 
 1189: 	cis = window_copy_is_lowercase(data->searchstr);
 1190: 
 1191: 	free(data->searchmark);
 1192: 	data->searchmark = bit_alloc((gd->hsize + gd->sy) * gd->sx);
 1193: 
 1194: 	for (py = 0; py < gd->hsize + gd->sy; py++) {
 1195: 		px = 0;
 1196: 		for (;;) {
 1197: 			found = window_copy_search_lr(gd, ssp->grid, &px, py,
 1198: 			    px, gd->sx, cis);
 1199: 			if (!found)
 1200: 				break;
 1201: 
 1202: 			nfound++;
 1203: 			if (px == data->cx && py == gd->hsize + data->cy - data->oy)
 1204: 				which = nfound;
 1205: 
 1206: 			b = (py * gd->sx) + px;
 1207: 			bit_nset(data->searchmark, b, b + width - 1);
 1208: 
 1209: 			px++;
 1210: 		}
 1211: 	}
 1212: 
 1213: 	if (which != -1)
 1214: 		data->searchthis = 1 + nfound - which;
 1215: 	else
 1216: 		data->searchthis = -1;
 1217: 	data->searchcount = nfound;
 1218: 
 1219: 	if (ssp == &ss)
 1220: 		screen_free(&ss);
 1221: 	return (nfound);
 1222: }
 1223: 
 1224: static void
 1225: window_copy_clear_marks(struct window_pane *wp)
 1226: {
 1227: 	struct window_copy_mode_data	*data = wp->modedata;
 1228: 
 1229: 	free(data->searchmark);
 1230: 	data->searchmark = NULL;
 1231: }
 1232: 
 1233: static int
 1234: window_copy_search_up(struct window_pane *wp, int moveflag)
 1235: {
 1236: 	return (window_copy_search(wp, 0, moveflag));
 1237: }
 1238: 
 1239: static int
 1240: window_copy_search_down(struct window_pane *wp, int moveflag)
 1241: {
 1242: 	return (window_copy_search(wp, 1, moveflag));
 1243: }
 1244: 
 1245: static void
 1246: window_copy_goto_line(struct window_pane *wp, const char *linestr)
 1247: {
 1248: 	struct window_copy_mode_data	*data = wp->modedata;
 1249: 	const char			*errstr;
 1250: 	u_int				 lineno;
 1251: 
 1252: 	lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
 1253: 	if (errstr != NULL)
 1254: 		return;
 1255: 
 1256: 	data->oy = lineno;
 1257: 	window_copy_update_selection(wp, 1);
 1258: 	window_copy_redraw_screen(wp);
 1259: }
 1260: 
 1261: static void
 1262: window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx,
 1263:     u_int py)
 1264: {
 1265: 	struct window_copy_mode_data	*data = wp->modedata;
 1266: 	struct screen			*s = &data->screen;
 1267: 	struct options			*oo = wp->window->options;
 1268: 	struct grid_cell		 gc;
 1269: 	char				 hdr[512];
 1270: 	size_t				 size = 0;
 1271: 
 1272: 	style_apply(&gc, oo, "mode-style");
 1273: 	gc.flags |= GRID_FLAG_NOPALETTE;
 1274: 
 1275: 	if (py == 0) {
 1276: 		if (data->searchmark == NULL) {
 1277: 			size = xsnprintf(hdr, sizeof hdr,
 1278: 			    "[%u/%u]", data->oy, screen_hsize(data->backing));
 1279: 		} else {
 1280: 			if (data->searchthis == -1) {
 1281: 				size = xsnprintf(hdr, sizeof hdr,
 1282: 				    "(%u results) [%d/%u]", data->searchcount,
 1283: 				    data->oy, screen_hsize(data->backing));
 1284: 			} else {
 1285: 				size = xsnprintf(hdr, sizeof hdr,
 1286: 				    "(%u/%u results) [%d/%u]", data->searchthis,
 1287: 				    data->searchcount, data->oy,
 1288: 				    screen_hsize(data->backing));
 1289: 			}
 1290: 		}
 1291: 		if (size > screen_size_x(s))
 1292: 			size = screen_size_x(s);
 1293: 		screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
 1294: 		screen_write_puts(ctx, &gc, "%s", hdr);
 1295: 	} else
 1296: 		size = 0;
 1297: 
 1298: 	if (size < screen_size_x(s)) {
 1299: 		screen_write_cursormove(ctx, 0, py);
 1300: 		screen_write_copy(ctx, data->backing, 0,
 1301: 		    (screen_hsize(data->backing) - data->oy) + py,
 1302: 		    screen_size_x(s) - size, 1, data->searchmark, &gc);
 1303: 	}
 1304: 
 1305: 	if (py == data->cy && data->cx == screen_size_x(s)) {
 1306: 		memcpy(&gc, &grid_default_cell, sizeof gc);
 1307: 		screen_write_cursormove(ctx, screen_size_x(s) - 1, py);
 1308: 		screen_write_putc(ctx, &gc, '$');
 1309: 	}
 1310: }
 1311: 
 1312: static void
 1313: window_copy_write_lines(struct window_pane *wp, struct screen_write_ctx *ctx,
 1314:     u_int py, u_int ny)
 1315: {
 1316: 	u_int	yy;
 1317: 
 1318: 	for (yy = py; yy < py + ny; yy++)
 1319: 		window_copy_write_line(wp, ctx, py);
 1320: }
 1321: 
 1322: static void
 1323: window_copy_redraw_selection(struct window_pane *wp, u_int old_y)
 1324: {
 1325: 	struct window_copy_mode_data	*data = wp->modedata;
 1326: 	u_int				 new_y, start, end;
 1327: 
 1328: 	new_y = data->cy;
 1329: 	if (old_y <= new_y) {
 1330: 		start = old_y;
 1331: 		end = new_y;
 1332: 	} else {
 1333: 		start = new_y;
 1334: 		end = old_y;
 1335: 	}
 1336: 	window_copy_redraw_lines(wp, start, end - start + 1);
 1337: }
 1338: 
 1339: static void
 1340: window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny)
 1341: {
 1342: 	struct window_copy_mode_data	*data = wp->modedata;
 1343: 	struct screen_write_ctx	 	 ctx;
 1344: 	u_int				 i;
 1345: 
 1346: 	screen_write_start(&ctx, wp, NULL);
 1347: 	for (i = py; i < py + ny; i++)
 1348: 		window_copy_write_line(wp, &ctx, i);
 1349: 	screen_write_cursormove(&ctx, data->cx, data->cy);
 1350: 	screen_write_stop(&ctx);
 1351: }
 1352: 
 1353: static void
 1354: window_copy_redraw_screen(struct window_pane *wp)
 1355: {
 1356: 	struct window_copy_mode_data	*data = wp->modedata;
 1357: 
 1358: 	window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen));
 1359: }
 1360: 
 1361: static void
 1362: window_copy_synchronize_cursor(struct window_pane *wp)
 1363: {
 1364: 	struct window_copy_mode_data	*data = wp->modedata;
 1365: 	u_int				 xx, yy;
 1366: 
 1367: 	xx = data->cx;
 1368: 	yy = screen_hsize(data->backing) + data->cy - data->oy;
 1369: 
 1370: 	switch (data->cursordrag) {
 1371: 	case CURSORDRAG_ENDSEL:
 1372: 		data->endselx = xx;
 1373: 		data->endsely = yy;
 1374: 		break;
 1375: 	case CURSORDRAG_SEL:
 1376: 		data->selx = xx;
 1377: 		data->sely = yy;
 1378: 		break;
 1379: 	case CURSORDRAG_NONE:
 1380: 		break;
 1381: 	}
 1382: }
 1383: 
 1384: static void
 1385: window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy)
 1386: {
 1387: 	struct window_copy_mode_data	*data = wp->modedata;
 1388: 	struct screen			*s = &data->screen;
 1389: 	struct screen_write_ctx		 ctx;
 1390: 	u_int				 old_cx, old_cy;
 1391: 
 1392: 	old_cx = data->cx; old_cy = data->cy;
 1393: 	data->cx = cx; data->cy = cy;
 1394: 	if (old_cx == screen_size_x(s))
 1395: 		window_copy_redraw_lines(wp, old_cy, 1);
 1396: 	if (data->cx == screen_size_x(s))
 1397: 		window_copy_redraw_lines(wp, data->cy, 1);
 1398: 	else {
 1399: 		screen_write_start(&ctx, wp, NULL);
 1400: 		screen_write_cursormove(&ctx, data->cx, data->cy);
 1401: 		screen_write_stop(&ctx);
 1402: 	}
 1403: }
 1404: 
 1405: static void
 1406: window_copy_start_selection(struct window_pane *wp)
 1407: {
 1408: 	struct window_copy_mode_data	*data = wp->modedata;
 1409: 	struct screen			*s = &data->screen;
 1410: 
 1411: 	data->selx = data->cx;
 1412: 	data->sely = screen_hsize(data->backing) + data->cy - data->oy;
 1413: 
 1414: 	data->endselx = data->selx;
 1415: 	data->endsely = data->sely;
 1416: 
 1417: 	data->cursordrag = CURSORDRAG_ENDSEL;
 1418: 
 1419: 	s->sel.flag = 1;
 1420: 	window_copy_update_selection(wp, 1);
 1421: }
 1422: 
 1423: static int
 1424: window_copy_adjust_selection(struct window_pane *wp, u_int *selx, u_int *sely)
 1425: {
 1426: 	struct window_copy_mode_data	*data = wp->modedata;
 1427: 	struct screen			*s = &data->screen;
 1428: 	u_int 				 sx, sy, ty;
 1429: 	int				 relpos;
 1430: 
 1431: 	sx = *selx;
 1432: 	sy = *sely;
 1433: 
 1434: 	ty = screen_hsize(data->backing) - data->oy;
 1435: 	if (sy < ty) {
 1436: 		relpos = WINDOW_COPY_REL_POS_ABOVE;
 1437: 		if (!data->rectflag)
 1438: 			sx = 0;
 1439: 		sy = 0;
 1440: 	} else if (sy > ty + screen_size_y(s) - 1) {
 1441: 		relpos = WINDOW_COPY_REL_POS_BELOW;
 1442: 		if (!data->rectflag)
 1443: 			sx = screen_size_x(s) - 1;
 1444: 		sy = screen_size_y(s) - 1;
 1445: 	} else {
 1446: 		relpos = WINDOW_COPY_REL_POS_ON_SCREEN;
 1447: 		sy -= ty;
 1448: 	}
 1449: 
 1450: 	*selx = sx;
 1451: 	*sely = screen_hsize(s) + sy;
 1452: 	return (relpos);
 1453: }
 1454: 
 1455: static int
 1456: window_copy_update_selection(struct window_pane *wp, int may_redraw)
 1457: {
 1458: 	struct window_copy_mode_data	*data = wp->modedata;
 1459: 	struct screen			*s = &data->screen;
 1460: 	struct options			*oo = wp->window->options;
 1461: 	struct grid_cell		 gc;
 1462: 	u_int				 sx, sy, cy, endsx, endsy;
 1463: 	int				 startrelpos, endrelpos;
 1464: 
 1465: 	if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
 1466: 		return (0);
 1467: 
 1468: 	window_copy_synchronize_cursor(wp);
 1469: 
 1470: 	/* Adjust the selection. */
 1471: 	sx = data->selx;
 1472: 	sy = data->sely;
 1473: 	startrelpos = window_copy_adjust_selection(wp, &sx, &sy);
 1474: 
 1475: 	/* Adjust the end of selection. */
 1476: 	endsx = data->endselx;
 1477: 	endsy = data->endsely;
 1478: 	endrelpos = window_copy_adjust_selection(wp, &endsx, &endsy);
 1479: 
 1480: 	/* Selection is outside of the current screen */
 1481: 	if (startrelpos == endrelpos &&
 1482: 	    startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) {
 1483: 		screen_hide_selection(s);
 1484: 		return (0);
 1485: 	}
 1486: 
 1487: 	/* Set colours and selection. */
 1488: 	style_apply(&gc, oo, "mode-style");
 1489: 	gc.flags |= GRID_FLAG_NOPALETTE;
 1490: 	screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag, &gc);
 1491: 
 1492: 	if (data->rectflag && may_redraw) {
 1493: 		/*
 1494: 		 * Can't rely on the caller to redraw the right lines for
 1495: 		 * rectangle selection - find the highest line and the number
 1496: 		 * of lines, and redraw just past that in both directions
 1497: 		 */
 1498: 		cy = data->cy;
 1499: 		if (sy < cy)
 1500: 			window_copy_redraw_lines(wp, sy, cy - sy + 1);
 1501: 		else
 1502: 			window_copy_redraw_lines(wp, cy, sy - cy + 1);
 1503: 	}
 1504: 
 1505: 	return (1);
 1506: }
 1507: 
 1508: static void *
 1509: window_copy_get_selection(struct window_pane *wp, size_t *len)
 1510: {
 1511: 	struct window_copy_mode_data	*data = wp->modedata;
 1512: 	struct screen			*s = &data->screen;
 1513: 	char				*buf;
 1514: 	size_t				 off;
 1515: 	u_int				 i, xx, yy, sx, sy, ex, ey, ey_last;
 1516: 	u_int				 firstsx, lastex, restex, restsx;
 1517: 	int				 keys;
 1518: 
 1519: 	if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
 1520: 		return (NULL);
 1521: 
 1522: 	buf = xmalloc(1);
 1523: 	off = 0;
 1524: 
 1525: 	*buf = '\0';
 1526: 
 1527: 	/*
 1528: 	 * The selection extends from selx,sely to (adjusted) cx,cy on
 1529: 	 * the base screen.
 1530: 	 */
 1531: 
 1532: 	/* Find start and end. */
 1533: 	xx = data->endselx;
 1534: 	yy = data->endsely;
 1535: 	if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
 1536: 		sx = xx; sy = yy;
 1537: 		ex = data->selx; ey = data->sely;
 1538: 	} else {
 1539: 		sx = data->selx; sy = data->sely;
 1540: 		ex = xx; ey = yy;
 1541: 	}
 1542: 
 1543: 	/* Trim ex to end of line. */
 1544: 	ey_last = window_copy_find_length(wp, ey);
 1545: 	if (ex > ey_last)
 1546: 		ex = ey_last;
 1547: 
 1548: 	/*
 1549: 	 * Deal with rectangle-copy if necessary; four situations: start of
 1550: 	 * first line (firstsx), end of last line (lastex), start (restsx) and
 1551: 	 * end (restex) of all other lines.
 1552: 	 */
 1553: 	xx = screen_size_x(s);
 1554: 
 1555: 	/*
 1556: 	 * Behave according to mode-keys. If it is emacs, copy like emacs,
 1557: 	 * keeping the top-left-most character, and dropping the
 1558: 	 * bottom-right-most, regardless of copy direction. If it is vi, also
 1559: 	 * keep bottom-right-most character.
 1560: 	 */
 1561: 	keys = options_get_number(wp->window->options, "mode-keys");
 1562: 	if (data->rectflag) {
 1563: 		/*
 1564: 		 * Need to ignore the column with the cursor in it, which for
 1565: 		 * rectangular copy means knowing which side the cursor is on.
 1566: 		 */
 1567: 		if (data->selx < data->cx) {
 1568: 			/* Selection start is on the left. */
 1569: 			if (keys == MODEKEY_EMACS) {
 1570: 				lastex = data->cx;
 1571: 				restex = data->cx;
 1572: 			}
 1573: 			else {
 1574: 				lastex = data->cx + 1;
 1575: 				restex = data->cx + 1;
 1576: 			}
 1577: 			firstsx = data->selx;
 1578: 			restsx = data->selx;
 1579: 		} else {
 1580: 			/* Cursor is on the left. */
 1581: 			lastex = data->selx + 1;
 1582: 			restex = data->selx + 1;
 1583: 			firstsx = data->cx;
 1584: 			restsx = data->cx;
 1585: 		}
 1586: 	} else {
 1587: 		if (keys == MODEKEY_EMACS)
 1588: 			lastex = ex;
 1589: 		else
 1590: 			lastex = ex + 1;
 1591: 		restex = xx;
 1592: 		firstsx = sx;
 1593: 		restsx = 0;
 1594: 	}
 1595: 
 1596: 	/* Copy the lines. */
 1597: 	for (i = sy; i <= ey; i++) {
 1598: 		window_copy_copy_line(wp, &buf, &off, i,
 1599: 		    (i == sy ? firstsx : restsx),
 1600: 		    (i == ey ? lastex : restex));
 1601: 	}
 1602: 
 1603: 	/* Don't bother if no data. */
 1604: 	if (off == 0) {
 1605: 		free(buf);
 1606: 		return (NULL);
 1607: 	}
 1608: 	if (keys == MODEKEY_EMACS || lastex <= ey_last)
 1609: 		off -= 1; /* remove final \n (unless at end in vi mode) */
 1610: 	*len = off;
 1611: 	return (buf);
 1612: }
 1613: 
 1614: static void
 1615: window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void *buf,
 1616:     size_t len)
 1617: {
 1618: 	struct screen_write_ctx	ctx;
 1619: 
 1620: 	if (options_get_number(global_options, "set-clipboard")) {
 1621: 		screen_write_start(&ctx, wp, NULL);
 1622: 		screen_write_setselection(&ctx, buf, len);
 1623: 		screen_write_stop(&ctx);
 1624: 	}
 1625: 
 1626: 	if (paste_set(buf, len, bufname, NULL) != 0)
 1627: 		free(buf);
 1628: }
 1629: 
 1630: static void
 1631: window_copy_copy_pipe(struct window_pane *wp, struct session *s,
 1632:     const char *bufname, const char *arg)
 1633: {
 1634: 	void		*buf;
 1635: 	size_t		 len;
 1636: 	struct job	*job;
 1637: 	char		*expanded;
 1638: 
 1639: 	buf = window_copy_get_selection(wp, &len);
 1640: 	if (buf == NULL)
 1641: 		return;
 1642: 	expanded = format_single(NULL, arg, NULL, s, NULL, wp);
 1643: 
 1644: 	job = job_run(expanded, s, NULL, NULL, NULL, NULL);
 1645: 	bufferevent_write(job->event, buf, len);
 1646: 
 1647: 	free(expanded);
 1648: 	window_copy_copy_buffer(wp, bufname, buf, len);
 1649: }
 1650: 
 1651: static void
 1652: window_copy_copy_selection(struct window_pane *wp, const char *bufname)
 1653: {
 1654: 	void	*buf;
 1655: 	size_t	 len;
 1656: 
 1657: 	buf = window_copy_get_selection(wp, &len);
 1658: 	if (buf == NULL)
 1659: 		return;
 1660: 
 1661: 	window_copy_copy_buffer(wp, bufname, buf, len);
 1662: }
 1663: 
 1664: static void
 1665: window_copy_append_selection(struct window_pane *wp, const char *bufname)
 1666: {
 1667: 	char				*buf;
 1668: 	struct paste_buffer		*pb;
 1669: 	const char			*bufdata;
 1670: 	size_t				 len, bufsize;
 1671: 	struct screen_write_ctx		 ctx;
 1672: 
 1673: 	buf = window_copy_get_selection(wp, &len);
 1674: 	if (buf == NULL)
 1675: 		return;
 1676: 
 1677: 	if (options_get_number(global_options, "set-clipboard")) {
 1678: 		screen_write_start(&ctx, wp, NULL);
 1679: 		screen_write_setselection(&ctx, buf, len);
 1680: 		screen_write_stop(&ctx);
 1681: 	}
 1682: 
 1683: 	if (bufname == NULL || *bufname == '\0')
 1684: 		pb = paste_get_top(&bufname);
 1685: 	else
 1686: 		pb = paste_get_name(bufname);
 1687: 	if (pb != NULL) {
 1688: 		bufdata = paste_buffer_data(pb, &bufsize);
 1689: 		buf = xrealloc(buf, len + bufsize);
 1690: 		memmove(buf + bufsize, buf, len);
 1691: 		memcpy(buf, bufdata, bufsize);
 1692: 		len += bufsize;
 1693: 	}
 1694: 	if (paste_set(buf, len, bufname, NULL) != 0)
 1695: 		free(buf);
 1696: }
 1697: 
 1698: static void
 1699: window_copy_copy_line(struct window_pane *wp, char **buf, size_t *off, u_int sy,
 1700:     u_int sx, u_int ex)
 1701: {
 1702: 	struct window_copy_mode_data	*data = wp->modedata;
 1703: 	struct grid			*gd = data->backing->grid;
 1704: 	struct grid_cell		 gc;
 1705: 	struct grid_line		*gl;
 1706: 	struct utf8_data		 ud;
 1707: 	u_int				 i, xx, wrapped = 0;
 1708: 	const char			*s;
 1709: 
 1710: 	if (sx > ex)
 1711: 		return;
 1712: 
 1713: 	/*
 1714: 	 * Work out if the line was wrapped at the screen edge and all of it is
 1715: 	 * on screen.
 1716: 	 */
 1717: 	gl = &gd->linedata[sy];
 1718: 	if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
 1719: 		wrapped = 1;
 1720: 
 1721: 	/* If the line was wrapped, don't strip spaces (use the full length). */
 1722: 	if (wrapped)
 1723: 		xx = gl->cellsize;
 1724: 	else
 1725: 		xx = window_copy_find_length(wp, sy);
 1726: 	if (ex > xx)
 1727: 		ex = xx;
 1728: 	if (sx > xx)
 1729: 		sx = xx;
 1730: 
 1731: 	if (sx < ex) {
 1732: 		for (i = sx; i < ex; i++) {
 1733: 			grid_get_cell(gd, i, sy, &gc);
 1734: 			if (gc.flags & GRID_FLAG_PADDING)
 1735: 				continue;
 1736: 			utf8_copy(&ud, &gc.data);
 1737: 			if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
 1738: 				s = tty_acs_get(NULL, ud.data[0]);
 1739: 				if (s != NULL && strlen(s) <= sizeof ud.data) {
 1740: 					ud.size = strlen(s);
 1741: 					memcpy(ud.data, s, ud.size);
 1742: 				}
 1743: 			}
 1744: 
 1745: 			*buf = xrealloc(*buf, (*off) + ud.size);
 1746: 			memcpy(*buf + *off, ud.data, ud.size);
 1747: 			*off += ud.size;
 1748: 		}
 1749: 	}
 1750: 
 1751: 	/* Only add a newline if the line wasn't wrapped. */
 1752: 	if (!wrapped || ex != xx) {
 1753: 		*buf = xrealloc(*buf, (*off) + 1);
 1754: 		(*buf)[(*off)++] = '\n';
 1755: 	}
 1756: }
 1757: 
 1758: static void
 1759: window_copy_clear_selection(struct window_pane *wp)
 1760: {
 1761: 	struct window_copy_mode_data   *data = wp->modedata;
 1762: 	u_int				px, py;
 1763: 
 1764: 	screen_clear_selection(&data->screen);
 1765: 
 1766: 	data->cursordrag = CURSORDRAG_NONE;
 1767: 
 1768: 	py = screen_hsize(data->backing) + data->cy - data->oy;
 1769: 	px = window_copy_find_length(wp, py);
 1770: 	if (data->cx > px)
 1771: 		window_copy_update_cursor(wp, px, data->cy);
 1772: }
 1773: 
 1774: static int
 1775: window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
 1776: {
 1777: 	struct window_copy_mode_data	*data = wp->modedata;
 1778: 	struct grid_cell		 gc;
 1779: 	const struct utf8_data		*ud;
 1780: 
 1781: 	grid_get_cell(data->backing->grid, px, py, &gc);
 1782: 
 1783: 	ud = &gc.data;
 1784: 	if (ud->size != 1 || (gc.flags & GRID_FLAG_PADDING))
 1785: 		return (0);
 1786: 	if (*ud->data == 0x00 || *ud->data == 0x7f)
 1787: 		return (0);
 1788: 	return (strchr(set, *ud->data) != NULL);
 1789: }
 1790: 
 1791: static u_int
 1792: window_copy_find_length(struct window_pane *wp, u_int py)
 1793: {
 1794: 	struct window_copy_mode_data	*data = wp->modedata;
 1795: 	struct screen			*s = data->backing;
 1796: 	struct grid_cell		 gc;
 1797: 	u_int				 px;
 1798: 
 1799: 	/*
 1800: 	 * If the pane has been resized, its grid can contain old overlong
 1801: 	 * lines. grid_peek_cell does not allow accessing cells beyond the
 1802: 	 * width of the grid, and screen_write_copy treats them as spaces, so
 1803: 	 * ignore them here too.
 1804: 	 */
 1805: 	px = s->grid->linedata[py].cellsize;
 1806: 	if (px > screen_size_x(s))
 1807: 		px = screen_size_x(s);
 1808: 	while (px > 0) {
 1809: 		grid_get_cell(s->grid, px - 1, py, &gc);
 1810: 		if (gc.data.size != 1 || *gc.data.data != ' ')
 1811: 			break;
 1812: 		px--;
 1813: 	}
 1814: 	return (px);
 1815: }
 1816: 
 1817: static void
 1818: window_copy_cursor_start_of_line(struct window_pane *wp)
 1819: {
 1820: 	struct window_copy_mode_data	*data = wp->modedata;
 1821: 	struct screen			*back_s = data->backing;
 1822: 	struct screen			*s = &data->screen;
 1823: 	struct grid			*gd = back_s->grid;
 1824: 	u_int				 py;
 1825: 
 1826: 	if (data->cx == 0 && s->sel.lineflag == LINE_SEL_NONE) {
 1827: 		py = screen_hsize(back_s) + data->cy - data->oy;
 1828: 		while (py > 0 &&
 1829: 		    gd->linedata[py-1].flags & GRID_LINE_WRAPPED) {
 1830: 			window_copy_cursor_up(wp, 0);
 1831: 			py = screen_hsize(back_s) + data->cy - data->oy;
 1832: 		}
 1833: 	}
 1834: 	window_copy_update_cursor(wp, 0, data->cy);
 1835: 	if (window_copy_update_selection(wp, 1))
 1836: 		window_copy_redraw_lines(wp, data->cy, 1);
 1837: }
 1838: 
 1839: static void
 1840: window_copy_cursor_back_to_indentation(struct window_pane *wp)
 1841: {
 1842: 	struct window_copy_mode_data	*data = wp->modedata;
 1843: 	u_int				 px, py, xx;
 1844: 	struct grid_cell		 gc;
 1845: 
 1846: 	px = 0;
 1847: 	py = screen_hsize(data->backing) + data->cy - data->oy;
 1848: 	xx = window_copy_find_length(wp, py);
 1849: 
 1850: 	while (px < xx) {
 1851: 		grid_get_cell(data->backing->grid, px, py, &gc);
 1852: 		if (gc.data.size != 1 || *gc.data.data != ' ')
 1853: 			break;
 1854: 		px++;
 1855: 	}
 1856: 
 1857: 	window_copy_update_cursor(wp, px, data->cy);
 1858: 	if (window_copy_update_selection(wp, 1))
 1859: 		window_copy_redraw_lines(wp, data->cy, 1);
 1860: }
 1861: 
 1862: static void
 1863: window_copy_cursor_end_of_line(struct window_pane *wp)
 1864: {
 1865: 	struct window_copy_mode_data	*data = wp->modedata;
 1866: 	struct screen			*back_s = data->backing;
 1867: 	struct screen			*s = &data->screen;
 1868: 	struct grid			*gd = back_s->grid;
 1869: 	u_int				 px, py;
 1870: 
 1871: 	py = screen_hsize(back_s) + data->cy - data->oy;
 1872: 	px = window_copy_find_length(wp, py);
 1873: 
 1874: 	if (data->cx == px && s->sel.lineflag == LINE_SEL_NONE) {
 1875: 		if (data->screen.sel.flag && data->rectflag)
 1876: 			px = screen_size_x(back_s);
 1877: 		if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
 1878: 			while (py < gd->sy + gd->hsize &&
 1879: 			    gd->linedata[py].flags & GRID_LINE_WRAPPED) {
 1880: 				window_copy_cursor_down(wp, 0);
 1881: 				py = screen_hsize(back_s)
 1882: 				     + data->cy - data->oy;
 1883: 			}
 1884: 			px = window_copy_find_length(wp, py);
 1885: 		}
 1886: 	}
 1887: 	window_copy_update_cursor(wp, px, data->cy);
 1888: 
 1889: 	if (window_copy_update_selection(wp, 1))
 1890: 		window_copy_redraw_lines(wp, data->cy, 1);
 1891: }
 1892: 
 1893: static void
 1894: window_copy_other_end(struct window_pane *wp)
 1895: {
 1896: 	struct window_copy_mode_data	*data = wp->modedata;
 1897: 	struct screen			*s = &data->screen;
 1898: 	u_int				 selx, sely, cy, yy, hsize;
 1899: 
 1900: 	if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
 1901: 		return;
 1902: 
 1903: 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
 1904: 		s->sel.lineflag = LINE_SEL_RIGHT_LEFT;
 1905: 	else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
 1906: 		s->sel.lineflag = LINE_SEL_LEFT_RIGHT;
 1907: 
 1908: 	switch (data->cursordrag) {
 1909: 		case CURSORDRAG_NONE:
 1910: 		case CURSORDRAG_SEL:
 1911: 			data->cursordrag = CURSORDRAG_ENDSEL;
 1912: 			break;
 1913: 		case CURSORDRAG_ENDSEL:
 1914: 			data->cursordrag = CURSORDRAG_SEL;
 1915: 			break;
 1916: 	}
 1917: 
 1918: 	selx = data->endselx;
 1919: 	sely = data->endsely;
 1920: 	if (data->cursordrag == CURSORDRAG_SEL) {
 1921: 		selx = data->selx;
 1922: 		sely = data->sely;
 1923: 	}
 1924: 
 1925: 	cy = data->cy;
 1926: 	yy = screen_hsize(data->backing) + data->cy - data->oy;
 1927: 
 1928: 	data->cx = selx;
 1929: 
 1930: 	hsize = screen_hsize(data->backing);
 1931: 	if (sely < hsize - data->oy) { /* above */
 1932: 		data->oy = hsize - sely;
 1933: 		data->cy = 0;
 1934: 	} else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */
 1935: 		data->oy = hsize - sely + screen_size_y(s) - 1;
 1936: 		data->cy = screen_size_y(s) - 1;
 1937: 	} else
 1938: 		data->cy = cy + sely - yy;
 1939: 
 1940: 	window_copy_update_selection(wp, 1);
 1941: 	window_copy_redraw_screen(wp);
 1942: }
 1943: 
 1944: static void
 1945: window_copy_cursor_left(struct window_pane *wp)
 1946: {
 1947: 	struct window_copy_mode_data	*data = wp->modedata;
 1948: 	u_int				 py, cx;
 1949: 	struct grid_cell		 gc;
 1950: 
 1951: 	py = screen_hsize(data->backing) + data->cy - data->oy;
 1952: 	cx = data->cx;
 1953: 	while (cx > 0) {
 1954: 		grid_get_cell(data->backing->grid, cx, py, &gc);
 1955: 		if (~gc.flags & GRID_FLAG_PADDING)
 1956: 			break;
 1957: 		cx--;
 1958: 	}
 1959: 	if (cx == 0 && py > 0) {
 1960: 		window_copy_cursor_up(wp, 0);
 1961: 		window_copy_cursor_end_of_line(wp);
 1962: 	} else if (cx > 0) {
 1963: 		window_copy_update_cursor(wp, cx - 1, data->cy);
 1964: 		if (window_copy_update_selection(wp, 1))
 1965: 			window_copy_redraw_lines(wp, data->cy, 1);
 1966: 	}
 1967: }
 1968: 
 1969: static void
 1970: window_copy_cursor_right(struct window_pane *wp)
 1971: {
 1972: 	struct window_copy_mode_data	*data = wp->modedata;
 1973: 	u_int				 px, py, yy, cx, cy;
 1974: 	struct grid_cell		 gc;
 1975: 
 1976: 	py = screen_hsize(data->backing) + data->cy - data->oy;
 1977: 	yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1;
 1978: 	if (data->screen.sel.flag && data->rectflag)
 1979: 		px = screen_size_x(&data->screen);
 1980: 	else
 1981: 		px = window_copy_find_length(wp, py);
 1982: 
 1983: 	if (data->cx >= px && py < yy) {
 1984: 		window_copy_cursor_start_of_line(wp);
 1985: 		window_copy_cursor_down(wp, 0);
 1986: 	} else if (data->cx < px) {
 1987: 		cx = data->cx + 1;
 1988: 		cy = screen_hsize(data->backing) + data->cy - data->oy;
 1989: 		while (cx < px) {
 1990: 			grid_get_cell(data->backing->grid, cx, cy, &gc);
 1991: 			if (~gc.flags & GRID_FLAG_PADDING)
 1992: 				break;
 1993: 			cx++;
 1994: 		}
 1995: 		window_copy_update_cursor(wp, cx, data->cy);
 1996: 		if (window_copy_update_selection(wp, 1))
 1997: 			window_copy_redraw_lines(wp, data->cy, 1);
 1998: 	}
 1999: }
 2000: 
 2001: static void
 2002: window_copy_cursor_up(struct window_pane *wp, int scroll_only)
 2003: {
 2004: 	struct window_copy_mode_data	*data = wp->modedata;
 2005: 	struct screen			*s = &data->screen;
 2006: 	u_int				 ox, oy, px, py;
 2007: 
 2008: 	oy = screen_hsize(data->backing) + data->cy - data->oy;
 2009: 	ox = window_copy_find_length(wp, oy);
 2010: 	if (data->cx != ox) {
 2011: 		data->lastcx = data->cx;
 2012: 		data->lastsx = ox;
 2013: 	}
 2014: 
 2015: 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
 2016: 		window_copy_other_end(wp);
 2017: 
 2018: 	data->cx = data->lastcx;
 2019: 	if (scroll_only || data->cy == 0) {
 2020: 		window_copy_scroll_down(wp, 1);
 2021: 		if (scroll_only) {
 2022: 			if (data->cy == screen_size_y(s) - 1)
 2023: 				window_copy_redraw_lines(wp, data->cy, 1);
 2024: 			else
 2025: 				window_copy_redraw_lines(wp, data->cy, 2);
 2026: 		}
 2027: 	} else {
 2028: 		window_copy_update_cursor(wp, data->cx, data->cy - 1);
 2029: 		if (window_copy_update_selection(wp, 1)) {
 2030: 			if (data->cy == screen_size_y(s) - 1)
 2031: 				window_copy_redraw_lines(wp, data->cy, 1);
 2032: 			else
 2033: 				window_copy_redraw_lines(wp, data->cy, 2);
 2034: 		}
 2035: 	}
 2036: 
 2037: 	if (!data->screen.sel.flag || !data->rectflag) {
 2038: 		py = screen_hsize(data->backing) + data->cy - data->oy;
 2039: 		px = window_copy_find_length(wp, py);
 2040: 		if ((data->cx >= data->lastsx && data->cx != px) ||
 2041: 		    data->cx > px)
 2042: 			window_copy_cursor_end_of_line(wp);
 2043: 	}
 2044: 
 2045: 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
 2046: 		window_copy_cursor_end_of_line(wp);
 2047: 	else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
 2048: 		window_copy_cursor_start_of_line(wp);
 2049: }
 2050: 
 2051: static void
 2052: window_copy_cursor_down(struct window_pane *wp, int scroll_only)
 2053: {
 2054: 	struct window_copy_mode_data	*data = wp->modedata;
 2055: 	struct screen			*s = &data->screen;
 2056: 	u_int				 ox, oy, px, py;
 2057: 
 2058: 	oy = screen_hsize(data->backing) + data->cy - data->oy;
 2059: 	ox = window_copy_find_length(wp, oy);
 2060: 	if (data->cx != ox) {
 2061: 		data->lastcx = data->cx;
 2062: 		data->lastsx = ox;
 2063: 	}
 2064: 
 2065: 	if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
 2066: 		window_copy_other_end(wp);
 2067: 
 2068: 	data->cx = data->lastcx;
 2069: 	if (scroll_only || data->cy == screen_size_y(s) - 1) {
 2070: 		window_copy_scroll_up(wp, 1);
 2071: 		if (scroll_only && data->cy > 0)
 2072: 			window_copy_redraw_lines(wp, data->cy - 1, 2);
 2073: 	} else {
 2074: 		window_copy_update_cursor(wp, data->cx, data->cy + 1);
 2075: 		if (window_copy_update_selection(wp, 1))
 2076: 			window_copy_redraw_lines(wp, data->cy - 1, 2);
 2077: 	}
 2078: 
 2079: 	if (!data->screen.sel.flag || !data->rectflag) {
 2080: 		py = screen_hsize(data->backing) + data->cy - data->oy;
 2081: 		px = window_copy_find_length(wp, py);
 2082: 		if ((data->cx >= data->lastsx && data->cx != px) ||
 2083: 		    data->cx > px)
 2084: 			window_copy_cursor_end_of_line(wp);
 2085: 	}
 2086: 
 2087: 	if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
 2088: 		window_copy_cursor_end_of_line(wp);
 2089: 	else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
 2090: 		window_copy_cursor_start_of_line(wp);
 2091: }
 2092: 
 2093: static void
 2094: window_copy_cursor_jump(struct window_pane *wp)
 2095: {
 2096: 	struct window_copy_mode_data	*data = wp->modedata;
 2097: 	struct screen			*back_s = data->backing;
 2098: 	struct grid_cell		 gc;
 2099: 	u_int				 px, py, xx;
 2100: 
 2101: 	px = data->cx + 1;
 2102: 	py = screen_hsize(back_s) + data->cy - data->oy;
 2103: 	xx = window_copy_find_length(wp, py);
 2104: 
 2105: 	while (px < xx) {
 2106: 		grid_get_cell(back_s->grid, px, py, &gc);
 2107: 		if (!(gc.flags & GRID_FLAG_PADDING) &&
 2108: 		    gc.data.size == 1 && *gc.data.data == data->jumpchar) {
 2109: 			window_copy_update_cursor(wp, px, data->cy);
 2110: 			if (window_copy_update_selection(wp, 1))
 2111: 				window_copy_redraw_lines(wp, data->cy, 1);
 2112: 			return;
 2113: 		}
 2114: 		px++;
 2115: 	}
 2116: }
 2117: 
 2118: static void
 2119: window_copy_cursor_jump_back(struct window_pane *wp)
 2120: {
 2121: 	struct window_copy_mode_data	*data = wp->modedata;
 2122: 	struct screen			*back_s = data->backing;
 2123: 	struct grid_cell		 gc;
 2124: 	u_int				 px, py;
 2125: 
 2126: 	px = data->cx;
 2127: 	py = screen_hsize(back_s) + data->cy - data->oy;
 2128: 
 2129: 	if (px > 0)
 2130: 		px--;
 2131: 
 2132: 	for (;;) {
 2133: 		grid_get_cell(back_s->grid, px, py, &gc);
 2134: 		if (!(gc.flags & GRID_FLAG_PADDING) &&
 2135: 		    gc.data.size == 1 && *gc.data.data == data->jumpchar) {
 2136: 			window_copy_update_cursor(wp, px, data->cy);
 2137: 			if (window_copy_update_selection(wp, 1))
 2138: 				window_copy_redraw_lines(wp, data->cy, 1);
 2139: 			return;
 2140: 		}
 2141: 		if (px == 0)
 2142: 			break;
 2143: 		px--;
 2144: 	}
 2145: }
 2146: 
 2147: static void
 2148: window_copy_cursor_jump_to(struct window_pane *wp, int jump_again)
 2149: {
 2150: 	struct window_copy_mode_data	*data = wp->modedata;
 2151: 	struct screen			*back_s = data->backing;
 2152: 	struct grid_cell		 gc;
 2153: 	u_int				 px, py, xx;
 2154: 
 2155: 	px = data->cx + 1 + jump_again;
 2156: 	py = screen_hsize(back_s) + data->cy - data->oy;
 2157: 	xx = window_copy_find_length(wp, py);
 2158: 
 2159: 	while (px < xx) {
 2160: 		grid_get_cell(back_s->grid, px, py, &gc);
 2161: 		if (!(gc.flags & GRID_FLAG_PADDING) &&
 2162: 		    gc.data.size == 1 && *gc.data.data == data->jumpchar) {
 2163: 			window_copy_update_cursor(wp, px - 1, data->cy);
 2164: 			if (window_copy_update_selection(wp, 1))
 2165: 				window_copy_redraw_lines(wp, data->cy, 1);
 2166: 			return;
 2167: 		}
 2168: 		px++;
 2169: 	}
 2170: }
 2171: 
 2172: static void
 2173: window_copy_cursor_jump_to_back(struct window_pane *wp, int jump_again)
 2174: {
 2175: 	struct window_copy_mode_data	*data = wp->modedata;
 2176: 	struct screen			*back_s = data->backing;
 2177: 	struct grid_cell		 gc;
 2178: 	u_int				 px, py;
 2179: 
 2180: 	px = data->cx;
 2181: 	py = screen_hsize(back_s) + data->cy - data->oy;
 2182: 
 2183: 	if (px > 0)
 2184: 		px--;
 2185: 
 2186: 	if (jump_again && px > 0)
 2187: 		px--;
 2188: 
 2189: 	for (;;) {
 2190: 		grid_get_cell(back_s->grid, px, py, &gc);
 2191: 		if (!(gc.flags & GRID_FLAG_PADDING) &&
 2192: 		    gc.data.size == 1 && *gc.data.data == data->jumpchar) {
 2193: 			window_copy_update_cursor(wp, px + 1, data->cy);
 2194: 			if (window_copy_update_selection(wp, 1))
 2195: 				window_copy_redraw_lines(wp, data->cy, 1);
 2196: 			return;
 2197: 		}
 2198: 		if (px == 0)
 2199: 			break;
 2200: 		px--;
 2201: 	}
 2202: }
 2203: 
 2204: static void
 2205: window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
 2206: {
 2207: 	struct window_copy_mode_data	*data = wp->modedata;
 2208: 	struct screen			*back_s = data->backing;
 2209: 	u_int				 px, py, xx, yy;
 2210: 	int				 expected = 0;
 2211: 
 2212: 	px = data->cx;
 2213: 	py = screen_hsize(back_s) + data->cy - data->oy;
 2214: 	xx = window_copy_find_length(wp, py);
 2215: 	yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
 2216: 
 2217: 	/*
 2218: 	 * First skip past any nonword characters and then any word characters.
 2219: 	 *
 2220: 	 * expected is initially set to 0 for the former and then 1 for the
 2221: 	 * latter.
 2222: 	 */
 2223: 	do {
 2224: 		while (px > xx ||
 2225: 		    window_copy_in_set(wp, px, py, separators) == expected) {
 2226: 			/* Move down if we're past the end of the line. */
 2227: 			if (px > xx) {
 2228: 				if (py == yy)
 2229: 					return;
 2230: 				window_copy_cursor_down(wp, 0);
 2231: 				px = 0;
 2232: 
 2233: 				py = screen_hsize(back_s) + data->cy - data->oy;
 2234: 				xx = window_copy_find_length(wp, py);
 2235: 			} else
 2236: 				px++;
 2237: 		}
 2238: 		expected = !expected;
 2239: 	} while (expected == 1);
 2240: 
 2241: 	window_copy_update_cursor(wp, px, data->cy);
 2242: 	if (window_copy_update_selection(wp, 1))
 2243: 		window_copy_redraw_lines(wp, data->cy, 1);
 2244: }
 2245: 
 2246: static void
 2247: window_copy_cursor_next_word_end(struct window_pane *wp,
 2248:     const char *separators)
 2249: {
 2250: 	struct window_copy_mode_data	*data = wp->modedata;
 2251: 	struct options			*oo = wp->window->options;
 2252: 	struct screen			*back_s = data->backing;
 2253: 	u_int				 px, py, xx, yy;
 2254: 	int				 keys, expected = 1;
 2255: 
 2256: 	px = data->cx;
 2257: 	py = screen_hsize(back_s) + data->cy - data->oy;
 2258: 	xx = window_copy_find_length(wp, py);
 2259: 	yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
 2260: 
 2261: 	keys = options_get_number(oo, "mode-keys");
 2262: 	if (keys == MODEKEY_VI && !window_copy_in_set(wp, px, py, separators))
 2263: 		px++;
 2264: 
 2265: 	/*
 2266: 	 * First skip past any word characters, then any nonword characters.
 2267: 	 *
 2268: 	 * expected is initially set to 1 for the former and then 0 for the
 2269: 	 * latter.
 2270: 	 */
 2271: 	do {
 2272: 		while (px > xx ||
 2273: 		    window_copy_in_set(wp, px, py, separators) == expected) {
 2274: 			/* Move down if we're past the end of the line. */
 2275: 			if (px > xx) {
 2276: 				if (py == yy)
 2277: 					return;
 2278: 				window_copy_cursor_down(wp, 0);
 2279: 				px = 0;
 2280: 
 2281: 				py = screen_hsize(back_s) + data->cy - data->oy;
 2282: 				xx = window_copy_find_length(wp, py);
 2283: 			} else
 2284: 				px++;
 2285: 		}
 2286: 		expected = !expected;
 2287: 	} while (expected == 0);
 2288: 
 2289: 	if (keys == MODEKEY_VI && px != 0)
 2290: 		px--;
 2291: 
 2292: 	window_copy_update_cursor(wp, px, data->cy);
 2293: 	if (window_copy_update_selection(wp, 1))
 2294: 		window_copy_redraw_lines(wp, data->cy, 1);
 2295: }
 2296: 
 2297: /* Move to the previous place where a word begins. */
 2298: static void
 2299: window_copy_cursor_previous_word(struct window_pane *wp,
 2300:     const char *separators)
 2301: {
 2302: 	struct window_copy_mode_data	*data = wp->modedata;
 2303: 	u_int				 px, py;
 2304: 
 2305: 	px = data->cx;
 2306: 	py = screen_hsize(data->backing) + data->cy - data->oy;
 2307: 
 2308: 	/* Move back to the previous word character. */
 2309: 	for (;;) {
 2310: 		if (px > 0) {
 2311: 			px--;
 2312: 			if (!window_copy_in_set(wp, px, py, separators))
 2313: 				break;
 2314: 		} else {
 2315: 			if (data->cy == 0 &&
 2316: 			    (screen_hsize(data->backing) == 0 ||
 2317: 			    data->oy >= screen_hsize(data->backing) - 1))
 2318: 				goto out;
 2319: 			window_copy_cursor_up(wp, 0);
 2320: 
 2321: 			py = screen_hsize(data->backing) + data->cy - data->oy;
 2322: 			px = window_copy_find_length(wp, py);
 2323: 		}
 2324: 	}
 2325: 
 2326: 	/* Move back to the beginning of this word. */
 2327: 	while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators))
 2328: 		px--;
 2329: 
 2330: out:
 2331: 	window_copy_update_cursor(wp, px, data->cy);
 2332: 	if (window_copy_update_selection(wp, 1))
 2333: 		window_copy_redraw_lines(wp, data->cy, 1);
 2334: }
 2335: 
 2336: static void
 2337: window_copy_scroll_up(struct window_pane *wp, u_int ny)
 2338: {
 2339: 	struct window_copy_mode_data	*data = wp->modedata;
 2340: 	struct screen			*s = &data->screen;
 2341: 	struct screen_write_ctx		 ctx;
 2342: 
 2343: 	if (data->oy < ny)
 2344: 		ny = data->oy;
 2345: 	if (ny == 0)
 2346: 		return;
 2347: 	data->oy -= ny;
 2348: 
 2349: 	window_copy_update_selection(wp, 0);
 2350: 
 2351: 	screen_write_start(&ctx, wp, NULL);
 2352: 	screen_write_cursormove(&ctx, 0, 0);
 2353: 	screen_write_deleteline(&ctx, ny, 8);
 2354: 	window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny);
 2355: 	window_copy_write_line(wp, &ctx, 0);
 2356: 	if (screen_size_y(s) > 1)
 2357: 		window_copy_write_line(wp, &ctx, 1);
 2358: 	if (screen_size_y(s) > 3)
 2359: 		window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
 2360: 	if (s->sel.flag && screen_size_y(s) > ny)
 2361: 		window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
 2362: 	screen_write_cursormove(&ctx, data->cx, data->cy);
 2363: 	screen_write_stop(&ctx);
 2364: }
 2365: 
 2366: static void
 2367: window_copy_scroll_down(struct window_pane *wp, u_int ny)
 2368: {
 2369: 	struct window_copy_mode_data	*data = wp->modedata;
 2370: 	struct screen			*s = &data->screen;
 2371: 	struct screen_write_ctx		 ctx;
 2372: 
 2373: 	if (ny > screen_hsize(data->backing))
 2374: 		return;
 2375: 
 2376: 	if (data->oy > screen_hsize(data->backing) - ny)
 2377: 		ny = screen_hsize(data->backing) - data->oy;
 2378: 	if (ny == 0)
 2379: 		return;
 2380: 	data->oy += ny;
 2381: 
 2382: 	window_copy_update_selection(wp, 0);
 2383: 
 2384: 	screen_write_start(&ctx, wp, NULL);
 2385: 	screen_write_cursormove(&ctx, 0, 0);
 2386: 	screen_write_insertline(&ctx, ny, 8);
 2387: 	window_copy_write_lines(wp, &ctx, 0, ny);
 2388: 	if (s->sel.flag && screen_size_y(s) > ny)
 2389: 		window_copy_write_line(wp, &ctx, ny);
 2390: 	else if (ny == 1) /* nuke position */
 2391: 		window_copy_write_line(wp, &ctx, 1);
 2392: 	screen_write_cursormove(&ctx, data->cx, data->cy);
 2393: 	screen_write_stop(&ctx);
 2394: }
 2395: 
 2396: int
 2397: window_copy_scroll_position(struct window_pane *wp)
 2398: {
 2399: 	struct window_copy_mode_data	*data = wp->modedata;
 2400: 
 2401: 	if (wp->mode != &window_copy_mode)
 2402: 		return (-1);
 2403: 	return (data->oy);
 2404: }
 2405: 
 2406: static void
 2407: window_copy_rectangle_toggle(struct window_pane *wp)
 2408: {
 2409: 	struct window_copy_mode_data	*data = wp->modedata;
 2410: 	u_int				 px, py;
 2411: 
 2412: 	data->rectflag = !data->rectflag;
 2413: 
 2414: 	py = screen_hsize(data->backing) + data->cy - data->oy;
 2415: 	px = window_copy_find_length(wp, py);
 2416: 	if (data->cx > px)
 2417: 		window_copy_update_cursor(wp, px, data->cy);
 2418: 
 2419: 	window_copy_update_selection(wp, 1);
 2420: 	window_copy_redraw_screen(wp);
 2421: }
 2422: 
 2423: static void
 2424: window_copy_move_mouse(struct mouse_event *m)
 2425: {
 2426: 	struct window_pane	*wp;
 2427: 	u_int			 x, y;
 2428: 
 2429: 	wp = cmd_mouse_pane(m, NULL, NULL);
 2430: 	if (wp == NULL || wp->mode != &window_copy_mode)
 2431: 		return;
 2432: 
 2433: 	if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
 2434: 		return;
 2435: 
 2436: 	window_copy_update_cursor(wp, x, y);
 2437: }
 2438: 
 2439: void
 2440: window_copy_start_drag(struct client *c, struct mouse_event *m)
 2441: {
 2442: 	struct window_pane	*wp;
 2443: 	u_int			 x, y;
 2444: 
 2445: 	if (c == NULL)
 2446: 		return;
 2447: 
 2448: 	wp = cmd_mouse_pane(m, NULL, NULL);
 2449: 	if (wp == NULL || wp->mode != &window_copy_mode)
 2450: 		return;
 2451: 
 2452: 	if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
 2453: 		return;
 2454: 
 2455: 	c->tty.mouse_drag_update = window_copy_drag_update;
 2456: 	c->tty.mouse_drag_release = NULL; /* will fire MouseDragEnd key */
 2457: 
 2458: 	window_copy_update_cursor(wp, x, y);
 2459: 	window_copy_start_selection(wp);
 2460: 	window_copy_redraw_screen(wp);
 2461: }
 2462: 
 2463: static void
 2464: window_copy_drag_update(__unused struct client *c, struct mouse_event *m)
 2465: {
 2466: 	struct window_pane		*wp;
 2467: 	struct window_copy_mode_data	*data;
 2468: 	u_int				 x, y, old_cy;
 2469: 
 2470: 	wp = cmd_mouse_pane(m, NULL, NULL);
 2471: 	if (wp == NULL || wp->mode != &window_copy_mode)
 2472: 		return;
 2473: 	data = wp->modedata;
 2474: 
 2475: 	if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
 2476: 		return;
 2477: 	old_cy = data->cy;
 2478: 
 2479: 	window_copy_update_cursor(wp, x, y);
 2480: 	if (window_copy_update_selection(wp, 1))
 2481: 		window_copy_redraw_selection(wp, old_cy);
 2482: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>