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