tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

window-copy.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <ctype.h>
22 #include <regex.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 
27 #include "tmux.h"
28 
30 
31 static const char *window_copy_key_table(struct window_mode_entry *);
32 static void window_copy_command(struct window_mode_entry *, struct client *,
33  struct session *, struct winlink *, struct args *,
34  struct mouse_event *);
35 static struct screen *window_copy_init(struct window_mode_entry *,
36  struct cmd_find_state *, struct args *);
37 static struct screen *window_copy_view_init(struct window_mode_entry *,
38  struct cmd_find_state *, struct args *);
39 static void window_copy_free(struct window_mode_entry *);
40 static void window_copy_resize(struct window_mode_entry *, u_int, u_int);
41 static void window_copy_formats(struct window_mode_entry *,
42  struct format_tree *);
43 static void window_copy_pageup1(struct window_mode_entry *, int);
44 static int window_copy_pagedown(struct window_mode_entry *, int, int);
45 static void window_copy_next_paragraph(struct window_mode_entry *);
47 static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
48 static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
49  u_int);
50 static void window_copy_redraw_screen(struct window_mode_entry *);
51 static void window_copy_write_line(struct window_mode_entry *,
52  struct screen_write_ctx *, u_int);
53 static void window_copy_write_lines(struct window_mode_entry *,
54  struct screen_write_ctx *, u_int, u_int);
56 static void window_copy_scroll_to(struct window_mode_entry *, u_int, u_int,
57  int);
58 static int window_copy_search_compare(struct grid *, u_int, u_int,
59  struct grid *, u_int, int);
60 static int window_copy_search_lr(struct grid *, struct grid *, u_int *,
61  u_int, u_int, u_int, int);
62 static int window_copy_search_rl(struct grid *, struct grid *, u_int *,
63  u_int, u_int, u_int, int);
64 static int window_copy_last_regex(struct grid *, u_int, u_int, u_int,
65  u_int, u_int *, u_int *, const char *, const regex_t *,
66  int);
68  u_int, u_int, u_int *);
69 static char *window_copy_stringify(struct grid *, u_int, u_int, u_int,
70  char *, u_int *);
71 static void window_copy_cstrtocellpos(struct grid *, u_int, u_int *,
72  u_int *, const char *);
74  struct screen *, int, int);
75 static void window_copy_clear_marks(struct window_mode_entry *);
76 static int window_copy_is_lowercase(const char *);
77 static void window_copy_search_back_overlap(struct grid *, regex_t *,
78  u_int *, u_int *, u_int *, u_int);
79 static int window_copy_search_jump(struct window_mode_entry *,
80  struct grid *, struct grid *, u_int, u_int, u_int, int, int,
81  int, int);
82 static int window_copy_search(struct window_mode_entry *, int, int);
83 static int window_copy_search_up(struct window_mode_entry *, int);
84 static int window_copy_search_down(struct window_mode_entry *, int);
85 static void window_copy_goto_line(struct window_mode_entry *, const char *);
86 static void window_copy_update_cursor(struct window_mode_entry *, u_int,
87  u_int);
90  u_int *, u_int *);
91 static int window_copy_set_selection(struct window_mode_entry *, int, int);
92 static int window_copy_update_selection(struct window_mode_entry *, int,
93  int);
94 static void window_copy_synchronize_cursor(struct window_mode_entry *, int);
95 static void *window_copy_get_selection(struct window_mode_entry *, size_t *);
96 static void window_copy_copy_buffer(struct window_mode_entry *,
97  const char *, void *, size_t);
98 static void window_copy_pipe(struct window_mode_entry *,
99  struct session *, const char *);
100 static void window_copy_copy_pipe(struct window_mode_entry *,
101  struct session *, const char *, const char *);
102 static void window_copy_copy_selection(struct window_mode_entry *,
103  const char *);
104 static void window_copy_append_selection(struct window_mode_entry *);
105 static void window_copy_clear_selection(struct window_mode_entry *);
106 static void window_copy_copy_line(struct window_mode_entry *, char **,
107  size_t *, u_int, u_int, u_int);
108 static int window_copy_in_set(struct window_mode_entry *, u_int, u_int,
109  const char *);
110 static u_int window_copy_find_length(struct window_mode_entry *, u_int);
113  struct window_mode_entry *);
115 static void window_copy_other_end(struct window_mode_entry *);
116 static void window_copy_cursor_left(struct window_mode_entry *);
117 static void window_copy_cursor_right(struct window_mode_entry *, int);
118 static void window_copy_cursor_up(struct window_mode_entry *, int);
119 static void window_copy_cursor_down(struct window_mode_entry *, int);
120 static void window_copy_cursor_jump(struct window_mode_entry *);
121 static void window_copy_cursor_jump_back(struct window_mode_entry *);
122 static void window_copy_cursor_jump_to(struct window_mode_entry *);
125  const char *);
127  const char *, u_int *, u_int *);
129  const char *, int);
131  const char *, int, u_int *, u_int *);
133  const char *, int);
134 static void window_copy_scroll_up(struct window_mode_entry *, u_int);
135 static void window_copy_scroll_down(struct window_mode_entry *, u_int);
136 static void window_copy_rectangle_set(struct window_mode_entry *, int);
137 static void window_copy_move_mouse(struct mouse_event *);
138 static void window_copy_drag_update(struct client *, struct mouse_event *);
139 static void window_copy_drag_release(struct client *, struct mouse_event *);
140 static void window_copy_jump_to_mark(struct window_mode_entry *);
142  u_int, u_int, u_int, u_int, u_int);
144  u_int, u_int, u_int, u_int, u_int, u_int, int);
145 
146 const struct window_mode window_copy_mode = {
147  .name = "copy-mode",
148 
149  .init = window_copy_init,
150  .free = window_copy_free,
151  .resize = window_copy_resize,
152  .key_table = window_copy_key_table,
153  .command = window_copy_command,
154  .formats = window_copy_formats,
155 };
156 
157 const struct window_mode window_view_mode = {
158  .name = "view-mode",
159 
160  .init = window_copy_view_init,
161  .free = window_copy_free,
162  .resize = window_copy_resize,
163  .key_table = window_copy_key_table,
164  .command = window_copy_command,
165  .formats = window_copy_formats,
166 };
167 
168 enum {
176 };
177 
178 enum {
182 };
183 
188 };
189 
194 };
195 
198  struct args *args;
199  struct mouse_event *m;
200 
201  struct client *c;
202  struct session *s;
203  struct winlink *wl;
204 };
205 
206 /*
207  * Copy mode's visible screen (the "screen" field) is filled from one of two
208  * sources: the original contents of the pane (used when we actually enter via
209  * the "copy-mode" command, to copy the contents of the current pane), or else
210  * a series of lines containing the output from an output-writing tmux command
211  * (such as any of the "show-*" or "list-*" commands).
212  *
213  * In either case, the full content of the copy-mode grid is pointed at by the
214  * "backing" field, and is copied into "screen" as needed (that is, when
215  * scrolling occurs). When copy-mode is backed by a pane, backing points
216  * directly at that pane's screen structure (&wp->base); when backed by a list
217  * of output-lines from a command, it points at a newly-allocated screen
218  * structure (which is deallocated when the mode ends).
219  */
221  struct screen screen;
222 
223  struct screen *backing;
224  int backing_written; /* backing display started */
225 
226  int viewmode; /* view mode entered */
227 
228  u_int oy; /* number of lines scrolled up */
229 
230  u_int selx; /* beginning of selection */
231  u_int sely;
232 
233  u_int endselx; /* end of selection */
234  u_int endsely;
235 
236  enum {
237  CURSORDRAG_NONE, /* selection is independent of cursor */
238  CURSORDRAG_ENDSEL, /* end is synchronized with cursor */
239  CURSORDRAG_SEL, /* start is synchronized with cursor */
241 
242  int modekeys;
243  enum {
247  } lineflag; /* line selection mode */
248  int rectflag; /* in rectangle copy mode? */
249  int scroll_exit; /* exit on scroll to end? */
250  int hide_position; /* hide position marker */
251 
252  enum {
253  SEL_CHAR, /* select one char at a time */
254  SEL_WORD, /* select one word at a time */
255  SEL_LINE, /* select one line at a time */
257 
258  const char *ws; /* word separators */
259 
260  u_int dx; /* drag start position */
261  u_int dy;
262 
263  u_int selrx; /* selection reset positions */
264  u_int selry;
265  u_int endselrx;
266  u_int endselry;
267 
268  u_int cx;
269  u_int cy;
270 
271  u_int lastcx; /* position in last line w/ content */
272  u_int lastsx; /* size of last line w/ content */
273 
274  u_int mx; /* mark position */
275  u_int my;
276  int showmark;
277 
281  char *searchstr;
282  u_char *searchmark;
286  int searchx;
287  int searchy;
288  int searcho;
289  u_char searchgen;
290 
291  int timeout; /* search has timed out */
292 #define WINDOW_COPY_SEARCH_TIMEOUT 10000
293 #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
294 
295  int jumptype;
297 
298  struct event dragtimer;
299 #define WINDOW_COPY_DRAG_REPEAT_TIME 50000
300 };
301 
302 static void
303 window_copy_scroll_timer(__unused int fd, __unused short events, void *arg)
304 {
305  struct window_mode_entry *wme = arg;
306  struct window_pane *wp = wme->wp;
307  struct window_copy_mode_data *data = wme->data;
308  struct timeval tv = {
310  };
311 
312  evtimer_del(&data->dragtimer);
313 
314  if (TAILQ_FIRST(&wp->modes) != wme)
315  return;
316 
317  if (data->cy == 0) {
318  evtimer_add(&data->dragtimer, &tv);
319  window_copy_cursor_up(wme, 1);
320  } else if (data->cy == screen_size_y(&data->screen) - 1) {
321  evtimer_add(&data->dragtimer, &tv);
322  window_copy_cursor_down(wme, 1);
323  }
324 }
325 
326 static struct screen *
327 window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
328  u_int *cy, int trim)
329 {
330  struct screen *dst;
331  const struct grid_line *gl;
332  u_int sy, wx, wy;
333  int reflow;
334 
335  dst = xcalloc(1, sizeof *dst);
336 
337  sy = screen_hsize(src) + screen_size_y(src);
338  if (trim) {
339  while (sy > screen_hsize(src)) {
340  gl = grid_peek_line(src->grid, sy - 1);
341  if (gl->cellused != 0)
342  break;
343  sy--;
344  }
345  }
346  log_debug("%s: target screen is %ux%u, source %ux%u", __func__,
347  screen_size_x(src), sy, screen_size_x(hint),
348  screen_hsize(src) + screen_size_y(src));
349  screen_init(dst, screen_size_x(src), sy, screen_hlimit(src));
350 
351  /*
352  * Ensure history is on for the backing grid so lines are not deleted
353  * during resizing.
354  */
355  dst->grid->flags |= GRID_HISTORY;
356  grid_duplicate_lines(dst->grid, 0, src->grid, 0, sy);
357 
358  dst->grid->sy = sy - screen_hsize(src);
359  dst->grid->hsize = screen_hsize(src);
360  dst->grid->hscrolled = src->grid->hscrolled;
361  if (src->cy > dst->grid->sy - 1) {
362  dst->cx = 0;
363  dst->cy = dst->grid->sy - 1;
364  } else {
365  dst->cx = src->cx;
366  dst->cy = src->cy;
367  }
368 
369  if (cx != NULL && cy != NULL) {
370  *cx = dst->cx;
371  *cy = screen_hsize(dst) + dst->cy;
372  reflow = (screen_size_x(hint) != screen_size_x(dst));
373  }
374  else
375  reflow = 0;
376  if (reflow)
377  grid_wrap_position(dst->grid, *cx, *cy, &wx, &wy);
378  screen_resize_cursor(dst, screen_size_x(hint), screen_size_y(hint), 1,
379  0, 0);
380  if (reflow)
381  grid_unwrap_position(dst->grid, cx, cy, wx, wy);
382 
383  return (dst);
384 }
385 
386 static struct window_copy_mode_data *
388 {
389  struct window_pane *wp = wme->wp;
390  struct window_copy_mode_data *data;
391  struct screen *base = &wp->base;
392 
393  wme->data = data = xcalloc(1, sizeof *data);
394 
395  data->cursordrag = CURSORDRAG_NONE;
396  data->lineflag = LINE_SEL_NONE;
397  data->selflag = SEL_CHAR;
398 
399  if (wp->searchstr != NULL) {
401  data->searchregex = wp->searchregex;
402  data->searchstr = xstrdup(wp->searchstr);
403  } else {
404  data->searchtype = WINDOW_COPY_OFF;
405  data->searchregex = 0;
406  data->searchstr = NULL;
407  }
408  data->searchx = data->searchy = data->searcho = -1;
409  data->searchall = 1;
410 
411  data->jumptype = WINDOW_COPY_OFF;
412  data->jumpchar = NULL;
413 
414  screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0);
415  data->modekeys = options_get_number(wp->window->options, "mode-keys");
416 
417  evtimer_set(&data->dragtimer, window_copy_scroll_timer, wme);
418 
419  return (data);
420 }
421 
422 static struct screen *
424  __unused struct cmd_find_state *fs, struct args *args)
425 {
426  struct window_pane *wp = wme->swp;
427  struct window_copy_mode_data *data;
428  struct screen *base = &wp->base;
429  struct screen_write_ctx ctx;
430  u_int i, cx, cy;
431 
432  data = window_copy_common_init(wme);
433  data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy,
434  wme->swp != wme->wp);
435 
436  data->cx = cx;
437  if (cy < screen_hsize(data->backing)) {
438  data->cy = 0;
439  data->oy = screen_hsize(data->backing) - cy;
440  } else {
441  data->cy = cy - screen_hsize(data->backing);
442  data->oy = 0;
443  }
444 
445  data->scroll_exit = args_has(args, 'e');
446  data->hide_position = args_has(args, 'H');
447 
448  data->screen.cx = data->cx;
449  data->screen.cy = data->cy;
450  data->mx = data->cx;
451  data->my = screen_hsize(data->backing) + data->cy - data->oy;
452  data->showmark = 0;
453 
454  screen_write_start(&ctx, &data->screen);
455  for (i = 0; i < screen_size_y(&data->screen); i++)
456  window_copy_write_line(wme, &ctx, i);
457  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
458  screen_write_stop(&ctx);
459 
460  return (&data->screen);
461 }
462 
463 static struct screen *
465  __unused struct cmd_find_state *fs, __unused struct args *args)
466 {
467  struct window_pane *wp = wme->wp;
468  struct window_copy_mode_data *data;
469  struct screen *base = &wp->base;
470  struct screen *s;
471 
472  data = window_copy_common_init(wme);
473  data->viewmode = 1;
474 
475  data->backing = s = xmalloc(sizeof *data->backing);
476  screen_init(s, screen_size_x(base), screen_size_y(base), UINT_MAX);
477  data->mx = data->cx;
478  data->my = screen_hsize(data->backing) + data->cy - data->oy;
479  data->showmark = 0;
480 
481  return (&data->screen);
482 }
483 
484 static void
486 {
487  struct window_copy_mode_data *data = wme->data;
488 
489  evtimer_del(&data->dragtimer);
490 
491  free(data->searchmark);
492  free(data->searchstr);
493  free(data->jumpchar);
494 
495  screen_free(data->backing);
496  free(data->backing);
497 
498  screen_free(&data->screen);
499  free(data);
500 }
501 
502 void
503 window_copy_add(struct window_pane *wp, const char *fmt, ...)
504 {
505  va_list ap;
506 
507  va_start(ap, fmt);
508  window_copy_vadd(wp, fmt, ap);
509  va_end(ap);
510 }
511 
512 void
513 window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
514 {
515  struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
516  struct window_copy_mode_data *data = wme->data;
517  struct screen *backing = data->backing;
518  struct screen_write_ctx back_ctx, ctx;
519  struct grid_cell gc;
520  u_int old_hsize, old_cy;
521 
522  memcpy(&gc, &grid_default_cell, sizeof gc);
523 
524  old_hsize = screen_hsize(data->backing);
525  screen_write_start(&back_ctx, backing);
526  if (data->backing_written) {
527  /*
528  * On the second or later line, do a CRLF before writing
529  * (so it's on a new line).
530  */
531  screen_write_carriagereturn(&back_ctx);
532  screen_write_linefeed(&back_ctx, 0, 8);
533  } else
534  data->backing_written = 1;
535  old_cy = backing->cy;
536  screen_write_vnputs(&back_ctx, 0, &gc, fmt, ap);
537  screen_write_stop(&back_ctx);
538 
539  data->oy += screen_hsize(data->backing) - old_hsize;
540 
541  screen_write_start_pane(&ctx, wp, &data->screen);
542 
543  /*
544  * If the history has changed, draw the top line.
545  * (If there's any history at all, it has changed.)
546  */
547  if (screen_hsize(data->backing))
548  window_copy_redraw_lines(wme, 0, 1);
549 
550  /* Write the new lines. */
551  window_copy_redraw_lines(wme, old_cy, backing->cy - old_cy + 1);
552 
553  screen_write_stop(&ctx);
554 }
555 
556 void
557 window_copy_pageup(struct window_pane *wp, int half_page)
558 {
559  window_copy_pageup1(TAILQ_FIRST(&wp->modes), half_page);
560 }
561 
562 static void
563 window_copy_pageup1(struct window_mode_entry *wme, int half_page)
564 {
565  struct window_copy_mode_data *data = wme->data;
566  struct screen *s = &data->screen;
567  u_int n, ox, oy, px, py;
568 
569  oy = screen_hsize(data->backing) + data->cy - data->oy;
570  ox = window_copy_find_length(wme, oy);
571 
572  if (data->cx != ox) {
573  data->lastcx = data->cx;
574  data->lastsx = ox;
575  }
576  data->cx = data->lastcx;
577 
578  n = 1;
579  if (screen_size_y(s) > 2) {
580  if (half_page)
581  n = screen_size_y(s) / 2;
582  else
583  n = screen_size_y(s) - 2;
584  }
585 
586  if (data->oy + n > screen_hsize(data->backing)) {
587  data->oy = screen_hsize(data->backing);
588  if (data->cy < n)
589  data->cy = 0;
590  else
591  data->cy -= n;
592  } else
593  data->oy += n;
594 
595  if (data->screen.sel == NULL || !data->rectflag) {
596  py = screen_hsize(data->backing) + data->cy - data->oy;
597  px = window_copy_find_length(wme, py);
598  if ((data->cx >= data->lastsx && data->cx != px) ||
599  data->cx > px)
601  }
602 
603  if (data->searchmark != NULL && !data->timeout)
604  window_copy_search_marks(wme, NULL, data->searchregex, 1);
605  window_copy_update_selection(wme, 1, 0);
607 }
608 
609 static int
610 window_copy_pagedown(struct window_mode_entry *wme, int half_page,
611  int scroll_exit)
612 {
613  struct window_copy_mode_data *data = wme->data;
614  struct screen *s = &data->screen;
615  u_int n, ox, oy, px, py;
616 
617  oy = screen_hsize(data->backing) + data->cy - data->oy;
618  ox = window_copy_find_length(wme, oy);
619 
620  if (data->cx != ox) {
621  data->lastcx = data->cx;
622  data->lastsx = ox;
623  }
624  data->cx = data->lastcx;
625 
626  n = 1;
627  if (screen_size_y(s) > 2) {
628  if (half_page)
629  n = screen_size_y(s) / 2;
630  else
631  n = screen_size_y(s) - 2;
632  }
633 
634  if (data->oy < n) {
635  data->oy = 0;
636  if (data->cy + (n - data->oy) >= screen_size_y(data->backing))
637  data->cy = screen_size_y(data->backing) - 1;
638  else
639  data->cy += n - data->oy;
640  } else
641  data->oy -= n;
642 
643  if (data->screen.sel == NULL || !data->rectflag) {
644  py = screen_hsize(data->backing) + data->cy - data->oy;
645  px = window_copy_find_length(wme, py);
646  if ((data->cx >= data->lastsx && data->cx != px) ||
647  data->cx > px)
649  }
650 
651  if (scroll_exit && data->oy == 0)
652  return (1);
653  if (data->searchmark != NULL && !data->timeout)
654  window_copy_search_marks(wme, NULL, data->searchregex, 1);
655  window_copy_update_selection(wme, 1, 0);
657  return (0);
658 }
659 
660 static void
662 {
663  struct window_copy_mode_data *data = wme->data;
664  u_int oy;
665 
666  oy = screen_hsize(data->backing) + data->cy - data->oy;
667 
668  while (oy > 0 && window_copy_find_length(wme, oy) == 0)
669  oy--;
670 
671  while (oy > 0 && window_copy_find_length(wme, oy) > 0)
672  oy--;
673 
674  window_copy_scroll_to(wme, 0, oy, 0);
675 }
676 
677 static void
679 {
680  struct window_copy_mode_data *data = wme->data;
681  struct screen *s = &data->screen;
682  u_int maxy, ox, oy;
683 
684  oy = screen_hsize(data->backing) + data->cy - data->oy;
685  maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
686 
687  while (oy < maxy && window_copy_find_length(wme, oy) == 0)
688  oy++;
689 
690  while (oy < maxy && window_copy_find_length(wme, oy) > 0)
691  oy++;
692 
693  ox = window_copy_find_length(wme, oy);
694  window_copy_scroll_to(wme, ox, oy, 0);
695 }
696 
697 char *
698 window_copy_get_word(struct window_pane *wp, u_int x, u_int y)
699 {
700  struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
701  struct window_copy_mode_data *data = wme->data;
702  struct grid *gd = data->screen.grid;
703 
704  return (format_grid_word(gd, x, gd->hsize + y));
705 }
706 
707 char *
708 window_copy_get_line(struct window_pane *wp, u_int y)
709 {
710  struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
711  struct window_copy_mode_data *data = wme->data;
712  struct grid *gd = data->screen.grid;
713 
714  return (format_grid_line(gd, gd->hsize + y));
715 }
716 
717 static void *
719 {
720  struct window_pane *wp = format_get_pane(ft);
721  struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
722  struct window_copy_mode_data *data = wme->data;
723 
724  return (window_copy_get_word(wp, data->cx, data->cy));
725 }
726 
727 static void *
729 {
730  struct window_pane *wp = format_get_pane(ft);
731  struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
732  struct window_copy_mode_data *data = wme->data;
733 
734  return (window_copy_get_line(wp, data->cy));
735 }
736 
737 static void *
739 {
740  struct window_pane *wp = format_get_pane(ft);
741  struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
742  struct window_copy_mode_data *data = wme->data;
743 
744  return (window_copy_match_at_cursor(data));
745 }
746 
747 static void
749 {
750  struct window_copy_mode_data *data = wme->data;
751 
752  format_add(ft, "scroll_position", "%d", data->oy);
753  format_add(ft, "rectangle_toggle", "%d", data->rectflag);
754 
755  format_add(ft, "copy_cursor_x", "%d", data->cx);
756  format_add(ft, "copy_cursor_y", "%d", data->cy);
757 
758  format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
759  if (data->screen.sel != NULL) {
760  format_add(ft, "selection_start_x", "%d", data->selx);
761  format_add(ft, "selection_start_y", "%d", data->sely);
762  format_add(ft, "selection_end_x", "%d", data->endselx);
763  format_add(ft, "selection_end_y", "%d", data->endsely);
764  format_add(ft, "selection_active", "%d",
765  data->cursordrag != CURSORDRAG_NONE);
766  } else
767  format_add(ft, "selection_active", "%d", 0);
768 
769  format_add(ft, "search_present", "%d", data->searchmark != NULL);
770  format_add_cb(ft, "search_match", window_copy_search_match_cb);
771 
772  format_add_cb(ft, "copy_cursor_word", window_copy_cursor_word_cb);
773  format_add_cb(ft, "copy_cursor_line", window_copy_cursor_line_cb);
774 }
775 
776 static void
778 {
779  struct window_copy_mode_data *data = wme->data;
780  struct screen *s = &data->screen;
781  struct screen_write_ctx ctx;
782  int search = (data->searchmark != NULL);
783 
786 
787  screen_write_start(&ctx, s);
788  window_copy_write_lines(wme, &ctx, 0, screen_size_y(s));
789  screen_write_stop(&ctx);
790 
791  if (search && !data->timeout)
792  window_copy_search_marks(wme, NULL, data->searchregex, 0);
793  data->searchx = data->cx;
794  data->searchy = data->cy;
795  data->searcho = data->oy;
796 }
797 
798 static void
799 window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
800 {
801  struct window_copy_mode_data *data = wme->data;
802  struct screen *s = &data->screen;
803  struct grid *gd = data->backing->grid;
804  u_int cx, cy, wx, wy;
805  int reflow;
806 
807  screen_resize(s, sx, sy, 0);
808  cx = data->cx;
809  cy = gd->hsize + data->cy - data->oy;
810  reflow = (gd->sx != sx);
811  if (reflow)
812  grid_wrap_position(gd, cx, cy, &wx, &wy);
813  screen_resize_cursor(data->backing, sx, sy, 1, 0, 0);
814  if (reflow)
815  grid_unwrap_position(gd, &cx, &cy, wx, wy);
816 
817  data->cx = cx;
818  if (cy < gd->hsize) {
819  data->cy = 0;
820  data->oy = gd->hsize - cy;
821  } else {
822  data->cy = cy - gd->hsize;
823  data->oy = 0;
824  }
825 
828 }
829 
830 static const char *
832 {
833  struct window_pane *wp = wme->wp;
834 
835  if (options_get_number(wp->window->options, "mode-keys") == MODEKEY_VI)
836  return ("copy-mode-vi");
837  return ("copy-mode");
838 }
839 
840 static int
842 {
843  struct window_mode_entry *wme = cs->wme;
844  struct window_copy_mode_data *data = wme->data;
845  const char *argument;
846  char *expanded;
847 
848  if (cs->args->argc == 2) {
849  argument = cs->args->argv[1];
850  if (*argument != '\0') {
851  if (args_has(cs->args, 'F')) {
852  expanded = format_single(NULL, argument, NULL,
853  NULL, NULL, wme->wp);
854  if (*expanded == '\0') {
855  free(expanded);
856  return (0);
857  }
858  free(data->searchstr);
859  data->searchstr = expanded;
860  } else {
861  free(data->searchstr);
862  data->searchstr = xstrdup(argument);
863  }
864  }
865  }
866  return (1);
867 }
868 
869 static enum window_copy_cmd_action
871 {
872  struct window_mode_entry *wme = cs->wme;
873  struct session *s = cs->s;
874 
875  if (s != NULL)
878  return (WINDOW_COPY_CMD_REDRAW);
879 }
880 
881 static enum window_copy_cmd_action
883 {
884  struct window_mode_entry *wme = cs->wme;
885  struct session *s = cs->s;
886 
887  if (s != NULL)
890  return (WINDOW_COPY_CMD_CANCEL);
891 }
892 
893 static enum window_copy_cmd_action
895 {
896  struct window_mode_entry *wme = cs->wme;
897 
899  return (WINDOW_COPY_CMD_NOTHING);
900 }
901 
902 static enum window_copy_cmd_action
904 {
905  struct window_mode_entry *wme = cs->wme;
906  struct client *c = cs->c;
907  struct mouse_event *m = cs->m;
908  struct window_copy_mode_data *data = wme->data;
909 
910  if (m != NULL) {
912  return (WINDOW_COPY_CMD_NOTHING);
913  }
914 
915  data->lineflag = LINE_SEL_NONE;
916  data->selflag = SEL_CHAR;
918  return (WINDOW_COPY_CMD_REDRAW);
919 }
920 
921 static enum window_copy_cmd_action
923 {
924  struct window_mode_entry *wme = cs->wme;
925  struct window_copy_mode_data *data = wme->data;
926 
927  data->cursordrag = CURSORDRAG_NONE;
928  data->lineflag = LINE_SEL_NONE;
929  data->selflag = SEL_CHAR;
930  return (WINDOW_COPY_CMD_NOTHING);
931 }
932 
933 static enum window_copy_cmd_action
935 {
936  struct window_mode_entry *wme = cs->wme;
937  struct window_copy_mode_data *data = wme->data;
938 
939  data->cx = 0;
940  data->cy = screen_size_y(&data->screen) - 1;
941 
942  window_copy_update_selection(wme, 1, 0);
943  return (WINDOW_COPY_CMD_REDRAW);
944 }
945 
946 static enum window_copy_cmd_action
948 {
949  return (WINDOW_COPY_CMD_CANCEL);
950 }
951 
952 static enum window_copy_cmd_action
954 {
955  struct window_mode_entry *wme = cs->wme;
956 
958  return (WINDOW_COPY_CMD_REDRAW);
959 }
960 
961 static enum window_copy_cmd_action
963 {
964  struct window_mode_entry *wme = cs->wme;
965  struct client *c = cs->c;
966  struct session *s = cs->s;
967  struct winlink *wl = cs->wl;
968  struct window_pane *wp = wme->wp;
969  u_int np = wme->prefix;
970  char *prefix = NULL;
971 
972  if (cs->args->argc == 2)
973  prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
974 
976  for (; np > 1; np--)
977  window_copy_cursor_down(wme, 0);
979 
980  if (s != NULL) {
981  window_copy_copy_selection(wme, prefix);
982 
983  free(prefix);
984  return (WINDOW_COPY_CMD_CANCEL);
985  }
986 
987  free(prefix);
988  return (WINDOW_COPY_CMD_REDRAW);
989 }
990 
991 static enum window_copy_cmd_action
993 {
994  struct window_mode_entry *wme = cs->wme;
995  struct client *c = cs->c;
996  struct session *s = cs->s;
997  struct winlink *wl = cs->wl;
998  struct window_pane *wp = wme->wp;
999  struct window_copy_mode_data *data = wme->data;
1000  u_int np = wme->prefix;
1001  char *prefix = NULL;
1002 
1003  if (cs->args->argc == 2)
1004  prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
1005 
1006  data->selflag = SEL_CHAR;
1009  for (; np > 1; np--)
1010  window_copy_cursor_down(wme, 0);
1012 
1013  if (s != NULL) {
1014  window_copy_copy_selection(wme, prefix);
1015 
1016  free(prefix);
1017  return (WINDOW_COPY_CMD_CANCEL);
1018  }
1019 
1020  free(prefix);
1021  return (WINDOW_COPY_CMD_REDRAW);
1022 }
1023 
1024 static enum window_copy_cmd_action
1026 {
1027  struct window_mode_entry *wme = cs->wme;
1028  struct client *c = cs->c;
1029  struct session *s = cs->s;
1030  struct winlink *wl = cs->wl;
1031  struct window_pane *wp = wme->wp;
1032  char *prefix = NULL;
1033 
1034  if (cs->args->argc == 2)
1035  prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
1036 
1037  if (s != NULL)
1038  window_copy_copy_selection(wme, prefix);
1039 
1040  free(prefix);
1041  return (WINDOW_COPY_CMD_NOTHING);
1042 }
1043 
1044 static enum window_copy_cmd_action
1046 {
1047  struct window_mode_entry *wme = cs->wme;
1048 
1051  return (WINDOW_COPY_CMD_REDRAW);
1052 }
1053 
1054 static enum window_copy_cmd_action
1056 {
1057  struct window_mode_entry *wme = cs->wme;
1058 
1061  return (WINDOW_COPY_CMD_CANCEL);
1062 }
1063 
1064 static enum window_copy_cmd_action
1066 {
1067  struct window_mode_entry *wme = cs->wme;
1068  u_int np = wme->prefix;
1069 
1070  for (; np != 0; np--)
1071  window_copy_cursor_down(wme, 0);
1072  return (WINDOW_COPY_CMD_NOTHING);
1073 }
1074 
1075 static enum window_copy_cmd_action
1077 {
1078  struct window_mode_entry *wme = cs->wme;
1079  struct window_copy_mode_data *data = wme->data;
1080  u_int np = wme->prefix, cy;
1081 
1082  cy = data->cy;
1083  for (; np != 0; np--)
1084  window_copy_cursor_down(wme, 0);
1085  if (cy == data->cy && data->oy == 0)
1086  return (WINDOW_COPY_CMD_CANCEL);
1087  return (WINDOW_COPY_CMD_NOTHING);
1088 }
1089 
1090 static enum window_copy_cmd_action
1092 {
1093  struct window_mode_entry *wme = cs->wme;
1094  u_int np = wme->prefix;
1095 
1096  for (; np != 0; np--)
1098  return (WINDOW_COPY_CMD_NOTHING);
1099 }
1100 
1101 static enum window_copy_cmd_action
1103 {
1104  struct window_mode_entry *wme = cs->wme;
1105  struct window_copy_mode_data *data = wme->data;
1106  u_int np = wme->prefix;
1107 
1108  for (; np != 0; np--) {
1109  window_copy_cursor_right(wme, data->screen.sel != NULL &&
1110  data->rectflag);
1111  }
1112  return (WINDOW_COPY_CMD_NOTHING);
1113 }
1114 
1115 static enum window_copy_cmd_action
1117 {
1118  struct window_mode_entry *wme = cs->wme;
1119  u_int np = wme->prefix;
1120 
1121  for (; np != 0; np--)
1122  window_copy_cursor_up(wme, 0);
1123  return (WINDOW_COPY_CMD_NOTHING);
1124 }
1125 
1126 static enum window_copy_cmd_action
1128 {
1129  struct window_mode_entry *wme = cs->wme;
1130 
1132  return (WINDOW_COPY_CMD_NOTHING);
1133 }
1134 
1135 static enum window_copy_cmd_action
1137 {
1138  struct window_mode_entry *wme = cs->wme;
1139  struct window_copy_mode_data *data = wme->data;
1140  u_int np = wme->prefix;
1141 
1142  for (; np != 0; np--) {
1143  if (window_copy_pagedown(wme, 1, data->scroll_exit))
1144  return (WINDOW_COPY_CMD_CANCEL);
1145  }
1146  return (WINDOW_COPY_CMD_NOTHING);
1147 }
1148 
1149 static enum window_copy_cmd_action
1151 {
1152 
1153  struct window_mode_entry *wme = cs->wme;
1154  u_int np = wme->prefix;
1155 
1156  for (; np != 0; np--) {
1157  if (window_copy_pagedown(wme, 1, 1))
1158  return (WINDOW_COPY_CMD_CANCEL);
1159  }
1160  return (WINDOW_COPY_CMD_NOTHING);
1161 }
1162 
1163 static enum window_copy_cmd_action
1165 {
1166  struct window_mode_entry *wme = cs->wme;
1167  u_int np = wme->prefix;
1168 
1169  for (; np != 0; np--)
1170  window_copy_pageup1(wme, 1);
1171  return (WINDOW_COPY_CMD_NOTHING);
1172 }
1173 
1174 static enum window_copy_cmd_action
1176 {
1177  struct window_mode_entry *wme = cs->wme;
1178  struct window_copy_mode_data *data = wme->data;
1179  struct screen *s = data->backing;
1180  u_int oy;
1181 
1182  oy = screen_hsize(s) + data->cy - data->oy;
1183  if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
1184  window_copy_other_end(wme);
1185 
1186  data->cy = screen_size_y(&data->screen) - 1;
1187  data->cx = window_copy_find_length(wme, screen_hsize(s) + data->cy);
1188  data->oy = 0;
1189 
1190  if (data->searchmark != NULL && !data->timeout)
1191  window_copy_search_marks(wme, NULL, data->searchregex, 1);
1192  window_copy_update_selection(wme, 1, 0);
1193  return (WINDOW_COPY_CMD_REDRAW);
1194 }
1195 
1196 static enum window_copy_cmd_action
1198 {
1199  struct window_mode_entry *wme = cs->wme;
1200  struct window_copy_mode_data *data = wme->data;
1201  u_int oy;
1202 
1203  oy = screen_hsize(data->backing) + data->cy - data->oy;
1204  if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1205  window_copy_other_end(wme);
1206 
1207  data->cy = 0;
1208  data->cx = 0;
1209  data->oy = screen_hsize(data->backing);
1210 
1211  if (data->searchmark != NULL && !data->timeout)
1212  window_copy_search_marks(wme, NULL, data->searchregex, 1);
1213  window_copy_update_selection(wme, 1, 0);
1214  return (WINDOW_COPY_CMD_REDRAW);
1215 }
1216 
1217 static enum window_copy_cmd_action
1219 {
1220  struct window_mode_entry *wme = cs->wme;
1221  struct window_copy_mode_data *data = wme->data;
1222  u_int np = wme->prefix;
1223 
1224  switch (data->jumptype) {
1226  for (; np != 0; np--)
1228  break;
1230  for (; np != 0; np--)
1232  break;
1234  for (; np != 0; np--)
1236  break;
1238  for (; np != 0; np--)
1240  break;
1241  }
1242  return (WINDOW_COPY_CMD_NOTHING);
1243 }
1244 
1245 static enum window_copy_cmd_action
1247 {
1248  struct window_mode_entry *wme = cs->wme;
1249  struct window_copy_mode_data *data = wme->data;
1250  u_int np = wme->prefix;
1251 
1252  switch (data->jumptype) {
1254  for (; np != 0; np--)
1256  break;
1258  for (; np != 0; np--)
1260  break;
1262  for (; np != 0; np--)
1264  break;
1266  for (; np != 0; np--)
1268  break;
1269  }
1270  return (WINDOW_COPY_CMD_NOTHING);
1271 }
1272 
1273 static enum window_copy_cmd_action
1275 {
1276  struct window_mode_entry *wme = cs->wme;
1277  struct window_copy_mode_data *data = wme->data;
1278 
1279  data->cx = 0;
1280  data->cy = (screen_size_y(&data->screen) - 1) / 2;
1281 
1282  window_copy_update_selection(wme, 1, 0);
1283  return (WINDOW_COPY_CMD_REDRAW);
1284 }
1285 
1286 static enum window_copy_cmd_action
1288 {
1289  struct window_mode_entry *wme = cs->wme;
1290  u_int np = wme->prefix;
1291  struct window_copy_mode_data *data = wme->data;
1292  struct screen *s = data->backing;
1293  char open[] = "{[(", close[] = "}])";
1294  char tried, found, start, *cp;
1295  u_int px, py, xx, n;
1296  struct grid_cell gc;
1297  int failed;
1298 
1299  for (; np != 0; np--) {
1300  /* Get cursor position and line length. */
1301  px = data->cx;
1302  py = screen_hsize(s) + data->cy - data->oy;
1303  xx = window_copy_find_length(wme, py);
1304  if (xx == 0)
1305  break;
1306 
1307  /*
1308  * Get the current character. If not on a bracket, try the
1309  * previous. If still not, then behave like previous-word.
1310  */
1311  tried = 0;
1312  retry:
1313  grid_get_cell(s->grid, px, py, &gc);
1314  if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING))
1315  cp = NULL;
1316  else {
1317  found = *gc.data.data;
1318  cp = strchr(close, found);
1319  }
1320  if (cp == NULL) {
1321  if (data->modekeys == MODEKEY_EMACS) {
1322  if (!tried && px > 0) {
1323  px--;
1324  tried = 1;
1325  goto retry;
1326  }
1327  window_copy_cursor_previous_word(wme, "}]) ", 1);
1328  }
1329  continue;
1330  }
1331  start = open[cp - close];
1332 
1333  /* Walk backward until the matching bracket is reached. */
1334  n = 1;
1335  failed = 0;
1336  do {
1337  if (px == 0) {
1338  if (py == 0) {
1339  failed = 1;
1340  break;
1341  }
1342  do {
1343  py--;
1344  xx = window_copy_find_length(wme, py);
1345  } while (xx == 0 && py > 0);
1346  if (xx == 0 && py == 0) {
1347  failed = 1;
1348  break;
1349  }
1350  px = xx - 1;
1351  } else
1352  px--;
1353 
1354  grid_get_cell(s->grid, px, py, &gc);
1355  if (gc.data.size == 1 &&
1356  (~gc.flags & GRID_FLAG_PADDING)) {
1357  if (*gc.data.data == found)
1358  n++;
1359  else if (*gc.data.data == start)
1360  n--;
1361  }
1362  } while (n != 0);
1363 
1364  /* Move the cursor to the found location if any. */
1365  if (!failed)
1366  window_copy_scroll_to(wme, px, py, 0);
1367  }
1368 
1369  return (WINDOW_COPY_CMD_NOTHING);
1370 }
1371 
1372 static enum window_copy_cmd_action
1374 {
1375  struct window_mode_entry *wme = cs->wme;
1376  u_int np = wme->prefix;
1377  struct window_copy_mode_data *data = wme->data;
1378  struct screen *s = data->backing;
1379  char open[] = "{[(", close[] = "}])";
1380  char tried, found, end, *cp;
1381  u_int px, py, xx, yy, sx, sy, n;
1382  struct grid_cell gc;
1383  int failed;
1384  struct grid_line *gl;
1385 
1386  for (; np != 0; np--) {
1387  /* Get cursor position and line length. */
1388  px = data->cx;
1389  py = screen_hsize(s) + data->cy - data->oy;
1390  xx = window_copy_find_length(wme, py);
1391  yy = screen_hsize(s) + screen_size_y(s) - 1;
1392  if (xx == 0)
1393  break;
1394 
1395  /*
1396  * Get the current character. If not on a bracket, try the
1397  * next. If still not, then behave like next-word.
1398  */
1399  tried = 0;
1400  retry:
1401  grid_get_cell(s->grid, px, py, &gc);
1402  if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING))
1403  cp = NULL;
1404  else {
1405  found = *gc.data.data;
1406 
1407  /*
1408  * In vi mode, attempt to move to previous bracket if a
1409  * closing bracket is found first. If this fails,
1410  * return to the original cursor position.
1411  */
1412  cp = strchr(close, found);
1413  if (cp != NULL && data->modekeys == MODEKEY_VI) {
1414  sx = data->cx;
1415  sy = screen_hsize(s) + data->cy - data->oy;
1416 
1417  window_copy_scroll_to(wme, px, py, 0);
1419 
1420  px = data->cx;
1421  py = screen_hsize(s) + data->cy - data->oy;
1422  grid_get_cell(s->grid, px, py, &gc);
1423  if (gc.data.size == 1 &&
1424  (~gc.flags & GRID_FLAG_PADDING) &&
1425  strchr(close, *gc.data.data) != NULL)
1426  window_copy_scroll_to(wme, sx, sy, 0);
1427  break;
1428  }
1429 
1430  cp = strchr(open, found);
1431  }
1432  if (cp == NULL) {
1433  if (data->modekeys == MODEKEY_EMACS) {
1434  if (!tried && px <= xx) {
1435  px++;
1436  tried = 1;
1437  goto retry;
1438  }
1440  0);
1441  continue;
1442  }
1443  /* For vi, continue searching for bracket until EOL. */
1444  if (px > xx) {
1445  if (py == yy)
1446  continue;
1447  gl = grid_get_line(s->grid, py);
1448  if (~gl->flags & GRID_LINE_WRAPPED)
1449  continue;
1450  if (gl->cellsize > s->grid->sx)
1451  continue;
1452  px = 0;
1453  py++;
1454  xx = window_copy_find_length(wme, py);
1455  } else
1456  px++;
1457  goto retry;
1458  }
1459  end = close[cp - open];
1460 
1461  /* Walk forward until the matching bracket is reached. */
1462  n = 1;
1463  failed = 0;
1464  do {
1465  if (px > xx) {
1466  if (py == yy) {
1467  failed = 1;
1468  break;
1469  }
1470  px = 0;
1471  py++;
1472  xx = window_copy_find_length(wme, py);
1473  } else
1474  px++;
1475 
1476  grid_get_cell(s->grid, px, py, &gc);
1477  if (gc.data.size == 1 &&
1478  (~gc.flags & GRID_FLAG_PADDING)) {
1479  if (*gc.data.data == found)
1480  n++;
1481  else if (*gc.data.data == end)
1482  n--;
1483  }
1484  } while (n != 0);
1485 
1486  /* Move the cursor to the found location if any. */
1487  if (!failed)
1488  window_copy_scroll_to(wme, px, py, 0);
1489  }
1490 
1491  return (WINDOW_COPY_CMD_NOTHING);
1492 }
1493 
1494 static enum window_copy_cmd_action
1496 {
1497  struct window_mode_entry *wme = cs->wme;
1498  u_int np = wme->prefix;
1499 
1500  for (; np != 0; np--)
1502  return (WINDOW_COPY_CMD_NOTHING);
1503 }
1504 
1505 static enum window_copy_cmd_action
1507 {
1508  struct window_mode_entry *wme = cs->wme;
1509  u_int np = wme->prefix;
1510 
1511  for (; np != 0; np--)
1512  window_copy_cursor_next_word(wme, " ");
1513  return (WINDOW_COPY_CMD_NOTHING);
1514 }
1515 
1516 static enum window_copy_cmd_action
1518 {
1519  struct window_mode_entry *wme = cs->wme;
1520  u_int np = wme->prefix;
1521 
1522  for (; np != 0; np--)
1523  window_copy_cursor_next_word_end(wme, " ", 0);
1524  return (WINDOW_COPY_CMD_NOTHING);
1525 }
1526 
1527 static enum window_copy_cmd_action
1529 {
1530  struct window_mode_entry *wme = cs->wme;
1531  struct session *s = cs->s;
1532  u_int np = wme->prefix;
1533  const char *ws;
1534 
1535  ws = options_get_string(s->options, "word-separators");
1536  for (; np != 0; np--)
1538  return (WINDOW_COPY_CMD_NOTHING);
1539 }
1540 
1541 static enum window_copy_cmd_action
1543 {
1544  struct window_mode_entry *wme = cs->wme;
1545  struct session *s = cs->s;
1546  u_int np = wme->prefix;
1547  const char *ws;
1548 
1549  ws = options_get_string(s->options, "word-separators");
1550  for (; np != 0; np--)
1552  return (WINDOW_COPY_CMD_NOTHING);
1553 }
1554 
1555 static enum window_copy_cmd_action
1557 {
1558  struct window_mode_entry *wme = cs->wme;
1559  u_int np = wme->prefix;
1560  struct window_copy_mode_data *data = wme->data;
1561 
1562  data->selflag = SEL_CHAR;
1563  if ((np % 2) != 0)
1564  window_copy_other_end(wme);
1565  return (WINDOW_COPY_CMD_NOTHING);
1566 }
1567 
1568 static enum window_copy_cmd_action
1570 {
1571  struct window_mode_entry *wme = cs->wme;
1572  struct window_copy_mode_data *data = wme->data;
1573  u_int np = wme->prefix;
1574 
1575  for (; np != 0; np--) {
1576  if (window_copy_pagedown(wme, 0, data->scroll_exit))
1577  return (WINDOW_COPY_CMD_CANCEL);
1578  }
1579  return (WINDOW_COPY_CMD_NOTHING);
1580 }
1581 
1582 static enum window_copy_cmd_action
1584 {
1585  struct window_mode_entry *wme = cs->wme;
1586  u_int np = wme->prefix;
1587 
1588  for (; np != 0; np--) {
1589  if (window_copy_pagedown(wme, 0, 1))
1590  return (WINDOW_COPY_CMD_CANCEL);
1591  }
1592  return (WINDOW_COPY_CMD_NOTHING);
1593 }
1594 
1595 static enum window_copy_cmd_action
1597 {
1598  struct window_mode_entry *wme = cs->wme;
1599  u_int np = wme->prefix;
1600 
1601  for (; np != 0; np--)
1602  window_copy_pageup1(wme, 0);
1603  return (WINDOW_COPY_CMD_NOTHING);
1604 }
1605 
1606 static enum window_copy_cmd_action
1608 {
1609  struct window_mode_entry *wme = cs->wme;
1610  u_int np = wme->prefix;
1611 
1612  for (; np != 0; np--)
1614  return (WINDOW_COPY_CMD_NOTHING);
1615 }
1616 
1617 static enum window_copy_cmd_action
1619 {
1620  struct window_mode_entry *wme = cs->wme;
1621  u_int np = wme->prefix;
1622 
1623  for (; np != 0; np--)
1624  window_copy_cursor_previous_word(wme, " ", 1);
1625  return (WINDOW_COPY_CMD_NOTHING);
1626 }
1627 
1628 static enum window_copy_cmd_action
1630 {
1631  struct window_mode_entry *wme = cs->wme;
1632  struct session *s = cs->s;
1633  u_int np = wme->prefix;
1634  const char *ws;
1635 
1636  ws = options_get_string(s->options, "word-separators");
1637  for (; np != 0; np--)
1639  return (WINDOW_COPY_CMD_NOTHING);
1640 }
1641 
1642 static enum window_copy_cmd_action
1644 {
1645  struct window_mode_entry *wme = cs->wme;
1646  struct window_copy_mode_data *data = wme->data;
1647 
1648  data->lineflag = LINE_SEL_NONE;
1649  window_copy_rectangle_set(wme, 1);
1650 
1651  return (WINDOW_COPY_CMD_NOTHING);
1652 }
1653 
1654 static enum window_copy_cmd_action
1656 {
1657  struct window_mode_entry *wme = cs->wme;
1658  struct window_copy_mode_data *data = wme->data;
1659 
1660  data->lineflag = LINE_SEL_NONE;
1661  window_copy_rectangle_set(wme, 0);
1662 
1663  return (WINDOW_COPY_CMD_NOTHING);
1664 }
1665 
1666 static enum window_copy_cmd_action
1668 {
1669  struct window_mode_entry *wme = cs->wme;
1670  struct window_copy_mode_data *data = wme->data;
1671 
1672  data->lineflag = LINE_SEL_NONE;
1673  window_copy_rectangle_set(wme, !data->rectflag);
1674 
1675  return (WINDOW_COPY_CMD_NOTHING);
1676 }
1677 
1678 static enum window_copy_cmd_action
1680 {
1681  struct window_mode_entry *wme = cs->wme;
1682  struct window_copy_mode_data *data = wme->data;
1683  u_int np = wme->prefix;
1684 
1685  for (; np != 0; np--)
1686  window_copy_cursor_down(wme, 1);
1687  if (data->scroll_exit && data->oy == 0)
1688  return (WINDOW_COPY_CMD_CANCEL);
1689  return (WINDOW_COPY_CMD_NOTHING);
1690 }
1691 
1692 static enum window_copy_cmd_action
1694 {
1695  struct window_mode_entry *wme = cs->wme;
1696  struct window_copy_mode_data *data = wme->data;
1697  u_int np = wme->prefix;
1698 
1699  for (; np != 0; np--)
1700  window_copy_cursor_down(wme, 1);
1701  if (data->oy == 0)
1702  return (WINDOW_COPY_CMD_CANCEL);
1703  return (WINDOW_COPY_CMD_NOTHING);
1704 }
1705 
1706 static enum window_copy_cmd_action
1708 {
1709  struct window_mode_entry *wme = cs->wme;
1710  u_int np = wme->prefix;
1711 
1712  for (; np != 0; np--)
1713  window_copy_cursor_up(wme, 1);
1714  return (WINDOW_COPY_CMD_NOTHING);
1715 }
1716 
1717 static enum window_copy_cmd_action
1719 {
1720  struct window_mode_entry *wme = cs->wme;
1721  struct window_copy_mode_data *data = wme->data;
1722  u_int np = wme->prefix;
1723 
1724  if (data->searchtype == WINDOW_COPY_SEARCHUP) {
1725  for (; np != 0; np--)
1726  window_copy_search_up(wme, data->searchregex);
1727  } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
1728  for (; np != 0; np--)
1730  }
1731  return (WINDOW_COPY_CMD_NOTHING);
1732 }
1733 
1734 static enum window_copy_cmd_action
1736 {
1737  struct window_mode_entry *wme = cs->wme;
1738  struct window_copy_mode_data *data = wme->data;
1739  u_int np = wme->prefix;
1740 
1741  if (data->searchtype == WINDOW_COPY_SEARCHUP) {
1742  for (; np != 0; np--)
1744  } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
1745  for (; np != 0; np--)
1746  window_copy_search_up(wme, data->searchregex);
1747  }
1748  return (WINDOW_COPY_CMD_NOTHING);
1749 }
1750 
1751 static enum window_copy_cmd_action
1753 {
1754  struct window_mode_entry *wme = cs->wme;
1755  struct window_copy_mode_data *data = wme->data;
1756  u_int np = wme->prefix;
1757 
1758  data->lineflag = LINE_SEL_LEFT_RIGHT;
1759  data->rectflag = 0;
1760  data->selflag = SEL_LINE;
1761  data->dx = data->cx;
1762  data->dy = screen_hsize(data->backing) + data->cy - data->oy;
1763 
1765  data->selrx = data->cx;
1766  data->selry = screen_hsize(data->backing) + data->cy - data->oy;
1767  data->endselry = data->selry;
1770  data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
1771  data->endselrx = window_copy_find_length(wme, data->endselry);
1772  for (; np > 1; np--) {
1773  window_copy_cursor_down(wme, 0);
1775  }
1776 
1777  return (WINDOW_COPY_CMD_REDRAW);
1778 }
1779 
1780 static enum window_copy_cmd_action
1782 {
1783  struct window_mode_entry *wme = cs->wme;
1784  struct session *s = cs->s;
1785  struct window_copy_mode_data *data = wme->data;
1786  u_int px, py, nextx, nexty;
1787 
1788  data->lineflag = LINE_SEL_LEFT_RIGHT;
1789  data->rectflag = 0;
1790  data->selflag = SEL_WORD;
1791  data->dx = data->cx;
1792  data->dy = screen_hsize(data->backing) + data->cy - data->oy;
1793 
1794  data->ws = options_get_string(s->options, "word-separators");
1795  window_copy_cursor_previous_word(wme, data->ws, 0);
1796  px = data->cx;
1797  py = screen_hsize(data->backing) + data->cy - data->oy;
1798  data->selrx = px;
1799  data->selry = py;
1801 
1802  /* Handle single character words. */
1803  nextx = px + 1;
1804  nexty = py;
1805  if (grid_get_line(data->backing->grid, nexty)->flags &
1806  GRID_LINE_WRAPPED && nextx > screen_size_x(data->backing) - 1) {
1807  nextx = 0;
1808  nexty++;
1809  }
1810  if (px >= window_copy_find_length(wme, py) ||
1811  !window_copy_in_set(wme, nextx, nexty, data->ws))
1812  window_copy_cursor_next_word_end(wme, data->ws, 1);
1813  else {
1814  window_copy_update_cursor(wme, px, data->cy);
1815  if (window_copy_update_selection(wme, 1, 1))
1816  window_copy_redraw_lines(wme, data->cy, 1);
1817  }
1818  data->endselrx = data->cx;
1819  data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
1820  if (data->dy > data->endselry) {
1821  data->dy = data->endselry;
1822  data->dx = data->endselrx;
1823  } else if (data->dx > data->endselrx)
1824  data->dx = data->endselrx;
1825 
1826  return (WINDOW_COPY_CMD_REDRAW);
1827 }
1828 
1829 static enum window_copy_cmd_action
1831 {
1832  struct window_copy_mode_data *data = cs->wme->data;
1833 
1834  data->mx = data->cx;
1835  data->my = screen_hsize(data->backing) + data->cy - data->oy;
1836  data->showmark = 1;
1837  return (WINDOW_COPY_CMD_REDRAW);
1838 }
1839 
1840 static enum window_copy_cmd_action
1842 {
1843  struct window_mode_entry *wme = cs->wme;
1844 
1846  return (WINDOW_COPY_CMD_NOTHING);
1847 }
1848 
1849 static enum window_copy_cmd_action
1851 {
1852  struct window_mode_entry *wme = cs->wme;
1853  struct window_copy_mode_data *data = wme->data;
1854 
1855  data->cx = 0;
1856  data->cy = 0;
1857 
1858  window_copy_update_selection(wme, 1, 0);
1859  return (WINDOW_COPY_CMD_REDRAW);
1860 }
1861 
1862 static enum window_copy_cmd_action
1864 {
1865  struct window_mode_entry *wme = cs->wme;
1866  struct client *c = cs->c;
1867  struct session *s = cs->s;
1868  struct winlink *wl = cs->wl;
1869  struct window_pane *wp = wme->wp;
1870  char *command = NULL;
1871  char *prefix = NULL;
1872 
1873  if (cs->args->argc == 3)
1874  prefix = format_single(NULL, cs->args->argv[2], c, s, wl, wp);
1875 
1876  if (s != NULL && cs->args->argc > 1 && *cs->args->argv[1] != '\0')
1877  command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
1878  window_copy_copy_pipe(wme, s, prefix, command);
1879  free(command);
1880 
1881  free(prefix);
1882  return (WINDOW_COPY_CMD_NOTHING);
1883 }
1884 
1885 static enum window_copy_cmd_action
1887 {
1888  struct window_mode_entry *wme = cs->wme;
1889 
1892  return (WINDOW_COPY_CMD_REDRAW);
1893 }
1894 
1895 static enum window_copy_cmd_action
1897 {
1898  struct window_mode_entry *wme = cs->wme;
1899 
1902  return (WINDOW_COPY_CMD_CANCEL);
1903 }
1904 
1905 static enum window_copy_cmd_action
1907 {
1908  struct window_mode_entry *wme = cs->wme;
1909  struct client *c = cs->c;
1910  struct session *s = cs->s;
1911  struct winlink *wl = cs->wl;
1912  struct window_pane *wp = wme->wp;
1913  char *command = NULL;
1914 
1915  if (s != NULL && cs->args->argc > 1 && *cs->args->argv[1] != '\0')
1916  command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
1917  window_copy_pipe(wme, s, command);
1918  free(command);
1919 
1920  return (WINDOW_COPY_CMD_NOTHING);
1921 }
1922 
1923 static enum window_copy_cmd_action
1925 {
1926  struct window_mode_entry *wme = cs->wme;
1927 
1930  return (WINDOW_COPY_CMD_REDRAW);
1931 }
1932 
1933 static enum window_copy_cmd_action
1935 {
1936  struct window_mode_entry *wme = cs->wme;
1937 
1940  return (WINDOW_COPY_CMD_CANCEL);
1941 }
1942 
1943 static enum window_copy_cmd_action
1945 {
1946  struct window_mode_entry *wme = cs->wme;
1947  const char *argument = cs->args->argv[1];
1948 
1949  if (*argument != '\0')
1950  window_copy_goto_line(wme, argument);
1951  return (WINDOW_COPY_CMD_NOTHING);
1952 }
1953 
1954 static enum window_copy_cmd_action
1956 {
1957  struct window_mode_entry *wme = cs->wme;
1958  struct window_copy_mode_data *data = wme->data;
1959  u_int np = wme->prefix;
1960  const char *argument = cs->args->argv[1];
1961 
1962  if (*argument != '\0') {
1964  free(data->jumpchar);
1965  data->jumpchar = utf8_fromcstr(argument);
1966  for (; np != 0; np--)
1968  }
1969  return (WINDOW_COPY_CMD_NOTHING);
1970 }
1971 
1972 static enum window_copy_cmd_action
1974 {
1975  struct window_mode_entry *wme = cs->wme;
1976  struct window_copy_mode_data *data = wme->data;
1977  u_int np = wme->prefix;
1978  const char *argument = cs->args->argv[1];
1979 
1980  if (*argument != '\0') {
1982  free(data->jumpchar);
1983  data->jumpchar = utf8_fromcstr(argument);
1984  for (; np != 0; np--)
1986  }
1987  return (WINDOW_COPY_CMD_NOTHING);
1988 }
1989 
1990 static enum window_copy_cmd_action
1992 {
1993  struct window_mode_entry *wme = cs->wme;
1994  struct window_copy_mode_data *data = wme->data;
1995  u_int np = wme->prefix;
1996  const char *argument = cs->args->argv[1];
1997 
1998  if (*argument != '\0') {
2000  free(data->jumpchar);
2001  data->jumpchar = utf8_fromcstr(argument);
2002  for (; np != 0; np--)
2004  }
2005  return (WINDOW_COPY_CMD_NOTHING);
2006 }
2007 
2008 static enum window_copy_cmd_action
2010 {
2011  struct window_mode_entry *wme = cs->wme;
2012  struct window_copy_mode_data *data = wme->data;
2013  u_int np = wme->prefix;
2014  const char *argument = cs->args->argv[1];
2015 
2016  if (*argument != '\0') {
2018  free(data->jumpchar);
2019  data->jumpchar = utf8_fromcstr(argument);
2020  for (; np != 0; np--)
2022  }
2023  return (WINDOW_COPY_CMD_NOTHING);
2024 }
2025 
2026 static enum window_copy_cmd_action
2028 {
2029  struct window_mode_entry *wme = cs->wme;
2030 
2032  return (WINDOW_COPY_CMD_NOTHING);
2033 }
2034 
2035 static enum window_copy_cmd_action
2037 {
2038  struct window_mode_entry *wme = cs->wme;
2039  struct window_copy_mode_data *data = wme->data;
2040  u_int np = wme->prefix;
2041 
2043  return (WINDOW_COPY_CMD_NOTHING);
2044 
2045  if (data->searchstr != NULL) {
2047  data->searchregex = 1;
2048  data->timeout = 0;
2049  for (; np != 0; np--)
2050  window_copy_search_up(wme, 1);
2051  }
2052  return (WINDOW_COPY_CMD_NOTHING);
2053 }
2054 
2055 static enum window_copy_cmd_action
2057 {
2058  struct window_mode_entry *wme = cs->wme;
2059  struct window_copy_mode_data *data = wme->data;
2060  u_int np = wme->prefix;
2061 
2063  return (WINDOW_COPY_CMD_NOTHING);
2064 
2065  if (data->searchstr != NULL) {
2067  data->searchregex = 0;
2068  data->timeout = 0;
2069  for (; np != 0; np--)
2070  window_copy_search_up(wme, 0);
2071  }
2072  return (WINDOW_COPY_CMD_NOTHING);
2073 }
2074 
2075 static enum window_copy_cmd_action
2077 {
2078  struct window_mode_entry *wme = cs->wme;
2079  struct window_copy_mode_data *data = wme->data;
2080  u_int np = wme->prefix;
2081 
2083  return (WINDOW_COPY_CMD_NOTHING);
2084 
2085  if (data->searchstr != NULL) {
2087  data->searchregex = 1;
2088  data->timeout = 0;
2089  for (; np != 0; np--)
2090  window_copy_search_down(wme, 1);
2091  }
2092  return (WINDOW_COPY_CMD_NOTHING);
2093 }
2094 
2095 static enum window_copy_cmd_action
2097 {
2098  struct window_mode_entry *wme = cs->wme;
2099  struct window_copy_mode_data *data = wme->data;
2100  u_int np = wme->prefix;
2101 
2103  return (WINDOW_COPY_CMD_NOTHING);
2104 
2105  if (data->searchstr != NULL) {
2107  data->searchregex = 0;
2108  data->timeout = 0;
2109  for (; np != 0; np--)
2110  window_copy_search_down(wme, 0);
2111  }
2112  return (WINDOW_COPY_CMD_NOTHING);
2113 }
2114 
2115 static enum window_copy_cmd_action
2117 {
2118  struct window_mode_entry *wme = cs->wme;
2119  struct window_copy_mode_data *data = wme->data;
2120  const char *argument = cs->args->argv[1];
2121  const char *ss = data->searchstr;
2122  char prefix;
2124 
2125  data->timeout = 0;
2126 
2127  log_debug ("%s: %s", __func__, argument);
2128 
2129  prefix = *argument++;
2130  if (data->searchx == -1 || data->searchy == -1) {
2131  data->searchx = data->cx;
2132  data->searchy = data->cy;
2133  data->searcho = data->oy;
2134  } else if (ss != NULL && strcmp(argument, ss) != 0) {
2135  data->cx = data->searchx;
2136  data->cy = data->searchy;
2137  data->oy = data->searcho;
2138  action = WINDOW_COPY_CMD_REDRAW;
2139  }
2140  if (*argument == '\0') {
2142  return (WINDOW_COPY_CMD_REDRAW);
2143  }
2144  switch (prefix) {
2145  case '=':
2146  case '-':
2148  data->searchregex = 0;
2149  free(data->searchstr);
2150  data->searchstr = xstrdup(argument);
2151  if (!window_copy_search_up(wme, 0)) {
2153  return (WINDOW_COPY_CMD_REDRAW);
2154  }
2155  break;
2156  case '+':
2158  data->searchregex = 0;
2159  free(data->searchstr);
2160  data->searchstr = xstrdup(argument);
2161  if (!window_copy_search_down(wme, 0)) {
2163  return (WINDOW_COPY_CMD_REDRAW);
2164  }
2165  break;
2166  }
2167  return (action);
2168 }
2169 
2170 static enum window_copy_cmd_action
2172 {
2173  struct window_mode_entry *wme = cs->wme;
2174  struct window_copy_mode_data *data = wme->data;
2175  const char *argument = cs->args->argv[1];
2176  const char *ss = data->searchstr;
2177  char prefix;
2179 
2180  data->timeout = 0;
2181 
2182  log_debug ("%s: %s", __func__, argument);
2183 
2184  prefix = *argument++;
2185  if (data->searchx == -1 || data->searchy == -1) {
2186  data->searchx = data->cx;
2187  data->searchy = data->cy;
2188  data->searcho = data->oy;
2189  } else if (ss != NULL && strcmp(argument, ss) != 0) {
2190  data->cx = data->searchx;
2191  data->cy = data->searchy;
2192  data->oy = data->searcho;
2193  action = WINDOW_COPY_CMD_REDRAW;
2194  }
2195  if (*argument == '\0') {
2197  return (WINDOW_COPY_CMD_REDRAW);
2198  }
2199  switch (prefix) {
2200  case '=':
2201  case '+':
2203  data->searchregex = 0;
2204  free(data->searchstr);
2205  data->searchstr = xstrdup(argument);
2206  if (!window_copy_search_down(wme, 0)) {
2208  return (WINDOW_COPY_CMD_REDRAW);
2209  }
2210  break;
2211  case '-':
2213  data->searchregex = 0;
2214  free(data->searchstr);
2215  data->searchstr = xstrdup(argument);
2216  if (!window_copy_search_up(wme, 0)) {
2218  return (WINDOW_COPY_CMD_REDRAW);
2219  }
2220  }
2221  return (action);
2222 }
2223 
2224 static enum window_copy_cmd_action
2226 {
2227  struct window_mode_entry *wme = cs->wme;
2228  struct window_pane *wp = wme->swp;
2229  struct window_copy_mode_data *data = wme->data;
2230 
2231  if (data->viewmode)
2232  return (WINDOW_COPY_CMD_NOTHING);
2233 
2234  screen_free(data->backing);
2235  free(data->backing);
2236  data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
2237  NULL, wme->swp != wme->wp);
2238 
2240  return (WINDOW_COPY_CMD_REDRAW);
2241 }
2242 
2243 static const struct {
2244  const char *command;
2245  int minargs;
2246  int maxargs;
2249 } window_copy_cmd_table[] = {
2250  { "append-selection", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2252  { "append-selection-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2254  { "back-to-indentation", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2256  { "begin-selection", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2258  { "bottom-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2260  { "cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2262  { "clear-selection", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2264  { "copy-end-of-line", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2266  { "copy-line", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2268  { "copy-pipe-no-clear", 0, 2, WINDOW_COPY_CMD_CLEAR_NEVER,
2270  { "copy-pipe", 0, 2, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2272  { "copy-pipe-and-cancel", 0, 2, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2274  { "copy-selection-no-clear", 0, 1, WINDOW_COPY_CMD_CLEAR_NEVER,
2276  { "copy-selection", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2278  { "copy-selection-and-cancel", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2280  { "cursor-down", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2282  { "cursor-down-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2284  { "cursor-left", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2286  { "cursor-right", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2288  { "cursor-up", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2290  { "end-of-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2292  { "goto-line", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2294  { "halfpage-down", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2296  { "halfpage-down-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2298  { "halfpage-up", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2300  { "history-bottom", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2302  { "history-top", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2304  { "jump-again", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2306  { "jump-backward", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2308  { "jump-forward", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2310  { "jump-reverse", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2312  { "jump-to-backward", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2314  { "jump-to-forward", 1, 1, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2316  { "jump-to-mark", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2318  { "middle-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2320  { "next-matching-bracket", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2322  { "next-paragraph", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2324  { "next-space", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2326  { "next-space-end", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2328  { "next-word", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2330  { "next-word-end", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2332  { "other-end", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2334  { "page-down", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2336  { "page-down-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2338  { "page-up", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2340  { "pipe-no-clear", 0, 1, WINDOW_COPY_CMD_CLEAR_NEVER,
2342  { "pipe", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2344  { "pipe-and-cancel", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2346  { "previous-matching-bracket", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2348  { "previous-paragraph", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2350  { "previous-space", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2352  { "previous-word", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2354  { "rectangle-on", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2356  { "rectangle-off", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2358  { "rectangle-toggle", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2360  { "refresh-from-pane", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2362  { "scroll-down", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2364  { "scroll-down-and-cancel", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2366  { "scroll-up", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2368  { "search-again", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2370  { "search-backward", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2372  { "search-backward-text", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2374  { "search-backward-incremental", 1, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2376  { "search-forward", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2378  { "search-forward-text", 0, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2380  { "search-forward-incremental", 1, 1, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2382  { "search-reverse", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2384  { "select-line", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2386  { "select-word", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2388  { "set-mark", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2390  { "start-of-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2392  { "stop-selection", 0, 0, WINDOW_COPY_CMD_CLEAR_ALWAYS,
2394  { "top-line", 0, 0, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2396 };
2397 
2398 static void
2400  struct session *s, struct winlink *wl, struct args *args,
2401  struct mouse_event *m)
2402 {
2403  struct window_copy_mode_data *data = wme->data;
2404  struct window_copy_cmd_state cs;
2405  enum window_copy_cmd_action action;
2407  const char *command;
2408  u_int i;
2409  int keys;
2410 
2411  if (args->argc == 0)
2412  return;
2413  command = args->argv[0];
2414 
2415  if (m != NULL && m->valid && !MOUSE_WHEEL(m->b))
2417 
2418  cs.wme = wme;
2419  cs.args = args;
2420  cs.m = m;
2421 
2422  cs.c = c;
2423  cs.s = s;
2424  cs.wl = wl;
2425 
2426  action = WINDOW_COPY_CMD_NOTHING;
2427  for (i = 0; i < nitems(window_copy_cmd_table); i++) {
2428  if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
2429  if (args->argc - 1 < window_copy_cmd_table[i].minargs ||
2430  args->argc - 1 > window_copy_cmd_table[i].maxargs)
2431  break;
2432  clear = window_copy_cmd_table[i].clear;
2433  action = window_copy_cmd_table[i].f (&cs);
2434  break;
2435  }
2436  }
2437 
2438  if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
2439  keys = options_get_number(wme->wp->window->options, "mode-keys");
2441  keys == MODEKEY_VI)
2445  data->searchx = data->searchy = -1;
2446  }
2447  if (action == WINDOW_COPY_CMD_NOTHING)
2448  action = WINDOW_COPY_CMD_REDRAW;
2449  }
2450  wme->prefix = 1;
2451 
2452  if (action == WINDOW_COPY_CMD_CANCEL)
2454  else if (action == WINDOW_COPY_CMD_REDRAW)
2456 }
2457 
2458 static void
2459 window_copy_scroll_to(struct window_mode_entry *wme, u_int px, u_int py,
2460  int no_redraw)
2461 {
2462  struct window_copy_mode_data *data = wme->data;
2463  struct grid *gd = data->backing->grid;
2464  u_int offset, gap;
2465 
2466  data->cx = px;
2467 
2468  if (py >= gd->hsize - data->oy && py < gd->hsize - data->oy + gd->sy)
2469  data->cy = py - (gd->hsize - data->oy);
2470  else {
2471  gap = gd->sy / 4;
2472  if (py < gd->sy) {
2473  offset = 0;
2474  data->cy = py;
2475  } else if (py > gd->hsize + gd->sy - gap) {
2476  offset = gd->hsize;
2477  data->cy = py - gd->hsize;
2478  } else {
2479  offset = py + gap - gd->sy;
2480  data->cy = py - offset;
2481  }
2482  data->oy = gd->hsize - offset;
2483  }
2484 
2485  if (!no_redraw && data->searchmark != NULL && !data->timeout)
2486  window_copy_search_marks(wme, NULL, data->searchregex, 1);
2487  window_copy_update_selection(wme, 1, 0);
2488  if (!no_redraw)
2490 }
2491 
2492 static int
2493 window_copy_search_compare(struct grid *gd, u_int px, u_int py,
2494  struct grid *sgd, u_int spx, int cis)
2495 {
2496  struct grid_cell gc, sgc;
2497  const struct utf8_data *ud, *sud;
2498 
2499  grid_get_cell(gd, px, py, &gc);
2500  ud = &gc.data;
2501  grid_get_cell(sgd, spx, 0, &sgc);
2502  sud = &sgc.data;
2503 
2504  if (ud->size != sud->size || ud->width != sud->width)
2505  return (0);
2506 
2507  if (cis && ud->size == 1)
2508  return (tolower(ud->data[0]) == sud->data[0]);
2509 
2510  return (memcmp(ud->data, sud->data, ud->size) == 0);
2511 }
2512 
2513 static int
2514 window_copy_search_lr(struct grid *gd, struct grid *sgd, u_int *ppx, u_int py,
2515  u_int first, u_int last, int cis)
2516 {
2517  u_int ax, bx, px, pywrap, endline;
2518  int matched;
2519  struct grid_line *gl;
2520 
2521  endline = gd->hsize + gd->sy - 1;
2522  for (ax = first; ax < last; ax++) {
2523  for (bx = 0; bx < sgd->sx; bx++) {
2524  px = ax + bx;
2525  pywrap = py;
2526  /* Wrap line. */
2527  while (px >= gd->sx && pywrap < endline) {
2528  gl = grid_get_line(gd, pywrap);
2529  if (~gl->flags & GRID_LINE_WRAPPED)
2530  break;
2531  px -= gd->sx;
2532  pywrap++;
2533  }
2534  /* We have run off the end of the grid. */
2535  if (px >= gd->sx)
2536  break;
2537  matched = window_copy_search_compare(gd, px, pywrap,
2538  sgd, bx, cis);
2539  if (!matched)
2540  break;
2541  }
2542  if (bx == sgd->sx) {
2543  *ppx = ax;
2544  return (1);
2545  }
2546  }
2547  return (0);
2548 }
2549 
2550 static int
2552  struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
2553 {
2554  u_int ax, bx, px, pywrap, endline;
2555  int matched;
2556  struct grid_line *gl;
2557 
2558  endline = gd->hsize + gd->sy - 1;
2559  for (ax = last; ax > first; ax--) {
2560  for (bx = 0; bx < sgd->sx; bx++) {
2561  px = ax - 1 + bx;
2562  pywrap = py;
2563  /* Wrap line. */
2564  while (px >= gd->sx && pywrap < endline) {
2565  gl = grid_get_line(gd, pywrap);
2566  if (~gl->flags & GRID_LINE_WRAPPED)
2567  break;
2568  px -= gd->sx;
2569  pywrap++;
2570  }
2571  /* We have run off the end of the grid. */
2572  if (px >= gd->sx)
2573  break;
2574  matched = window_copy_search_compare(gd, px, pywrap,
2575  sgd, bx, cis);
2576  if (!matched)
2577  break;
2578  }
2579  if (bx == sgd->sx) {
2580  *ppx = ax - 1;
2581  return (1);
2582  }
2583  }
2584  return (0);
2585 }
2586 
2587 static int
2588 window_copy_search_lr_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
2589  u_int first, u_int last, regex_t *reg)
2590 {
2591  int eflags = 0;
2592  u_int endline, foundx, foundy, len, pywrap, size = 1;
2593  char *buf;
2594  regmatch_t regmatch;
2595  struct grid_line *gl;
2596 
2597  /*
2598  * This can happen during search if the last match was the last
2599  * character on a line.
2600  */
2601  if (first >= last)
2602  return (0);
2603 
2604  /* Set flags for regex search. */
2605  if (first != 0)
2606  eflags |= REG_NOTBOL;
2607 
2608  /* Need to look at the entire string. */
2609  buf = xmalloc(size);
2610  buf[0] = '\0';
2611  buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
2612  len = gd->sx - first;
2613  endline = gd->hsize + gd->sy - 1;
2614  pywrap = py;
2615  while (buf != NULL && pywrap <= endline) {
2616  gl = grid_get_line(gd, pywrap);
2617  if (~gl->flags & GRID_LINE_WRAPPED)
2618  break;
2619  pywrap++;
2620  buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
2621  len += gd->sx;
2622  }
2623 
2624  if (regexec(reg, buf, 1, &regmatch, eflags) == 0 &&
2625  regmatch.rm_so != regmatch.rm_eo) {
2626  foundx = first;
2627  foundy = py;
2628  window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
2629  buf + regmatch.rm_so);
2630  if (foundy == py && foundx < last) {
2631  *ppx = foundx;
2632  len -= foundx - first;
2633  window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
2634  buf + regmatch.rm_eo);
2635  *psx = foundx;
2636  while (foundy > py) {
2637  *psx += gd->sx;
2638  foundy--;
2639  }
2640  *psx -= *ppx;
2641  free(buf);
2642  return (1);
2643  }
2644  }
2645 
2646  free(buf);
2647  *ppx = 0;
2648  *psx = 0;
2649  return (0);
2650 }
2651 
2652 static int
2653 window_copy_search_rl_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
2654  u_int first, u_int last, regex_t *reg)
2655 {
2656  int eflags = 0;
2657  u_int endline, len, pywrap, size = 1;
2658  char *buf;
2659  struct grid_line *gl;
2660 
2661  /* Set flags for regex search. */
2662  if (first != 0)
2663  eflags |= REG_NOTBOL;
2664 
2665  /* Need to look at the entire string. */
2666  buf = xmalloc(size);
2667  buf[0] = '\0';
2668  buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
2669  len = gd->sx - first;
2670  endline = gd->hsize + gd->sy - 1;
2671  pywrap = py;
2672  while (buf != NULL && (pywrap <= endline)) {
2673  gl = grid_get_line(gd, pywrap);
2674  if (~gl->flags & GRID_LINE_WRAPPED)
2675  break;
2676  pywrap++;
2677  buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
2678  len += gd->sx;
2679  }
2680 
2681  if (window_copy_last_regex(gd, py, first, last, len, ppx, psx, buf,
2682  reg, eflags))
2683  {
2684  free(buf);
2685  return (1);
2686  }
2687 
2688  free(buf);
2689  *ppx = 0;
2690  *psx = 0;
2691  return (0);
2692 }
2693 
2694 static const char *
2695 window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size,
2696  int *allocated)
2697 {
2698  static struct utf8_data ud;
2699  struct grid_cell_entry *gce;
2700  char *copy;
2701 
2702  if (px >= gl->cellsize) {
2703  *size = 1;
2704  *allocated = 0;
2705  return (" ");
2706  }
2707 
2708  gce = &gl->celldata[px];
2709  if (gce->flags & GRID_FLAG_PADDING) {
2710  *size = 0;
2711  *allocated = 0;
2712  return (NULL);
2713  }
2714  if (~gce->flags & GRID_FLAG_EXTENDED) {
2715  *size = 1;
2716  *allocated = 0;
2717  return (&gce->data.data);
2718  }
2719 
2720  utf8_to_data(gl->extddata[gce->offset].data, &ud);
2721  *size = ud.size;
2722  *allocated = 1;
2723 
2724  copy = xmalloc(ud.size);
2725  memcpy(copy, ud.data, ud.size);
2726  return (copy);
2727 }
2728 
2729 /* Find last match in given range. */
2730 static int
2731 window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last,
2732  u_int len, u_int *ppx, u_int *psx, const char *buf, const regex_t *preg,
2733  int eflags)
2734 {
2735  u_int foundx, foundy, oldx, px = 0, savepx, savesx = 0;
2736  regmatch_t regmatch;
2737 
2738  foundx = first;
2739  foundy = py;
2740  oldx = first;
2741  while (regexec(preg, buf + px, 1, &regmatch, eflags) == 0) {
2742  if (regmatch.rm_so == regmatch.rm_eo)
2743  break;
2744  window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
2745  buf + px + regmatch.rm_so);
2746  if (foundy > py || foundx >= last)
2747  break;
2748  len -= foundx - oldx;
2749  savepx = foundx;
2750  window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
2751  buf + px + regmatch.rm_eo);
2752  if (foundy > py || foundx >= last) {
2753  *ppx = savepx;
2754  *psx = foundx;
2755  while (foundy > py) {
2756  *psx += gd->sx;
2757  foundy--;
2758  }
2759  *psx -= *ppx;
2760  return (1);
2761  } else {
2762  savesx = foundx - savepx;
2763  len -= savesx;
2764  oldx = foundx;
2765  }
2766  px += regmatch.rm_eo;
2767  }
2768 
2769  if (savesx > 0) {
2770  *ppx = savepx;
2771  *psx = savesx;
2772  return (1);
2773  } else {
2774  *ppx = 0;
2775  *psx = 0;
2776  return (0);
2777  }
2778 }
2779 
2780 /* Stringify line and append to input buffer. Caller frees. */
2781 static char *
2782 window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
2783  char *buf, u_int *size)
2784 {
2785  u_int ax, bx, newsize = *size;
2786  const struct grid_line *gl;
2787  const char *d;
2788  size_t bufsize = 1024, dlen;
2789  int allocated;
2790 
2791  while (bufsize < newsize)
2792  bufsize *= 2;
2793  buf = xrealloc(buf, bufsize);
2794 
2795  gl = grid_peek_line(gd, py);
2796  bx = *size - 1;
2797  for (ax = first; ax < last; ax++) {
2798  d = window_copy_cellstring(gl, ax, &dlen, &allocated);
2799  newsize += dlen;
2800  while (bufsize < newsize) {
2801  bufsize *= 2;
2802  buf = xrealloc(buf, bufsize);
2803  }
2804  if (dlen == 1)
2805  buf[bx++] = *d;
2806  else {
2807  memcpy(buf + bx, d, dlen);
2808  bx += dlen;
2809  }
2810  if (allocated)
2811  free((void *)d);
2812  }
2813  buf[newsize - 1] = '\0';
2814 
2815  *size = newsize;
2816  return (buf);
2817 }
2818 
2819 /* Map start of C string containing UTF-8 data to grid cell position. */
2820 static void
2821 window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy,
2822  const char *str)
2823 {
2824  u_int cell, ccell, px, pywrap, pos, len;
2825  int match;
2826  const struct grid_line *gl;
2827  const char *d;
2828  size_t dlen;
2829  struct {
2830  const char *d;
2831  size_t dlen;
2832  int allocated;
2833  } *cells;
2834 
2835  /* Populate the array of cell data. */
2836  cells = xreallocarray(NULL, ncells, sizeof cells[0]);
2837  cell = 0;
2838  px = *ppx;
2839  pywrap = *ppy;
2840  gl = grid_peek_line(gd, pywrap);
2841  while (cell < ncells) {
2842  cells[cell].d = window_copy_cellstring(gl, px,
2843  &cells[cell].dlen, &cells[cell].allocated);
2844  cell++;
2845  px++;
2846  if (px == gd->sx) {
2847  px = 0;
2848  pywrap++;
2849  gl = grid_peek_line(gd, pywrap);
2850  }
2851  }
2852 
2853  /* Locate starting cell. */
2854  cell = 0;
2855  len = strlen(str);
2856  while (cell < ncells) {
2857  ccell = cell;
2858  pos = 0;
2859  match = 1;
2860  while (ccell < ncells) {
2861  if (str[pos] == '\0') {
2862  match = 0;
2863  break;
2864  }
2865  d = cells[ccell].d;
2866  dlen = cells[ccell].dlen;
2867  if (dlen == 1) {
2868  if (str[pos] != *d) {
2869  match = 0;
2870  break;
2871  }
2872  pos++;
2873  } else {
2874  if (dlen > len - pos)
2875  dlen = len - pos;
2876  if (memcmp(str + pos, d, dlen) != 0) {
2877  match = 0;
2878  break;
2879  }
2880  pos += dlen;
2881  }
2882  ccell++;
2883  }
2884  if (match)
2885  break;
2886  cell++;
2887  }
2888 
2889  /* If not found this will be one past the end. */
2890  px = *ppx + cell;
2891  pywrap = *ppy;
2892  while (px >= gd->sx) {
2893  px -= gd->sx;
2894  pywrap++;
2895  }
2896 
2897  *ppx = px;
2898  *ppy = pywrap;
2899 
2900  /* Free cell data. */
2901  for (cell = 0; cell < ncells; cell++) {
2902  if (cells[cell].allocated)
2903  free((void *)cells[cell].d);
2904  }
2905  free(cells);
2906 }
2907 
2908 static void
2909 window_copy_move_left(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
2910 {
2911  if (*fx == 0) { /* left */
2912  if (*fy == 0) { /* top */
2913  if (wrapflag) {
2914  *fx = screen_size_x(s) - 1;
2915  *fy = screen_hsize(s) + screen_size_y(s) - 1;
2916  }
2917  return;
2918  }
2919  *fx = screen_size_x(s) - 1;
2920  *fy = *fy - 1;
2921  } else
2922  *fx = *fx - 1;
2923 }
2924 
2925 static void
2926 window_copy_move_right(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
2927 {
2928  if (*fx == screen_size_x(s) - 1) { /* right */
2929  if (*fy == screen_hsize(s) + screen_size_y(s) - 1) { /* bottom */
2930  if (wrapflag) {
2931  *fx = 0;
2932  *fy = 0;
2933  }
2934  return;
2935  }
2936  *fx = 0;
2937  *fy = *fy + 1;
2938  } else
2939  *fx = *fx + 1;
2940 }
2941 
2942 static int
2944 {
2945  while (*ptr != '\0') {
2946  if (*ptr != tolower((u_char)*ptr))
2947  return (0);
2948  ++ptr;
2949  }
2950  return (1);
2951 }
2952 
2953 /*
2954  * Handle backward wrapped regex searches with overlapping matches. In this case
2955  * find the longest overlapping match from previous wrapped lines.
2956  */
2957 static void
2958 window_copy_search_back_overlap(struct grid *gd, regex_t *preg, u_int *ppx,
2959  u_int *psx, u_int *ppy, u_int endline)
2960 {
2961  u_int endx, endy, oldendx, oldendy, px, py, sx;
2962  int found = 1;
2963 
2964  oldendx = *ppx + *psx;
2965  oldendy = *ppy - 1;
2966  while (oldendx > gd->sx - 1) {
2967  oldendx -= gd->sx;
2968  oldendy++;
2969  }
2970  endx = oldendx;
2971  endy = oldendy;
2972  px = *ppx;
2973  py = *ppy;
2974  while (found && px == 0 && py - 1 > endline &&
2975  grid_get_line(gd, py - 2)->flags & GRID_LINE_WRAPPED &&
2976  endx == oldendx && endy == oldendy) {
2977  py--;
2978  found = window_copy_search_rl_regex(gd, &px, &sx, py - 1, 0,
2979  gd->sx, preg);
2980  if (found) {
2981  endx = px + sx;
2982  endy = py - 1;
2983  while (endx > gd->sx - 1) {
2984  endx -= gd->sx;
2985  endy++;
2986  }
2987  if (endx == oldendx && endy == oldendy) {
2988  *ppx = px;
2989  *ppy = py;
2990  }
2991  }
2992  }
2993 }
2994 
2995 /*
2996  * Search for text stored in sgd starting from position fx,fy up to endline. If
2997  * found, jump to it. If cis then ignore case. The direction is 0 for searching
2998  * up, down otherwise. If wrap then go to begin/end of grid and try again if
2999  * not found.
3000  */
3001 static int
3003  struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
3004  int direction, int regex)
3005 {
3006  u_int i, px, sx, ssize = 1;
3007  int found = 0, cflags = REG_EXTENDED;
3008  char *sbuf;
3009  regex_t reg;
3010 
3011  if (regex) {
3012  sbuf = xmalloc(ssize);
3013  sbuf[0] = '\0';
3014  sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize);
3015  if (cis)
3016  cflags |= REG_ICASE;
3017  if (regcomp(&reg, sbuf, cflags) != 0) {
3018  free(sbuf);
3019  return (0);
3020  }
3021  free(sbuf);
3022  }
3023 
3024  if (direction) {
3025  for (i = fy; i <= endline; i++) {
3026  if (regex) {
3027  found = window_copy_search_lr_regex(gd,
3028  &px, &sx, i, fx, gd->sx, &reg);
3029  } else {
3030  found = window_copy_search_lr(gd, sgd,
3031  &px, i, fx, gd->sx, cis);
3032  }
3033  if (found)
3034  break;
3035  fx = 0;
3036  }
3037  } else {
3038  for (i = fy + 1; endline < i; i--) {
3039  if (regex) {
3040  found = window_copy_search_rl_regex(gd,
3041  &px, &sx, i - 1, 0, fx + 1, &reg);
3042  if (found) {
3044  &reg, &px, &sx, &i, endline);
3045  }
3046  } else {
3047  found = window_copy_search_rl(gd, sgd,
3048  &px, i - 1, 0, fx + 1, cis);
3049  }
3050  if (found) {
3051  i--;
3052  break;
3053  }
3054  fx = gd->sx - 1;
3055  }
3056  }
3057  if (regex)
3058  regfree(&reg);
3059 
3060  if (found) {
3061  window_copy_scroll_to(wme, px, i, 1);
3062  return (1);
3063  }
3064  if (wrap) {
3065  return (window_copy_search_jump(wme, gd, sgd,
3066  direction ? 0 : gd->sx - 1,
3067  direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
3068  direction, regex));
3069  }
3070  return (0);
3071 }
3072 
3073 static void
3075  u_int *fx, u_int *fy, int wrapflag)
3076 {
3077  struct screen *s = data->backing;
3078  u_int at, start;
3079 
3080  if (window_copy_search_mark_at(data, *fx, *fy, &start) == 0 &&
3081  data->searchmark[start] != 0) {
3082  while (window_copy_search_mark_at(data, *fx, *fy, &at) == 0) {
3083  if (data->searchmark[at] != data->searchmark[start])
3084  break;
3085  /* Stop if not wrapping and at the end of the grid. */
3086  if (!wrapflag &&
3087  *fx == screen_size_x(s) - 1 &&
3088  *fy == screen_hsize(s) + screen_size_y(s) - 1)
3089  break;
3090 
3091  window_copy_move_right(s, fx, fy, wrapflag);
3092  }
3093  }
3094 }
3095 
3096 /*
3097  * Search in for text searchstr. If direction is 0 then search up, otherwise
3098  * down.
3099  */
3100 static int
3101 window_copy_search(struct window_mode_entry *wme, int direction, int regex)
3102 {
3103  struct window_pane *wp = wme->wp;
3104  struct window_copy_mode_data *data = wme->data;
3105  struct screen *s = data->backing, ss;
3106  struct screen_write_ctx ctx;
3107  struct grid *gd = s->grid;
3108  const char *str = data->searchstr;
3109  u_int at, endline, fx, fy, start;
3110  int cis, found, keys, visible_only;
3111  int wrapflag;
3112 
3113  if (regex && str[strcspn(str, "^$*+()?[].\\")] == '\0')
3114  regex = 0;
3115 
3116  data->searchdirection = direction;
3117 
3118  if (data->timeout)
3119  return (0);
3120 
3121  if (data->searchall || wp->searchstr == NULL ||
3122  wp->searchregex != regex) {
3123  visible_only = 0;
3124  data->searchall = 0;
3125  } else
3126  visible_only = (strcmp(wp->searchstr, str) == 0);
3127  free(wp->searchstr);
3128  wp->searchstr = xstrdup(str);
3129  wp->searchregex = regex;
3130 
3131  fx = data->cx;
3132  fy = screen_hsize(data->backing) - data->oy + data->cy;
3133 
3134  screen_init(&ss, screen_write_strlen("%s", str), 1, 0);
3135  screen_write_start(&ctx, &ss);
3136  screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str);
3137  screen_write_stop(&ctx);
3138 
3139  wrapflag = options_get_number(wp->window->options, "wrap-search");
3140  cis = window_copy_is_lowercase(str);
3141 
3142  keys = options_get_number(wp->window->options, "mode-keys");
3143 
3144  if (direction) {
3145  /*
3146  * Behave according to mode-keys. If it is emacs, search forward
3147  * leaves the cursor after the match. If it is vi, the cursor
3148  * remains at the beginning of the match, regardless of
3149  * direction, which means that we need to start the next search
3150  * after the term the cursor is currently on when searching
3151  * forward.
3152  */
3153  if (keys == MODEKEY_VI) {
3154  if (data->searchmark != NULL)
3156  &fy, wrapflag);
3157  else {
3158  /*
3159  * When there are no search marks, start the
3160  * search after the current cursor position.
3161  */
3162  window_copy_move_right(s, &fx, &fy, wrapflag);
3163  }
3164  }
3165  endline = gd->hsize + gd->sy - 1;
3166  }
3167  else {
3168  window_copy_move_left(s, &fx, &fy, wrapflag);
3169  endline = 0;
3170  }
3171 
3172  found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
3173  wrapflag, direction, regex);
3174  if (found) {
3175  window_copy_search_marks(wme, &ss, regex, visible_only);
3176  fx = data->cx;
3177  fy = screen_hsize(data->backing) - data->oy + data->cy;
3178 
3179  /*
3180  * When searching forward, if the cursor is not at the beginning
3181  * of the mark, search again.
3182  */
3183  if (direction &&
3184  window_copy_search_mark_at(data, fx, fy, &at) == 0 &&
3185  at > 0 &&
3186  data->searchmark[at] == data->searchmark[at - 1]) {
3187  window_copy_move_after_search_mark(data, &fx, &fy,
3188  wrapflag);
3189  window_copy_search_jump(wme, gd, ss.grid, fx,
3190  fy, endline, cis, wrapflag, direction,
3191  regex);
3192  fx = data->cx;
3193  fy = screen_hsize(data->backing) - data->oy + data->cy;
3194  }
3195 
3196  if (direction) {
3197  /*
3198  * When in Emacs mode, position the cursor just after
3199  * the mark.
3200  */
3201  if (keys == MODEKEY_EMACS) {
3203  &fy, wrapflag);
3204  data->cx = fx;
3205  data->cy = fy - screen_hsize(data->backing) +
3206  data-> oy;
3207  }
3208  }
3209  else {
3210  /*
3211  * When searching backward, position the cursor at the
3212  * beginning of the mark.
3213  */
3214  if (window_copy_search_mark_at(data, fx, fy,
3215  &start) == 0) {
3216  while (window_copy_search_mark_at(data, fx, fy,
3217  &at) == 0 &&
3218  data->searchmark[at] ==
3219  data->searchmark[start]) {
3220  data->cx = fx;
3221  data->cy = fy -
3222  screen_hsize(data->backing) +
3223  data-> oy;
3224  if (at == 0)
3225  break;
3226 
3227  window_copy_move_left(s, &fx, &fy, 0);
3228  }
3229  }
3230  }
3231  }
3233 
3234  screen_free(&ss);
3235  return (found);
3236 }
3237 
3238 static void
3240  u_int *end)
3241 {
3242  struct grid *gd = data->backing->grid;
3243  const struct grid_line *gl;
3244 
3245  for (*start = gd->hsize - data->oy; *start > 0; (*start)--) {
3246  gl = grid_peek_line(gd, (*start) - 1);
3247  if (~gl->flags & GRID_LINE_WRAPPED)
3248  break;
3249  }
3250  *end = gd->hsize - data->oy + gd->sy;
3251 }
3252 
3253 static int
3255  u_int py, u_int *at)
3256 {
3257  struct screen *s = data->backing;
3258  struct grid *gd = s->grid;
3259 
3260  if (py < gd->hsize - data->oy)
3261  return (-1);
3262  if (py > gd->hsize - data->oy + gd->sy - 1)
3263  return (-1);
3264  *at = ((py - (gd->hsize - data->oy)) * gd->sx) + px;
3265  return (0);
3266 }
3267 
3268 static int
3270  int regex, int visible_only)
3271 {
3272  struct window_copy_mode_data *data = wme->data;
3273  struct screen *s = data->backing, ss;
3274  struct screen_write_ctx ctx;
3275  struct grid *gd = s->grid;
3276  int found, cis, stopped = 0;
3277  int cflags = REG_EXTENDED;
3278  u_int px, py, i, b, nfound = 0, width;
3279  u_int ssize = 1, start, end;
3280  char *sbuf;
3281  regex_t reg;
3282  uint64_t stop = 0, tstart, t;
3283 
3284  if (ssp == NULL) {
3285  width = screen_write_strlen("%s", data->searchstr);
3286  screen_init(&ss, width, 1, 0);
3287  screen_write_start(&ctx, &ss);
3288  screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
3289  data->searchstr);
3290  screen_write_stop(&ctx);
3291  ssp = &ss;
3292  } else
3293  width = screen_size_x(ssp);
3294 
3295  cis = window_copy_is_lowercase(data->searchstr);
3296 
3297  if (regex) {
3298  sbuf = xmalloc(ssize);
3299  sbuf[0] = '\0';
3300  sbuf = window_copy_stringify(ssp->grid, 0, 0, ssp->grid->sx,
3301  sbuf, &ssize);
3302  if (cis)
3303  cflags |= REG_ICASE;
3304  if (regcomp(&reg, sbuf, cflags) != 0) {
3305  free(sbuf);
3306  return (0);
3307  }
3308  free(sbuf);
3309  }
3310  tstart = get_timer();
3311 
3312  if (visible_only)
3313  window_copy_visible_lines(data, &start, &end);
3314  else {
3315  start = 0;
3316  end = gd->hsize + gd->sy;
3318  }
3319 
3320 again:
3321  free(data->searchmark);
3322  data->searchmark = xcalloc(gd->sx, gd->sy);
3323  data->searchgen = 1;
3324 
3325  for (py = start; py < end; py++) {
3326  px = 0;
3327  for (;;) {
3328  if (regex) {
3329  found = window_copy_search_lr_regex(gd,
3330  &px, &width, py, px, gd->sx, &reg);
3331  if (!found)
3332  break;
3333  } else {
3334  found = window_copy_search_lr(gd, ssp->grid,
3335  &px, py, px, gd->sx, cis);
3336  if (!found)
3337  break;
3338  }
3339  nfound++;
3340 
3341  if (window_copy_search_mark_at(data, px, py, &b) == 0) {
3342  if (b + width > gd->sx * gd->sy)
3343  width = (gd->sx * gd->sy) - b;
3344  for (i = b; i < b + width; i++) {
3345  if (data->searchmark[i] != 0)
3346  continue;
3347  data->searchmark[i] = data->searchgen;
3348  }
3349  if (data->searchgen == UCHAR_MAX)
3350  data->searchgen = 1;
3351  else
3352  data->searchgen++;
3353  }
3354  px += width;
3355  }
3356 
3357  t = get_timer();
3358  if (t - tstart > WINDOW_COPY_SEARCH_TIMEOUT) {
3359  data->timeout = 1;
3360  break;
3361  }
3362  if (stop != 0 && t > stop) {
3363  stopped = 1;
3364  break;
3365  }
3366  }
3367  if (data->timeout) {
3369  goto out;
3370  }
3371 
3372  if (stopped && stop != 0) {
3373  /* Try again but just the visible context. */
3374  window_copy_visible_lines(data, &start, &end);
3375  stop = 0;
3376  goto again;
3377  }
3378 
3379  if (!visible_only) {
3380  if (stopped) {
3381  if (nfound > 1000)
3382  data->searchcount = 1000;
3383  else if (nfound > 100)
3384  data->searchcount = 100;
3385  else if (nfound > 10)
3386  data->searchcount = 10;
3387  else
3388  data->searchcount = -1;
3389  data->searchmore = 1;
3390  } else {
3391  data->searchcount = nfound;
3392  data->searchmore = 0;
3393  }
3394  }
3395 
3396 out:
3397  if (ssp == &ss)
3398  screen_free(&ss);
3399  if (regex)
3400  regfree(&reg);
3401  return (1);
3402 }
3403 
3404 static void
3406 {
3407  struct window_copy_mode_data *data = wme->data;
3408 
3409  free(data->searchmark);
3410  data->searchmark = NULL;
3411 }
3412 
3413 static int
3415 {
3416  return (window_copy_search(wme, 0, regex));
3417 }
3418 
3419 static int
3421 {
3422  return (window_copy_search(wme, 1, regex));
3423 }
3424 
3425 static void
3426 window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
3427 {
3428  struct window_copy_mode_data *data = wme->data;
3429  const char *errstr;
3430  int lineno;
3431 
3432  lineno = strtonum(linestr, -1, INT_MAX, &errstr);
3433  if (errstr != NULL)
3434  return;
3435  if (lineno < 0 || (u_int)lineno > screen_hsize(data->backing))
3436  lineno = screen_hsize(data->backing);
3437 
3438  data->oy = lineno;
3439  window_copy_update_selection(wme, 1, 0);
3441 }
3442 
3443 static void
3445  u_int *start, u_int *end)
3446 {
3447  struct grid *gd = data->backing->grid;
3448  u_int last = (gd->sy * gd->sx) - 1;
3449  u_char mark = data->searchmark[at];
3450 
3451  *start = *end = at;
3452  while (*start != 0 && data->searchmark[*start] == mark)
3453  (*start)--;
3454  if (data->searchmark[*start] != mark)
3455  (*start)++;
3456  while (*end != last && data->searchmark[*end] == mark)
3457  (*end)++;
3458  if (data->searchmark[*end] != mark)
3459  (*end)--;
3460 }
3461 
3462 static char *
3464 {
3465  struct grid *gd = data->backing->grid;
3466  struct grid_cell gc;
3467  u_int at, start, end, cy, px, py;
3468  u_int sx = screen_size_x(data->backing);
3469  char *buf = NULL;
3470  size_t len = 0;
3471 
3472  if (data->searchmark == NULL)
3473  return (NULL);
3474 
3475  cy = screen_hsize(data->backing) - data->oy + data->cy;
3476  if (window_copy_search_mark_at(data, data->cx, cy, &at) != 0)
3477  return (NULL);
3478  if (data->searchmark[at] == 0) {
3479  /* Allow one position after the match. */
3480  if (at == 0 || data->searchmark[--at] == 0)
3481  return (NULL);
3482  }
3483  window_copy_match_start_end(data, at, &start, &end);
3484 
3485  /*
3486  * Cells will not be set in the marked array unless they are valid text
3487  * and wrapping will be taken care of, so we can just copy.
3488  */
3489  for (at = start; at <= end; at++) {
3490  py = at / sx;
3491  px = at - (py * sx);
3492 
3493  grid_get_cell(gd, px, gd->hsize + py - data->oy, &gc);
3494  buf = xrealloc(buf, len + gc.data.size + 1);
3495  memcpy(buf + len, gc.data.data, gc.data.size);
3496  len += gc.data.size;
3497  }
3498  if (len != 0)
3499  buf[len] = '\0';
3500  return (buf);
3501 }
3502 
3503 static void
3504 window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
3505  struct grid_cell *gc, const struct grid_cell *mgc,
3506  const struct grid_cell *cgc, const struct grid_cell *mkgc)
3507 {
3508  struct window_pane *wp = wme->wp;
3509  struct window_copy_mode_data *data = wme->data;
3510  u_int mark, start, end, cy, cursor, current;
3511  int inv = 0, found = 0;
3512  int keys;
3513 
3514  if (data->showmark && fy == data->my) {
3515  gc->attr = mkgc->attr;
3516  if (fx == data->mx)
3517  inv = 1;
3518  if (inv) {
3519  gc->fg = mkgc->bg;
3520  gc->bg = mkgc->fg;
3521  }
3522  else {
3523  gc->fg = mkgc->fg;
3524  gc->bg = mkgc->bg;
3525  }
3526  }
3527 
3528  if (data->searchmark == NULL)
3529  return;
3530 
3531  if (window_copy_search_mark_at(data, fx, fy, &current) != 0)
3532  return;
3533  mark = data->searchmark[current];
3534  if (mark == 0)
3535  return;
3536 
3537  cy = screen_hsize(data->backing) - data->oy + data->cy;
3538  if (window_copy_search_mark_at(data, data->cx, cy, &cursor) == 0) {
3539  keys = options_get_number(wp->window->options, "mode-keys");
3540  if (cursor != 0 &&
3541  keys == MODEKEY_EMACS &&
3542  data->searchdirection) {
3543  if (data->searchmark[cursor - 1] == mark) {
3544  cursor--;
3545  found = 1;
3546  }
3547  } else if (data->searchmark[cursor] == mark)
3548  found = 1;
3549  if (found) {
3550  window_copy_match_start_end(data, cursor, &start, &end);
3551  if (current >= start && current <= end) {
3552  gc->attr = cgc->attr;
3553  if (inv) {
3554  gc->fg = cgc->bg;
3555  gc->bg = cgc->fg;
3556  }
3557  else {
3558  gc->fg = cgc->fg;
3559  gc->bg = cgc->bg;
3560  }
3561  return;
3562  }
3563  }
3564  }
3565 
3566  gc->attr = mgc->attr;
3567  if (inv) {
3568  gc->fg = mgc->bg;
3569  gc->bg = mgc->fg;
3570  }
3571  else {
3572  gc->fg = mgc->fg;
3573  gc->bg = mgc->bg;
3574  }
3575 }
3576 
3577 static void
3579  struct screen_write_ctx *ctx, u_int py, u_int fy, u_int nx,
3580  const struct grid_cell *mgc, const struct grid_cell *cgc,
3581  const struct grid_cell *mkgc)
3582 {
3583  struct window_copy_mode_data *data = wme->data;
3584  struct grid *gd = data->backing->grid;
3585  struct grid_cell gc;
3586  u_int fx;
3587 
3588  screen_write_cursormove(ctx, 0, py, 0);
3589  for (fx = 0; fx < nx; fx++) {
3590  grid_get_cell(gd, fx, fy, &gc);
3591  if (fx + gc.data.width <= nx) {
3592  window_copy_update_style(wme, fx, fy, &gc, mgc, cgc,
3593  mkgc);
3594  screen_write_cell(ctx, &gc);
3595  }
3596  }
3597 }
3598 
3599 static void
3601  struct screen_write_ctx *ctx, u_int py)
3602 {
3603  struct window_pane *wp = wme->wp;
3604  struct window_copy_mode_data *data = wme->data;
3605  struct screen *s = &data->screen;
3606  struct options *oo = wp->window->options;
3607  struct grid_cell gc, mgc, cgc, mkgc;
3608  char hdr[512];
3609  size_t size = 0;
3610  u_int hsize = screen_hsize(data->backing);
3611 
3612  style_apply(&gc, oo, "mode-style", NULL);
3613  gc.flags |= GRID_FLAG_NOPALETTE;
3614  style_apply(&mgc, oo, "copy-mode-match-style", NULL);
3615  mgc.flags |= GRID_FLAG_NOPALETTE;
3616  style_apply(&cgc, oo, "copy-mode-current-match-style", NULL);
3617  cgc.flags |= GRID_FLAG_NOPALETTE;
3618  style_apply(&mkgc, oo, "copy-mode-mark-style", NULL);
3619  mkgc.flags |= GRID_FLAG_NOPALETTE;
3620 
3621  if (py == 0 && s->rupper < s->rlower && !data->hide_position) {
3622  if (data->searchmark == NULL) {
3623  if (data->timeout) {
3624  size = xsnprintf(hdr, sizeof hdr,
3625  "(timed out) [%u/%u]", data->oy, hsize);
3626  } else {
3627  size = xsnprintf(hdr, sizeof hdr,
3628  "[%u/%u]", data->oy, hsize);
3629  }
3630  } else {
3631  if (data->searchcount == -1) {
3632  size = xsnprintf(hdr, sizeof hdr,
3633  "[%u/%u]", data->oy, hsize);
3634  } else {
3635  size = xsnprintf(hdr, sizeof hdr,
3636  "(%d%s results) [%u/%u]", data->searchcount,
3637  data->searchmore ? "+" : "", data->oy,
3638  hsize);
3639  }
3640  }
3641  if (size > screen_size_x(s))
3642  size = screen_size_x(s);
3643  screen_write_cursormove(ctx, screen_size_x(s) - size, 0, 0);
3644  screen_write_puts(ctx, &gc, "%s", hdr);
3645  } else
3646  size = 0;
3647 
3648  if (size < screen_size_x(s)) {
3649  window_copy_write_one(wme, ctx, py, hsize - data->oy + py,
3650  screen_size_x(s) - size, &mgc, &cgc, &mkgc);
3651  }
3652 
3653  if (py == data->cy && data->cx == screen_size_x(s)) {
3654  screen_write_cursormove(ctx, screen_size_x(s) - 1, py, 0);
3656  }
3657 }
3658 
3659 static void
3661  struct screen_write_ctx *ctx, u_int py, u_int ny)
3662 {
3663  u_int yy;
3664 
3665  for (yy = py; yy < py + ny; yy++)
3666  window_copy_write_line(wme, ctx, py);
3667 }
3668 
3669 static void
3671 {
3672  struct window_copy_mode_data *data = wme->data;
3673  struct grid *gd = data->backing->grid;
3674  u_int new_y, start, end;
3675 
3676  new_y = data->cy;
3677  if (old_y <= new_y) {
3678  start = old_y;
3679  end = new_y;
3680  } else {
3681  start = new_y;
3682  end = old_y;
3683  }
3684 
3685  /*
3686  * In word selection mode the first word on the line below the cursor
3687  * might be selected, so add this line to the redraw area.
3688  */
3689  if (data->selflag == SEL_WORD) {
3690  /* Last grid line in data coordinates. */
3691  if (end < gd->sy + data->oy - 1)
3692  end++;
3693  }
3694  window_copy_redraw_lines(wme, start, end - start + 1);
3695 }
3696 
3697 static void
3698 window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
3699 {
3700  struct window_pane *wp = wme->wp;
3701  struct window_copy_mode_data *data = wme->data;
3702  struct screen_write_ctx ctx;
3703  u_int i;
3704 
3705  screen_write_start_pane(&ctx, wp, NULL);
3706  for (i = py; i < py + ny; i++)
3707  window_copy_write_line(wme, &ctx, i);
3708  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
3709  screen_write_stop(&ctx);
3710 }
3711 
3712 static void
3714 {
3715  struct window_copy_mode_data *data = wme->data;
3716 
3718 }
3719 
3720 static void
3722  int no_reset)
3723 {
3724  struct window_copy_mode_data *data = wme->data;
3725  u_int xx, yy;
3726 
3727  xx = data->cx;
3728  yy = screen_hsize(data->backing) + data->cy - data->oy;
3729  switch (data->selflag) {
3730  case SEL_WORD:
3731  if (no_reset)
3732  break;
3733  begin = 0;
3734  if (data->dy > yy || (data->dy == yy && data->dx > xx)) {
3735  /* Right to left selection. */
3737  &xx, &yy);
3738  begin = 1;
3739 
3740  /* Reset the end. */
3741  data->endselx = data->endselrx;
3742  data->endsely = data->endselry;
3743  } else {
3744  /* Left to right selection. */
3745  if (xx >= window_copy_find_length(wme, yy) ||
3746  !window_copy_in_set(wme, xx + 1, yy, data->ws))
3748  data->ws, &xx, &yy);
3749 
3750  /* Reset the start. */
3751  data->selx = data->selrx;
3752  data->sely = data->selry;
3753  }
3754  break;
3755  case SEL_LINE:
3756  if (no_reset)
3757  break;
3758  begin = 0;
3759  if (data->dy > yy) {
3760  /* Right to left selection. */
3761  xx = 0;
3762  begin = 1;
3763 
3764  /* Reset the end. */
3765  data->endselx = data->endselrx;
3766  data->endsely = data->endselry;
3767  } else {
3768  /* Left to right selection. */
3769  if (yy < data->endselry)
3770  yy = data->endselry;
3771  xx = window_copy_find_length(wme, yy);
3772 
3773  /* Reset the start. */
3774  data->selx = data->selrx;
3775  data->sely = data->selry;
3776  }
3777  break;
3778  case SEL_CHAR:
3779  break;
3780  }
3781  if (begin) {
3782  data->selx = xx;
3783  data->sely = yy;
3784  } else {
3785  data->endselx = xx;
3786  data->endsely = yy;
3787  }
3788 }
3789 
3790 static void
3792 {
3793  struct window_copy_mode_data *data = wme->data;
3794 
3795  switch (data->cursordrag) {
3796  case CURSORDRAG_ENDSEL:
3797  window_copy_synchronize_cursor_end(wme, 0, no_reset);
3798  break;
3799  case CURSORDRAG_SEL:
3800  window_copy_synchronize_cursor_end(wme, 1, no_reset);
3801  break;
3802  case CURSORDRAG_NONE:
3803  break;
3804  }
3805 }
3806 
3807 static void
3809 {
3810  struct window_pane *wp = wme->wp;
3811  struct window_copy_mode_data *data = wme->data;
3812  struct screen *s = &data->screen;
3813  struct screen_write_ctx ctx;
3814  u_int old_cx, old_cy;
3815 
3816  old_cx = data->cx; old_cy = data->cy;
3817  data->cx = cx; data->cy = cy;
3818  if (old_cx == screen_size_x(s))
3819  window_copy_redraw_lines(wme, old_cy, 1);
3820  if (data->cx == screen_size_x(s))
3821  window_copy_redraw_lines(wme, data->cy, 1);
3822  else {
3823  screen_write_start_pane(&ctx, wp, NULL);
3824  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
3825  screen_write_stop(&ctx);
3826  }
3827 }
3828 
3829 static void
3831 {
3832  struct window_copy_mode_data *data = wme->data;
3833 
3834  data->selx = data->cx;
3835  data->sely = screen_hsize(data->backing) + data->cy - data->oy;
3836 
3837  data->endselx = data->selx;
3838  data->endsely = data->sely;
3839 
3840  data->cursordrag = CURSORDRAG_ENDSEL;
3841 
3842  window_copy_set_selection(wme, 1, 0);
3843 }
3844 
3845 static int
3847  u_int *sely)
3848 {
3849  struct window_copy_mode_data *data = wme->data;
3850  struct screen *s = &data->screen;
3851  u_int sx, sy, ty;
3852  int relpos;
3853 
3854  sx = *selx;
3855  sy = *sely;
3856 
3857  ty = screen_hsize(data->backing) - data->oy;
3858  if (sy < ty) {
3859  relpos = WINDOW_COPY_REL_POS_ABOVE;
3860  if (!data->rectflag)
3861  sx = 0;
3862  sy = 0;
3863  } else if (sy > ty + screen_size_y(s) - 1) {
3864  relpos = WINDOW_COPY_REL_POS_BELOW;
3865  if (!data->rectflag)
3866  sx = screen_size_x(s) - 1;
3867  sy = screen_size_y(s) - 1;
3868  } else {
3870  sy -= ty;
3871  }
3872 
3873  *selx = sx;
3874  *sely = sy;
3875  return (relpos);
3876 }
3877 
3878 static int
3880  int no_reset)
3881 {
3882  struct window_copy_mode_data *data = wme->data;
3883  struct screen *s = &data->screen;
3884 
3885  if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
3886  return (0);
3887  return (window_copy_set_selection(wme, may_redraw, no_reset));
3888 }
3889 
3890 static int
3891 window_copy_set_selection(struct window_mode_entry *wme, int may_redraw,
3892  int no_reset)
3893 {
3894  struct window_pane *wp = wme->wp;
3895  struct window_copy_mode_data *data = wme->data;
3896  struct screen *s = &data->screen;
3897  struct options *oo = wp->window->options;
3898  struct grid_cell gc;
3899  u_int sx, sy, cy, endsx, endsy;
3900  int startrelpos, endrelpos;
3901 
3902  window_copy_synchronize_cursor(wme, no_reset);
3903 
3904  /* Adjust the selection. */
3905  sx = data->selx;
3906  sy = data->sely;
3907  startrelpos = window_copy_adjust_selection(wme, &sx, &sy);
3908 
3909  /* Adjust the end of selection. */
3910  endsx = data->endselx;
3911  endsy = data->endsely;
3912  endrelpos = window_copy_adjust_selection(wme, &endsx, &endsy);
3913 
3914  /* Selection is outside of the current screen */
3915  if (startrelpos == endrelpos &&
3916  startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) {
3918  return (0);
3919  }
3920 
3921  /* Set colours and selection. */
3922  style_apply(&gc, oo, "mode-style", NULL);
3923  gc.flags |= GRID_FLAG_NOPALETTE;
3924  screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
3925  data->modekeys, &gc);
3926 
3927  if (data->rectflag && may_redraw) {
3928  /*
3929  * Can't rely on the caller to redraw the right lines for
3930  * rectangle selection - find the highest line and the number
3931  * of lines, and redraw just past that in both directions
3932  */
3933  cy = data->cy;
3934  if (data->cursordrag == CURSORDRAG_ENDSEL) {
3935  if (sy < cy)
3936  window_copy_redraw_lines(wme, sy, cy - sy + 1);
3937  else
3938  window_copy_redraw_lines(wme, cy, sy - cy + 1);
3939  } else {
3940  if (endsy < cy) {
3941  window_copy_redraw_lines(wme, endsy,
3942  cy - endsy + 1);
3943  } else {
3944  window_copy_redraw_lines(wme, cy,
3945  endsy - cy + 1);
3946  }
3947  }
3948  }
3949 
3950  return (1);
3951 }
3952 
3953 static void *
3955 {
3956  struct window_pane *wp = wme->wp;
3957  struct window_copy_mode_data *data = wme->data;
3958  struct screen *s = &data->screen;
3959  char *buf;
3960  size_t off;
3961  u_int i, xx, yy, sx, sy, ex, ey, ey_last;
3962  u_int firstsx, lastex, restex, restsx, selx;
3963  int keys;
3964 
3965  if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) {
3966  buf = window_copy_match_at_cursor(data);
3967  if (buf != NULL)
3968  *len = strlen(buf);
3969  else
3970  *len = 0;
3971  return (buf);
3972  }
3973 
3974  buf = xmalloc(1);
3975  off = 0;
3976 
3977  *buf = '\0';
3978 
3979  /*
3980  * The selection extends from selx,sely to (adjusted) cx,cy on
3981  * the base screen.
3982  */
3983 
3984  /* Find start and end. */
3985  xx = data->endselx;
3986  yy = data->endsely;
3987  if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
3988  sx = xx; sy = yy;
3989  ex = data->selx; ey = data->sely;
3990  } else {
3991  sx = data->selx; sy = data->sely;
3992  ex = xx; ey = yy;
3993  }
3994 
3995  /* Trim ex to end of line. */
3996  ey_last = window_copy_find_length(wme, ey);
3997  if (ex > ey_last)
3998  ex = ey_last;
3999 
4000  /*
4001  * Deal with rectangle-copy if necessary; four situations: start of
4002  * first line (firstsx), end of last line (lastex), start (restsx) and
4003  * end (restex) of all other lines.
4004  */
4005  xx = screen_size_x(s);
4006 
4007  /*
4008  * Behave according to mode-keys. If it is emacs, copy like emacs,
4009  * keeping the top-left-most character, and dropping the
4010  * bottom-right-most, regardless of copy direction. If it is vi, also
4011  * keep bottom-right-most character.
4012  */
4013  keys = options_get_number(wp->window->options, "mode-keys");
4014  if (data->rectflag) {
4015  /*
4016  * Need to ignore the column with the cursor in it, which for
4017  * rectangular copy means knowing which side the cursor is on.
4018  */
4019  if (data->cursordrag == CURSORDRAG_ENDSEL)
4020  selx = data->selx;
4021  else
4022  selx = data->endselx;
4023  if (selx < data->cx) {
4024  /* Selection start is on the left. */
4025  if (keys == MODEKEY_EMACS) {
4026  lastex = data->cx;
4027  restex = data->cx;
4028  }
4029  else {
4030  lastex = data->cx + 1;
4031  restex = data->cx + 1;
4032  }
4033  firstsx = selx;
4034  restsx = selx;
4035  } else {
4036  /* Cursor is on the left. */
4037  lastex = selx + 1;
4038  restex = selx + 1;
4039  firstsx = data->cx;
4040  restsx = data->cx;
4041  }
4042  } else {
4043  if (keys == MODEKEY_EMACS)
4044  lastex = ex;
4045  else
4046  lastex = ex + 1;
4047  restex = xx;
4048  firstsx = sx;
4049  restsx = 0;
4050  }
4051 
4052  /* Copy the lines. */
4053  for (i = sy; i <= ey; i++) {
4054  window_copy_copy_line(wme, &buf, &off, i,
4055  (i == sy ? firstsx : restsx),
4056  (i == ey ? lastex : restex));
4057  }
4058 
4059  /* Don't bother if no data. */
4060  if (off == 0) {
4061  free(buf);
4062  *len = 0;
4063  return (NULL);
4064  }
4065  /* Remove final \n (unless at end in vi mode). */
4066  if (keys == MODEKEY_EMACS || lastex <= ey_last) {
4067  if (~grid_get_line(data->backing->grid, ey)->flags &
4068  GRID_LINE_WRAPPED || lastex != ey_last)
4069  off -= 1;
4070  }
4071  *len = off;
4072  return (buf);
4073 }
4074 
4075 static void
4076 window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
4077  void *buf, size_t len)
4078 {
4079  struct window_pane *wp = wme->wp;
4080  struct screen_write_ctx ctx;
4081 
4082  if (options_get_number(global_options, "set-clipboard") != 0) {
4083  screen_write_start_pane(&ctx, wp, NULL);
4084  screen_write_setselection(&ctx, buf, len);
4085  screen_write_stop(&ctx);
4086  notify_pane("pane-set-clipboard", wp);
4087  }
4088 
4089  paste_add(prefix, buf, len);
4090 }
4091 
4092 static void *
4094  const char *cmd, size_t *len)
4095 {
4096  void *buf;
4097  struct job *job;
4098 
4099  buf = window_copy_get_selection(wme, len);
4100  if (cmd == NULL || *cmd == '\0')
4101  cmd = options_get_string(global_options, "copy-command");
4102  if (cmd != NULL && *cmd != '\0') {
4103  job = job_run(cmd, 0, NULL, s, NULL, NULL, NULL, NULL, NULL,
4104  JOB_NOWAIT, -1, -1);
4105  bufferevent_write(job_get_event(job), buf, *len);
4106  }
4107  return (buf);
4108 }
4109 
4110 static void
4112  const char *cmd)
4113 {
4114  size_t len;
4115 
4116  window_copy_pipe_run(wme, s, cmd, &len);
4117 }
4118 
4119 static void
4121  const char *prefix, const char *cmd)
4122 {
4123  void *buf;
4124  size_t len;
4125 
4126  buf = window_copy_pipe_run(wme, s, cmd, &len);
4127  if (buf != NULL)
4128  window_copy_copy_buffer(wme, prefix, buf, len);
4129 }
4130 
4131 static void
4132 window_copy_copy_selection(struct window_mode_entry *wme, const char *prefix)
4133 {
4134  char *buf;
4135  size_t len;
4136 
4137  buf = window_copy_get_selection(wme, &len);
4138  if (buf != NULL)
4139  window_copy_copy_buffer(wme, prefix, buf, len);
4140 }
4141 
4142 static void
4144 {
4145  struct window_pane *wp = wme->wp;
4146  char *buf;
4147  struct paste_buffer *pb;
4148  const char *bufdata, *bufname = NULL;
4149  size_t len, bufsize;
4150  struct screen_write_ctx ctx;
4151 
4152  buf = window_copy_get_selection(wme, &len);
4153  if (buf == NULL)
4154  return;
4155 
4156  if (options_get_number(global_options, "set-clipboard") != 0) {
4157  screen_write_start_pane(&ctx, wp, NULL);
4158  screen_write_setselection(&ctx, buf, len);
4159  screen_write_stop(&ctx);
4160  notify_pane("pane-set-clipboard", wp);
4161  }
4162 
4163  pb = paste_get_top(&bufname);
4164  if (pb != NULL) {
4165  bufdata = paste_buffer_data(pb, &bufsize);
4166  buf = xrealloc(buf, len + bufsize);
4167  memmove(buf + bufsize, buf, len);
4168  memcpy(buf, bufdata, bufsize);
4169  len += bufsize;
4170  }
4171  if (paste_set(buf, len, bufname, NULL) != 0)
4172  free(buf);
4173 }
4174 
4175 static void
4176 window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
4177  u_int sy, u_int sx, u_int ex)
4178 {
4179  struct window_copy_mode_data *data = wme->data;
4180  struct grid *gd = data->backing->grid;
4181  struct grid_cell gc;
4182  struct grid_line *gl;
4183  struct utf8_data ud;
4184  u_int i, xx, wrapped = 0;
4185  const char *s;
4186 
4187  if (sx > ex)
4188  return;
4189 
4190  /*
4191  * Work out if the line was wrapped at the screen edge and all of it is
4192  * on screen.
4193  */
4194  gl = grid_get_line(gd, sy);
4195  if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
4196  wrapped = 1;
4197 
4198  /* If the line was wrapped, don't strip spaces (use the full length). */
4199  if (wrapped)
4200  xx = gl->cellsize;
4201  else
4202  xx = window_copy_find_length(wme, sy);
4203  if (ex > xx)
4204  ex = xx;
4205  if (sx > xx)
4206  sx = xx;
4207 
4208  if (sx < ex) {
4209  for (i = sx; i < ex; i++) {
4210  grid_get_cell(gd, i, sy, &gc);
4211  if (gc.flags & GRID_FLAG_PADDING)
4212  continue;
4213  utf8_copy(&ud, &gc.data);
4214  if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
4215  s = tty_acs_get(NULL, ud.data[0]);
4216  if (s != NULL && strlen(s) <= sizeof ud.data) {
4217  ud.size = strlen(s);
4218  memcpy(ud.data, s, ud.size);
4219  }
4220  }
4221 
4222  *buf = xrealloc(*buf, (*off) + ud.size);
4223  memcpy(*buf + *off, ud.data, ud.size);
4224  *off += ud.size;
4225  }
4226  }
4227 
4228  /* Only add a newline if the line wasn't wrapped. */
4229  if (!wrapped || ex != xx) {
4230  *buf = xrealloc(*buf, (*off) + 1);
4231  (*buf)[(*off)++] = '\n';
4232  }
4233 }
4234 
4235 static void
4237 {
4238  struct window_copy_mode_data *data = wme->data;
4239  u_int px, py;
4240 
4242 
4243  data->cursordrag = CURSORDRAG_NONE;
4244  data->lineflag = LINE_SEL_NONE;
4245  data->selflag = SEL_CHAR;
4246 
4247  py = screen_hsize(data->backing) + data->cy - data->oy;
4248  px = window_copy_find_length(wme, py);
4249  if (data->cx > px)
4250  window_copy_update_cursor(wme, px, data->cy);
4251 }
4252 
4253 static int
4254 window_copy_in_set(struct window_mode_entry *wme, u_int px, u_int py,
4255  const char *set)
4256 {
4257  struct window_copy_mode_data *data = wme->data;
4258  struct grid_cell gc;
4259 
4260  grid_get_cell(data->backing->grid, px, py, &gc);
4261  if (gc.flags & GRID_FLAG_PADDING)
4262  return (0);
4263  return (utf8_cstrhas(set, &gc.data));
4264 }
4265 
4266 static u_int
4268 {
4269  struct window_copy_mode_data *data = wme->data;
4270 
4271  return (grid_line_length(data->backing->grid, py));
4272 }
4273 
4274 static void
4276 {
4277  struct window_copy_mode_data *data = wme->data;
4278  struct screen *back_s = data->backing;
4279  struct grid_reader gr;
4280  u_int px, py, oldy, hsize;
4281 
4282  px = data->cx;
4283  hsize = screen_hsize(back_s);
4284  py = hsize + data->cy - data->oy;
4285  oldy = data->cy;
4286 
4287  grid_reader_start(&gr, back_s->grid, px, py);
4289  grid_reader_get_cursor(&gr, &px, &py);
4290  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
4291 }
4292 
4293 static void
4295 {
4296  struct window_copy_mode_data *data = wme->data;
4297  struct screen *back_s = data->backing;
4298  struct grid_reader gr;
4299  u_int px, py, oldy, hsize;
4300 
4301  px = data->cx;
4302  hsize = screen_hsize(back_s);
4303  py = hsize + data->cy - data->oy;
4304  oldy = data->cy;
4305 
4306  grid_reader_start(&gr, back_s->grid, px, py);
4308  grid_reader_get_cursor(&gr, &px, &py);
4309  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
4310 }
4311 
4312 static void
4314 {
4315  struct window_copy_mode_data *data = wme->data;
4316  struct screen *back_s = data->backing;
4317  struct grid_reader gr;
4318  u_int px, py, oldy, hsize;
4319 
4320  px = data->cx;
4321  hsize = screen_hsize(back_s);
4322  py = hsize + data->cy - data->oy;
4323  oldy = data->cy;
4324 
4325  grid_reader_start(&gr, back_s->grid, px, py);
4326  if (data->screen.sel != NULL && data->rectflag)
4327  grid_reader_cursor_end_of_line(&gr, 1, 1);
4328  else
4329  grid_reader_cursor_end_of_line(&gr, 1, 0);
4330  grid_reader_get_cursor(&gr, &px, &py);
4331  window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
4332  data->oy, oldy, px, py, 0);
4333 }
4334 
4335 static void
4337 {
4338  struct window_copy_mode_data *data = wme->data;
4339  struct screen *s = &data->screen;
4340  u_int selx, sely, cy, yy, hsize;
4341 
4342  if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
4343  return;
4344 
4345  if (data->lineflag == LINE_SEL_LEFT_RIGHT)
4346  data->lineflag = LINE_SEL_RIGHT_LEFT;
4347  else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
4348  data->lineflag = LINE_SEL_LEFT_RIGHT;
4349 
4350  switch (data->cursordrag) {
4351  case CURSORDRAG_NONE:
4352  case CURSORDRAG_SEL:
4353  data->cursordrag = CURSORDRAG_ENDSEL;
4354  break;
4355  case CURSORDRAG_ENDSEL:
4356  data->cursordrag = CURSORDRAG_SEL;
4357  break;
4358  }
4359 
4360  selx = data->endselx;
4361  sely = data->endsely;
4362  if (data->cursordrag == CURSORDRAG_SEL) {
4363  selx = data->selx;
4364  sely = data->sely;
4365  }
4366 
4367  cy = data->cy;
4368  yy = screen_hsize(data->backing) + data->cy - data->oy;
4369 
4370  data->cx = selx;
4371 
4372  hsize = screen_hsize(data->backing);
4373  if (sely < hsize - data->oy) { /* above */
4374  data->oy = hsize - sely;
4375  data->cy = 0;
4376  } else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */
4377  data->oy = hsize - sely + screen_size_y(s) - 1;
4378  data->cy = screen_size_y(s) - 1;
4379  } else
4380  data->cy = cy + sely - yy;
4381 
4382  window_copy_update_selection(wme, 1, 1);
4384 }
4385 
4386 static void
4388 {
4389  struct window_copy_mode_data *data = wme->data;
4390  struct screen *back_s = data->backing;
4391  struct grid_reader gr;
4392  u_int px, py, oldy, hsize;
4393 
4394  px = data->cx;
4395  hsize = screen_hsize(back_s);
4396  py = hsize + data->cy - data->oy;
4397  oldy = data->cy;
4398 
4399  grid_reader_start(&gr, back_s->grid, px, py);
4400  grid_reader_cursor_left(&gr, 1);
4401  grid_reader_get_cursor(&gr, &px, &py);
4402  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
4403 }
4404 
4405 static void
4407 {
4408  struct window_copy_mode_data *data = wme->data;
4409  struct screen *back_s = data->backing;
4410  struct grid_reader gr;
4411  u_int px, py, oldy, hsize;
4412 
4413  px = data->cx;
4414  hsize = screen_hsize(back_s);
4415  py = hsize + data->cy - data->oy;
4416  oldy = data->cy;
4417 
4418  grid_reader_start(&gr, back_s->grid, px, py);
4419  grid_reader_cursor_right(&gr, 1, all);
4420  grid_reader_get_cursor(&gr, &px, &py);
4421  window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
4422  data->oy, oldy, px, py, 0);
4423 }
4424 
4425 static void
4426 window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
4427 {
4428  struct window_copy_mode_data *data = wme->data;
4429  struct screen *s = &data->screen;
4430  u_int ox, oy, px, py;
4431  int norectsel;
4432 
4433  norectsel = data->screen.sel == NULL || !data->rectflag;
4434  oy = screen_hsize(data->backing) + data->cy - data->oy;
4435  ox = window_copy_find_length(wme, oy);
4436  if (norectsel && data->cx != ox) {
4437  data->lastcx = data->cx;
4438  data->lastsx = ox;
4439  }
4440 
4441  if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
4442  window_copy_other_end(wme);
4443 
4444  if (scroll_only || data->cy == 0) {
4445  if (norectsel)
4446  data->cx = data->lastcx;
4447  window_copy_scroll_down(wme, 1);
4448  if (scroll_only) {
4449  if (data->cy == screen_size_y(s) - 1)
4450  window_copy_redraw_lines(wme, data->cy, 1);
4451  else
4452  window_copy_redraw_lines(wme, data->cy, 2);
4453  }
4454  } else {
4455  if (norectsel) {
4456  window_copy_update_cursor(wme, data->lastcx,
4457  data->cy - 1);
4458  } else
4459  window_copy_update_cursor(wme, data->cx, data->cy - 1);
4460  if (window_copy_update_selection(wme, 1, 0)) {
4461  if (data->cy == screen_size_y(s) - 1)
4462  window_copy_redraw_lines(wme, data->cy, 1);
4463  else
4464  window_copy_redraw_lines(wme, data->cy, 2);
4465  }
4466  }
4467 
4468  if (norectsel) {
4469  py = screen_hsize(data->backing) + data->cy - data->oy;
4470  px = window_copy_find_length(wme, py);
4471  if ((data->cx >= data->lastsx && data->cx != px) ||
4472  data->cx > px)
4473  {
4474  window_copy_update_cursor(wme, px, data->cy);
4475  if (window_copy_update_selection(wme, 1, 0))
4476  window_copy_redraw_lines(wme, data->cy, 1);
4477  }
4478  }
4479 
4480  if (data->lineflag == LINE_SEL_LEFT_RIGHT)
4481  {
4482  py = screen_hsize(data->backing) + data->cy - data->oy;
4483  if (data->rectflag)
4484  px = screen_size_x(data->backing);
4485  else
4486  px = window_copy_find_length(wme, py);
4487  window_copy_update_cursor(wme, px, data->cy);
4488  if (window_copy_update_selection(wme, 1, 0))
4489  window_copy_redraw_lines(wme, data->cy, 1);
4490  }
4491  else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
4492  {
4493  window_copy_update_cursor(wme, 0, data->cy);
4494  if (window_copy_update_selection(wme, 1, 0))
4495  window_copy_redraw_lines(wme, data->cy, 1);
4496  }
4497 }
4498 
4499 static void
4500 window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
4501 {
4502  struct window_copy_mode_data *data = wme->data;
4503  struct screen *s = &data->screen;
4504  u_int ox, oy, px, py;
4505  int norectsel;
4506 
4507  norectsel = data->screen.sel == NULL || !data->rectflag;
4508  oy = screen_hsize(data->backing) + data->cy - data->oy;
4509  ox = window_copy_find_length(wme, oy);
4510  if (norectsel && data->cx != ox) {
4511  data->lastcx = data->cx;
4512  data->lastsx = ox;
4513  }
4514 
4515  if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
4516  window_copy_other_end(wme);
4517 
4518  if (scroll_only || data->cy == screen_size_y(s) - 1) {
4519  if (norectsel)
4520  data->cx = data->lastcx;
4521  window_copy_scroll_up(wme, 1);
4522  if (scroll_only && data->cy > 0)
4523  window_copy_redraw_lines(wme, data->cy - 1, 2);
4524  } else {
4525  if (norectsel) {
4526  window_copy_update_cursor(wme, data->lastcx,
4527  data->cy + 1);
4528  } else
4529  window_copy_update_cursor(wme, data->cx, data->cy + 1);
4530  if (window_copy_update_selection(wme, 1, 0))
4531  window_copy_redraw_lines(wme, data->cy - 1, 2);
4532  }
4533 
4534  if (norectsel) {
4535  py = screen_hsize(data->backing) + data->cy - data->oy;
4536  px = window_copy_find_length(wme, py);
4537  if ((data->cx >= data->lastsx && data->cx != px) ||
4538  data->cx > px)
4539  {
4540  window_copy_update_cursor(wme, px, data->cy);
4541  if (window_copy_update_selection(wme, 1, 0))
4542  window_copy_redraw_lines(wme, data->cy, 1);
4543  }
4544  }
4545 
4546  if (data->lineflag == LINE_SEL_LEFT_RIGHT)
4547  {
4548  py = screen_hsize(data->backing) + data->cy - data->oy;
4549  if (data->rectflag)
4550  px = screen_size_x(data->backing);
4551  else
4552  px = window_copy_find_length(wme, py);
4553  window_copy_update_cursor(wme, px, data->cy);
4554  if (window_copy_update_selection(wme, 1, 0))
4555  window_copy_redraw_lines(wme, data->cy, 1);
4556  }
4557  else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
4558  {
4559  window_copy_update_cursor(wme, 0, data->cy);
4560  if (window_copy_update_selection(wme, 1, 0))
4561  window_copy_redraw_lines(wme, data->cy, 1);
4562  }
4563 }
4564 
4565 static void
4567 {
4568  struct window_copy_mode_data *data = wme->data;
4569  struct screen *back_s = data->backing;
4570  struct grid_reader gr;
4571  u_int px, py, oldy, hsize;
4572 
4573  px = data->cx + 1;
4574  hsize = screen_hsize(back_s);
4575  py = hsize + data->cy - data->oy;
4576  oldy = data->cy;
4577 
4578  grid_reader_start(&gr, back_s->grid, px, py);
4579  if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
4580  grid_reader_get_cursor(&gr, &px, &py);
4582  screen_size_y(back_s), data->oy, oldy, px, py, 0);
4583  }
4584 }
4585 
4586 static void
4588 {
4589  struct window_copy_mode_data *data = wme->data;
4590  struct screen *back_s = data->backing;
4591  struct grid_reader gr;
4592  u_int px, py, oldy, hsize;
4593 
4594  px = data->cx;
4595  hsize = screen_hsize(back_s);
4596  py = hsize + data->cy - data->oy;
4597  oldy = data->cy;
4598 
4599  grid_reader_start(&gr, back_s->grid, px, py);
4600  grid_reader_cursor_left(&gr, 0);
4601  if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
4602  grid_reader_get_cursor(&gr, &px, &py);
4603  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
4604  py);
4605  }
4606 }
4607 
4608 static void
4610 {
4611  struct window_copy_mode_data *data = wme->data;
4612  struct screen *back_s = data->backing;
4613  struct grid_reader gr;
4614  u_int px, py, oldy, hsize;
4615 
4616  px = data->cx + 2;
4617  hsize = screen_hsize(back_s);
4618  py = hsize + data->cy - data->oy;
4619  oldy = data->cy;
4620 
4621  grid_reader_start(&gr, back_s->grid, px, py);
4622  if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
4623  grid_reader_cursor_left(&gr, 1);
4624  grid_reader_get_cursor(&gr, &px, &py);
4626  screen_size_y(back_s), data->oy, oldy, px, py, 0);
4627  }
4628 }
4629 
4630 static void
4632 {
4633  struct window_copy_mode_data *data = wme->data;
4634  struct screen *back_s = data->backing;
4635  struct grid_reader gr;
4636  u_int px, py, oldy, hsize;
4637 
4638  px = data->cx;
4639  hsize = screen_hsize(back_s);
4640  py = hsize + data->cy - data->oy;
4641  oldy = data->cy;
4642 
4643  grid_reader_start(&gr, back_s->grid, px, py);
4644  grid_reader_cursor_left(&gr, 0);
4645  grid_reader_cursor_left(&gr, 0);
4646  if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
4647  grid_reader_cursor_right(&gr, 1, 0);
4648  grid_reader_get_cursor(&gr, &px, &py);
4649  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
4650  py);
4651  }
4652 }
4653 
4654 static void
4656  const char *separators)
4657 {
4658  struct window_copy_mode_data *data = wme->data;
4659  struct screen *back_s = data->backing;
4660  struct grid_reader gr;
4661  u_int px, py, oldy, hsize;
4662 
4663  px = data->cx;
4664  hsize = screen_hsize(back_s);
4665  py = hsize + data->cy - data->oy;
4666  oldy = data->cy;
4667 
4668  grid_reader_start(&gr, back_s->grid, px, py);
4669  grid_reader_cursor_next_word(&gr, separators);
4670  grid_reader_get_cursor(&gr, &px, &py);
4671  window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
4672  data->oy, oldy, px, py, 0);
4673 }
4674 
4675 /* Compute the next place where a word ends. */
4676 static void
4678  const char *separators, u_int *ppx, u_int *ppy)
4679 {
4680  struct window_pane *wp = wme->wp;
4681  struct window_copy_mode_data *data = wme->data;
4682  struct options *oo = wp->window->options;
4683  struct screen *back_s = data->backing;
4684  struct grid_reader gr;
4685  u_int px, py, hsize;
4686  int keys;
4687 
4688  px = data->cx;
4689  hsize = screen_hsize(back_s);
4690  py = hsize + data->cy - data->oy;
4691 
4692  grid_reader_start(&gr, back_s->grid, px, py);
4693  keys = options_get_number(oo, "mode-keys");
4694  if (keys == MODEKEY_VI && !grid_reader_in_set(&gr, separators))
4695  grid_reader_cursor_right(&gr, 0, 0);
4696  grid_reader_cursor_next_word_end(&gr, separators);
4697  if (keys == MODEKEY_VI)
4698  grid_reader_cursor_left(&gr, 1);
4699  grid_reader_get_cursor(&gr, &px, &py);
4700  *ppx = px;
4701  *ppy = py;
4702 }
4703 
4704 /* Move to the next place where a word ends. */
4705 static void
4707  const char *separators, int no_reset)
4708 {
4709  struct window_pane *wp = wme->wp;
4710  struct window_copy_mode_data *data = wme->data;
4711  struct options *oo = wp->window->options;
4712  struct screen *back_s = data->backing;
4713  struct grid_reader gr;
4714  u_int px, py, oldy, hsize;
4715  int keys;
4716 
4717  px = data->cx;
4718  hsize = screen_hsize(back_s);
4719  py = hsize + data->cy - data->oy;
4720  oldy = data->cy;
4721 
4722  grid_reader_start(&gr, back_s->grid, px, py);
4723  keys = options_get_number(oo, "mode-keys");
4724  if (keys == MODEKEY_VI && !grid_reader_in_set(&gr, separators))
4725  grid_reader_cursor_right(&gr, 0, 0);
4726  grid_reader_cursor_next_word_end(&gr, separators);
4727  if (keys == MODEKEY_VI)
4728  grid_reader_cursor_left(&gr, 1);
4729  grid_reader_get_cursor(&gr, &px, &py);
4730  window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
4731  data->oy, oldy, px, py, no_reset);
4732 }
4733 
4734 /* Compute the previous place where a word begins. */
4735 static void
4737  const char *separators, int already, u_int *ppx, u_int *ppy)
4738 {
4739  struct window_copy_mode_data *data = wme->data;
4740  struct screen *back_s = data->backing;
4741  struct grid_reader gr;
4742  u_int px, py, hsize;
4743 
4744  px = data->cx;
4745  hsize = screen_hsize(back_s);
4746  py = hsize + data->cy - data->oy;
4747 
4748  grid_reader_start(&gr, back_s->grid, px, py);
4749  grid_reader_cursor_previous_word(&gr, separators, already);
4750  grid_reader_get_cursor(&gr, &px, &py);
4751  *ppx = px;
4752  *ppy = py;
4753 }
4754 
4755 /* Move to the previous place where a word begins. */
4756 static void
4758  const char *separators, int already)
4759 {
4760  struct window_copy_mode_data *data = wme->data;
4761  struct screen *back_s = data->backing;
4762  struct grid_reader gr;
4763  u_int px, py, oldy, hsize;
4764 
4765  px = data->cx;
4766  hsize = screen_hsize(back_s);
4767  py = hsize + data->cy - data->oy;
4768  oldy = data->cy;
4769 
4770  grid_reader_start(&gr, back_s->grid, px, py);
4771  grid_reader_cursor_previous_word(&gr, separators, already);
4772  grid_reader_get_cursor(&gr, &px, &py);
4773  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
4774 }
4775 
4776 static void
4778 {
4779  struct window_pane *wp = wme->wp;
4780  struct window_copy_mode_data *data = wme->data;
4781  struct screen *s = &data->screen;
4782  struct screen_write_ctx ctx;
4783 
4784  if (data->oy < ny)
4785  ny = data->oy;
4786  if (ny == 0)
4787  return;
4788  data->oy -= ny;
4789 
4790  if (data->searchmark != NULL && !data->timeout)
4791  window_copy_search_marks(wme, NULL, data->searchregex, 1);
4792  window_copy_update_selection(wme, 0, 0);
4793 
4794  screen_write_start_pane(&ctx, wp, NULL);
4795  screen_write_cursormove(&ctx, 0, 0, 0);
4796  screen_write_deleteline(&ctx, ny, 8);
4797  window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
4798  window_copy_write_line(wme, &ctx, 0);
4799  if (screen_size_y(s) > 1)
4800  window_copy_write_line(wme, &ctx, 1);
4801  if (screen_size_y(s) > 3)
4802  window_copy_write_line(wme, &ctx, screen_size_y(s) - 2);
4803  if (s->sel != NULL && screen_size_y(s) > ny)
4804  window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1);
4805  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
4806  screen_write_stop(&ctx);
4807 }
4808 
4809 static void
4811 {
4812  struct window_pane *wp = wme->wp;
4813  struct window_copy_mode_data *data = wme->data;
4814  struct screen *s = &data->screen;
4815  struct screen_write_ctx ctx;
4816 
4817  if (ny > screen_hsize(data->backing))
4818  return;
4819 
4820  if (data->oy > screen_hsize(data->backing) - ny)
4821  ny = screen_hsize(data->backing) - data->oy;
4822  if (ny == 0)
4823  return;
4824  data->oy += ny;
4825 
4826  if (data->searchmark != NULL && !data->timeout)
4827  window_copy_search_marks(wme, NULL, data->searchregex, 1);
4828  window_copy_update_selection(wme, 0, 0);
4829 
4830  screen_write_start_pane(&ctx, wp, NULL);
4831  screen_write_cursormove(&ctx, 0, 0, 0);
4832  screen_write_insertline(&ctx, ny, 8);
4833  window_copy_write_lines(wme, &ctx, 0, ny);
4834  if (s->sel != NULL && screen_size_y(s) > ny)
4835  window_copy_write_line(wme, &ctx, ny);
4836  else if (ny == 1) /* nuke position */
4837  window_copy_write_line(wme, &ctx, 1);
4838  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
4839  screen_write_stop(&ctx);
4840 }
4841 
4842 static void
4844 {
4845  struct window_copy_mode_data *data = wme->data;
4846  u_int px, py;
4847 
4848  data->rectflag = rectflag;
4849 
4850  py = screen_hsize(data->backing) + data->cy - data->oy;
4851  px = window_copy_find_length(wme, py);
4852  if (data->cx > px)
4853  window_copy_update_cursor(wme, px, data->cy);
4854 
4855  window_copy_update_selection(wme, 1, 0);
4857 }
4858 
4859 static void
4861 {
4862  struct window_pane *wp;
4863  struct window_mode_entry *wme;
4864  u_int x, y;
4865 
4866  wp = cmd_mouse_pane(m, NULL, NULL);
4867  if (wp == NULL)
4868  return;
4869  wme = TAILQ_FIRST(&wp->modes);
4870  if (wme == NULL)
4871  return;
4872  if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
4873  return;
4874 
4875  if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
4876  return;
4877 
4878  window_copy_update_cursor(wme, x, y);
4879 }
4880 
4881 void
4883 {
4884  struct window_pane *wp;
4885  struct window_mode_entry *wme;
4886  struct window_copy_mode_data *data;
4887  u_int x, y, yg;
4888 
4889  if (c == NULL)
4890  return;
4891 
4892  wp = cmd_mouse_pane(m, NULL, NULL);
4893  if (wp == NULL)
4894  return;
4895  wme = TAILQ_FIRST(&wp->modes);
4896  if (wme == NULL)
4897  return;
4898  if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
4899  return;
4900 
4901  if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
4902  return;
4903 
4906 
4907  data = wme->data;
4908  yg = screen_hsize(data->backing) + y - data->oy;
4909  if (x < data->selrx || x > data->endselrx || yg != data->selry)
4910  data->selflag = SEL_CHAR;
4911  switch (data->selflag) {
4912  case SEL_WORD:
4913  if (data->ws != NULL) {
4914  window_copy_update_cursor(wme, x, y);
4916  &x, &y);
4917  y -= screen_hsize(data->backing) - data->oy;
4918  }
4919  window_copy_update_cursor(wme, x, y);
4920  break;
4921  case SEL_LINE:
4922  window_copy_update_cursor(wme, 0, y);
4923  break;
4924  case SEL_CHAR:
4925  window_copy_update_cursor(wme, x, y);
4927  break;
4928  }
4929 
4932 }
4933 
4934 static void
4936 {
4937  struct window_pane *wp;
4938  struct window_mode_entry *wme;
4939  struct window_copy_mode_data *data;
4940  u_int x, y, old_cx, old_cy;
4941  struct timeval tv = {
4942  .tv_usec = WINDOW_COPY_DRAG_REPEAT_TIME
4943  };
4944 
4945  if (c == NULL)
4946  return;
4947 
4948  wp = cmd_mouse_pane(m, NULL, NULL);
4949  if (wp == NULL)
4950  return;
4951  wme = TAILQ_FIRST(&wp->modes);
4952  if (wme == NULL)
4953  return;
4954  if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
4955  return;
4956 
4957  data = wme->data;
4958  evtimer_del(&data->dragtimer);
4959 
4960  if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
4961  return;
4962  old_cx = data->cx;
4963  old_cy = data->cy;
4964 
4965  window_copy_update_cursor(wme, x, y);
4966  if (window_copy_update_selection(wme, 1, 0))
4967  window_copy_redraw_selection(wme, old_cy);
4968  if (old_cy != data->cy || old_cx == data->cx) {
4969  if (y == 0) {
4970  evtimer_add(&data->dragtimer, &tv);
4971  window_copy_cursor_up(wme, 1);
4972  } else if (y == screen_size_y(&data->screen) - 1) {
4973  evtimer_add(&data->dragtimer, &tv);
4974  window_copy_cursor_down(wme, 1);
4975  }
4976  }
4977 }
4978 
4979 static void
4981 {
4982  struct window_pane *wp;
4983  struct window_mode_entry *wme;
4984  struct window_copy_mode_data *data;
4985 
4986  if (c == NULL)
4987  return;
4988 
4989  wp = cmd_mouse_pane(m, NULL, NULL);
4990  if (wp == NULL)
4991  return;
4992  wme = TAILQ_FIRST(&wp->modes);
4993  if (wme == NULL)
4994  return;
4995  if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
4996  return;
4997 
4998  data = wme->data;
4999  evtimer_del(&data->dragtimer);
5000 }
5001 
5002 static void
5004 {
5005  struct window_copy_mode_data *data = wme->data;
5006  u_int tmx, tmy;
5007 
5008  tmx = data->cx;
5009  tmy = screen_hsize(data->backing) + data->cy - data->oy;
5010  data->cx = data->mx;
5011  if (data->my < screen_hsize(data->backing)) {
5012  data->cy = 0;
5013  data->oy = screen_hsize(data->backing) - data->my;
5014  } else {
5015  data->cy = data->my - screen_hsize(data->backing);
5016  data->oy = 0;
5017  }
5018  data->mx = tmx;
5019  data->my = tmy;
5020  data->showmark = 1;
5021  window_copy_update_selection(wme, 0, 0);
5023 }
5024 
5025 /* Scroll up if the cursor went off the visible screen. */
5026 static void
5028  u_int oy, u_int oldy, u_int px, u_int py)
5029 {
5030  u_int cy, yy, ny, nd;
5031 
5032  yy = hsize - oy;
5033  if (py < yy) {
5034  ny = yy - py;
5035  cy = 0;
5036  nd = 1;
5037  } else {
5038  ny = 0;
5039  cy = py - yy;
5040  nd = oldy - cy + 1;
5041  }
5042  while (ny > 0) {
5043  window_copy_cursor_up(wme, 1);
5044  ny--;
5045  }
5046  window_copy_update_cursor(wme, px, cy);
5047  if (window_copy_update_selection(wme, 1, 0))
5048  window_copy_redraw_lines(wme, cy, nd);
5049 }
5050 
5051 /* Scroll down if the cursor went off the visible screen. */
5052 static void
5054  u_int sy, u_int oy, u_int oldy, u_int px, u_int py, int no_reset)
5055 {
5056  u_int cy, yy, ny, nd;
5057 
5058  cy = py - hsize + oy;
5059  yy = sy - 1;
5060  if (cy > yy) {
5061  ny = cy - yy;
5062  oldy = yy;
5063  nd = 1;
5064  } else {
5065  ny = 0;
5066  nd = cy - oldy + 1;
5067  }
5068  while (ny > 0) {
5069  window_copy_cursor_down(wme, 1);
5070  ny--;
5071  }
5072  if (cy > yy)
5073  window_copy_update_cursor(wme, px, yy);
5074  else
5075  window_copy_update_cursor(wme, px, cy);
5076  if (window_copy_update_selection(wme, 1, no_reset))
5077  window_copy_redraw_lines(wme, oldy, nd);
5078 }
int args_has(struct args *args, u_char flag)
Definition: arguments.c:259
int cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp, u_int *yp, int last)
Definition: cmd.c:703
struct window_pane * cmd_mouse_pane(struct mouse_event *m, struct session **sp, struct winlink **wlp)
Definition: cmd.c:758
#define __unused
Definition: compat.h:60
long long strtonum(const char *, long long, long long, const char **)
char * format_grid_line(struct grid *gd, u_int y)
Definition: format.c:4865
char * format_single(struct cmdq_item *item, const char *fmt, struct client *c, struct session *s, struct winlink *wl, struct window_pane *wp)
Definition: format.c:4621
void format_add(struct format_tree *ft, const char *key, const char *fmt,...)
Definition: format.c:3126
void format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
Definition: format.c:3176
struct window_pane * format_get_pane(struct format_tree *ft)
Definition: format.c:3024
char * format_grid_word(struct grid *gd, u_int x, u_int y)
Definition: format.c:4795
void grid_reader_get_cursor(struct grid_reader *gr, u_int *cx, u_int *cy)
Definition: grid-reader.c:33
void grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
Definition: grid-reader.c:140
void grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
Definition: grid-reader.c:371
int grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
Definition: grid-reader.c:342
int grid_reader_in_set(struct grid_reader *gr, const char *set)
Definition: grid-reader.c:158
void grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
Definition: grid-reader.c:48
int grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
Definition: grid-reader.c:310
void grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
Definition: grid-reader.c:170
void grid_reader_cursor_left(struct grid_reader *gr, int wrap)
Definition: grid-reader.c:74
void grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators, int already)
Definition: grid-reader.c:258
void grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
Definition: grid-reader.c:214
void grid_reader_start(struct grid_reader *gr, struct grid *gd, u_int cx, u_int cy)
Definition: grid-reader.c:24
void grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
Definition: grid-reader.c:127
const struct grid_cell grid_default_cell
Definition: grid.c:39
void grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy, u_int ny)
Definition: grid.c:1024
void grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
Definition: grid.c:529
struct grid_line * grid_get_line(struct grid *gd, u_int line)
Definition: grid.c:181
u_int grid_line_length(struct grid *gd, u_int py)
Definition: grid.c:1414