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