void
window_copy_cursor_end_of_line(struct window_pane *wp)
{
	struct window_copy_mode_data	*data = wp->modedata;
	struct screen			*base_s = &wp->base;
	struct grid			*gd = base_s->grid;
	u_int				 px, py;

	py = screen_hsize(base_s) + data->cy - data->oy;
	px = window_copy_find_length(wp, py);

	if (data->cx == px) {
		if (data->screen.sel.flag && data->rectflag)
			px = screen_size_x(&wp->base);
		if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
			while (py < gd->sy + gd->hsize &&
			    gd->linedata[py].flags & GRID_LINE_WRAPPED) {
				window_copy_cursor_down(wp, 0);
				py = screen_hsize(base_s) + data->cy - data->oy;
			}
			px = window_copy_find_length(wp, py);
		}
	}
	window_copy_update_cursor(wp, px, data->cy);

	if (window_copy_update_selection(wp))
		window_copy_redraw_lines(wp, data->cy, 1);
}
void
window_copy_cursor_down(struct window_pane *wp, int scroll_only)
{
	struct window_copy_mode_data	*data = wp->modedata;
	struct screen			*s = &data->screen;
	u_int				 ox, oy, px, py;

	oy = screen_hsize(&wp->base) + data->cy - data->oy;
	ox = window_copy_find_length(wp, oy);
	if (ox != 0) {
		data->lastcx = data->cx;
		data->lastsx = ox;
	}

	data->cx = data->lastcx;
	if (scroll_only || data->cy == screen_size_y(s) - 1) {
		window_copy_scroll_up(wp, 1);
		if (scroll_only && data->cy > 0)
			window_copy_redraw_lines(wp, data->cy - 1, 2);
	} else {
		window_copy_update_cursor(wp, data->cx, data->cy + 1);
		if (window_copy_update_selection(wp))
			window_copy_redraw_lines(wp, data->cy - 1, 2);
	}

	if (!data->screen.sel.flag || !data->rectflag) {
		py = screen_hsize(&wp->base) + data->cy - data->oy;
		px = window_copy_find_length(wp, py);
		if ((data->cx >= data->lastsx && data->cx != px) ||
		    data->cx > px)
			window_copy_cursor_end_of_line(wp);
	}
}
Exemple #3
0
void
window_copy_cursor_jump(struct window_pane *wp)
{
	struct window_copy_mode_data	*data = wp->modedata;
	struct screen			*back_s = data->backing;
	const struct grid_cell		*gc;
	uint				 px, py, xx;

	px = data->cx + 1;
	py = screen_hsize(back_s) + data->cy - data->oy;
	xx = window_copy_find_length(wp, py);

	while (px < xx) {
		gc = grid_peek_cell(back_s->grid, px, py);
		if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
		    && gc->data == data->jumpchar) {

			window_copy_update_cursor(wp, px, data->cy);
			if (window_copy_update_selection(wp))
				window_copy_redraw_lines(wp, data->cy, 1);
			return;
		}
		px++;
	}
}
Exemple #4
0
void
window_copy_copy_line(struct window_pane *wp,
    char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
{
	struct window_copy_mode_data	*data = wp->modedata;
	struct grid			*gd = data->backing->grid;
	const struct grid_cell		*gc;
	const struct grid_utf8		*gu;
	struct grid_line		*gl;
	u_int				 i, xx, wrapped = 0;
	size_t				 size;

	if (sx > ex)
		return;

	/*
	 * Work out if the line was wrapped at the screen edge and all of it is
	 * on screen.
	 */
	gl = &gd->linedata[sy];
	if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
		wrapped = 1;

	/* If the line was wrapped, don't strip spaces (use the full length). */
	if (wrapped)
		xx = gl->cellsize;
	else
		xx = window_copy_find_length(wp, sy);
	if (ex > xx)
		ex = xx;
	if (sx > xx)
		sx = xx;

	if (sx < ex) {
		for (i = sx; i < ex; i++) {
			gc = grid_peek_cell(gd, i, sy);
			if (gc->flags & GRID_FLAG_PADDING)
				continue;
			if (!(gc->flags & GRID_FLAG_UTF8)) {
				*buf = xrealloc(*buf, 1, (*off) + 1);
				(*buf)[(*off)++] = gc->data;
			} else {
				gu = grid_peek_utf8(gd, i, sy);
				size = grid_utf8_size(gu);
				*buf = xrealloc(*buf, 1, (*off) + size);
				*off += grid_utf8_copy(gu, *buf + *off, size);
			}
		}
	}

	/* Only add a newline if the line wasn't wrapped. */
	if (!wrapped || ex != xx) {
		*buf = xrealloc(*buf, 1, (*off) + 1);
		(*buf)[(*off)++] = '\n';
	}
}
void
window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
{
	struct window_copy_mode_data	*data = wp->modedata;
	struct screen			*base_s = &wp->base;
	u_int				 px, py, xx, yy;
	int				 expected = 1;

	px = data->cx;
	py = screen_hsize(base_s) + data->cy - data->oy;
	xx = window_copy_find_length(wp, py);
	yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;

	/*
	 * First skip past any word characters, then any nonword characters.
	 *
	 * expected is initially set to 1 for the former and then 0 for the
	 * latter.
	 */
	do {
		while (px > xx ||
		    window_copy_in_set(wp, px, py, separators) == expected) {
			/* Move down if we're past the end of the line. */
			if (px > xx) {
				if (py == yy)
					return;
				window_copy_cursor_down(wp, 0);
				px = 0;

				py = screen_hsize(base_s) + data->cy - data->oy;
				xx = window_copy_find_length(wp, py);
			} else
				px++;
		}
		expected = !expected;
	} while (expected == 0);

	window_copy_update_cursor(wp, px, data->cy);
	if (window_copy_update_selection(wp))
		window_copy_redraw_lines(wp, data->cy, 1);
}
void
window_copy_clear_selection(struct window_pane *wp)
{
	struct window_copy_mode_data   *data = wp->modedata;
	u_int				px, py;

	screen_clear_selection(&data->screen);

	py = screen_hsize(&wp->base) + data->cy - data->oy;
	px = window_copy_find_length(wp, py);
	if (data->cx > px)
		window_copy_update_cursor(wp, px, data->cy);
}
void
window_copy_rectangle_toggle(struct window_pane *wp)
{
	struct window_copy_mode_data	*data = wp->modedata;
	u_int				 px, py;

	data->rectflag = !data->rectflag;

	py = screen_hsize(&wp->base) + data->cy - data->oy;
	px = window_copy_find_length(wp, py);
	if (data->cx > px)
		window_copy_update_cursor(wp, px, data->cy);

	window_copy_update_selection(wp);
	window_copy_redraw_screen(wp);
}
void
window_copy_cursor_right(struct window_pane *wp)
{
	struct window_copy_mode_data	*data = wp->modedata;
	u_int				 px, py;

	if (data->screen.sel.flag && data->rectflag)
		px = screen_size_x(&data->screen);
	else {
		py = screen_hsize(&wp->base) + data->cy - data->oy;
		px = window_copy_find_length(wp, py);
	}

	if (data->cx >= px) {
		window_copy_cursor_start_of_line(wp);
		window_copy_cursor_down(wp, 0);
	} else {
		window_copy_update_cursor(wp, data->cx + 1, data->cy);
		if (window_copy_update_selection(wp))
			window_copy_redraw_lines(wp, data->cy, 1);
	}
}
/* Move to the previous place where a word begins. */
void
window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
{
	struct window_copy_mode_data	*data = wp->modedata;
	u_int				 px, py;

	px = data->cx;
	py = screen_hsize(&wp->base) + data->cy - data->oy;

	/* Move back to the previous word character. */
	for (;;) {
		if (px > 0) {
			px--;
			if (!window_copy_in_set(wp, px, py, separators))
				break;
		} else {
			if (data->cy == 0 &&
			    (screen_hsize(&wp->base) == 0 ||
			    data->oy >= screen_hsize(&wp->base) - 1))
				goto out;
			window_copy_cursor_up(wp, 0);

			py = screen_hsize(&wp->base) + data->cy - data->oy;
			px = window_copy_find_length(wp, py);
		}
	}

	/* Move back to the beginning of this word. */
	while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators))
		px--;

out:
	window_copy_update_cursor(wp, px, data->cy);
	if (window_copy_update_selection(wp))
		window_copy_redraw_lines(wp, data->cy, 1);
}
void
window_copy_cursor_back_to_indentation(struct window_pane *wp)
{
	struct window_copy_mode_data	*data = wp->modedata;
	u_int				 px, py, xx;
	const struct grid_cell		*gc;

	px = 0;
	py = screen_hsize(&wp->base) + data->cy - data->oy;
	xx = window_copy_find_length(wp, py);

	while (px < xx) {
		gc = grid_peek_cell(wp->base.grid, px, py);
		if (gc->flags & GRID_FLAG_UTF8)
			break;
		if (gc->data != ' ')
			break;
		px++;
	}

	window_copy_update_cursor(wp, px, data->cy);
	if (window_copy_update_selection(wp))
		window_copy_redraw_lines(wp, data->cy, 1);
}
void
window_copy_copy_selection(struct window_pane *wp, struct client *c)
{
	struct window_copy_mode_data	*data = wp->modedata;
	struct screen			*s = &data->screen;
	char				*buf;
	size_t				 off;
	u_int				 i, xx, yy, sx, sy, ex, ey, limit;
	u_int				 firstsx, lastex, restex, restsx;

	if (!s->sel.flag)
		return;

	buf = xmalloc(1);
	off = 0;

	*buf = '\0';

	/*
	 * The selection extends from selx,sely to (adjusted) cx,cy on
	 * the base screen.
	 */

	/* Find start and end. */
	xx = data->cx;
	yy = screen_hsize(&wp->base) + data->cy - data->oy;
	if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
		sx = xx; sy = yy;
		ex = data->selx; ey = data->sely;
	} else {
		sx = data->selx; sy = data->sely;
		ex = xx; ey = yy;
	}

	/* Trim ex to end of line. */
	xx = window_copy_find_length(wp, ey);
	if (ex > xx)
		ex = xx;

	/*
	 * Deal with rectangle-copy if necessary; four situations: start of
	 * first line (firstsx), end of last line (lastex), start (restsx) and
	 * end (restex) of all other lines.
	 */
	xx = screen_size_x(s);
	if (data->rectflag) {
		/*
		 * Need to ignore the column with the cursor in it, which for
		 * rectangular copy means knowing which side the cursor is on.
		 */
		if (data->selx < data->cx) {
			/* Selection start is on the left. */
			lastex = data->cx;
			restex = data->cx;
			firstsx = data->selx;
			restsx = data->selx;
		} else {
			/* Cursor is on the left. */
			lastex = data->selx + 1;
			restex = data->selx + 1;
			firstsx = data->cx + 1;
			restsx = data->cx + 1;
		}
	} else {
		/*
		 * Like emacs, keep the top-left-most character, and drop the
		 * bottom-right-most, regardless of copy direction.
		 */
		lastex = ex;
		restex = xx;
		firstsx = sx;
		restsx = 0;
	}

	/* Copy the lines. */
	if (sy == ey)
		window_copy_copy_line(wp, &buf, &off, sy, firstsx, lastex);
	else {
		window_copy_copy_line(wp, &buf, &off, sy, firstsx, restex);
		if (ey - sy > 1) {
			for (i = sy + 1; i < ey; i++) {
				window_copy_copy_line(
				    wp, &buf, &off, i, restsx, restex);
			}
		}
		window_copy_copy_line(wp, &buf, &off, ey, restsx, lastex);
	}

	/* Don't bother if no data. */
	if (off == 0) {
		xfree(buf);
		return;
	}
	off--;	/* remove final \n */

	/* Add the buffer to the stack. */
	limit = options_get_number(&c->session->options, "buffer-limit");
	paste_add(&c->session->buffers, buf, off, limit);
}