Coverage Report

Created: 2025-12-11 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/window-copy.c
Line
Count
Source
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
29
struct window_copy_mode_data;
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 struct screen *window_copy_get_screen(struct window_mode_entry *);
44
static void window_copy_scroll1(struct window_mode_entry *,
45
        struct window_pane *wp, int, u_int, int);
46
static void window_copy_pageup1(struct window_mode_entry *, int);
47
static int  window_copy_pagedown1(struct window_mode_entry *, int, int);
48
static void window_copy_next_paragraph(struct window_mode_entry *);
49
static void window_copy_previous_paragraph(struct window_mode_entry *);
50
static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
51
static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
52
        u_int);
53
static void window_copy_redraw_screen(struct window_mode_entry *);
54
static void window_copy_write_line(struct window_mode_entry *,
55
        struct screen_write_ctx *, u_int);
56
static void window_copy_write_lines(struct window_mode_entry *,
57
        struct screen_write_ctx *, u_int, u_int);
58
static char    *window_copy_match_at_cursor(struct window_copy_mode_data *);
59
static void window_copy_scroll_to(struct window_mode_entry *, u_int, u_int,
60
        int);
61
static int  window_copy_search_compare(struct grid *, u_int, u_int,
62
        struct grid *, u_int, int);
63
static int  window_copy_search_lr(struct grid *, struct grid *, u_int *,
64
        u_int, u_int, u_int, int);
65
static int  window_copy_search_rl(struct grid *, struct grid *, u_int *,
66
        u_int, u_int, u_int, int);
67
static int  window_copy_last_regex(struct grid *, u_int, u_int, u_int,
68
        u_int, u_int *, u_int *, const char *, const regex_t *,
69
        int);
70
static int  window_copy_search_mark_at(struct window_copy_mode_data *,
71
        u_int, u_int, u_int *);
72
static char    *window_copy_stringify(struct grid *, u_int, u_int, u_int,
73
        char *, u_int *);
74
static void window_copy_cstrtocellpos(struct grid *, u_int, u_int *,
75
        u_int *, const char *);
76
static int  window_copy_search_marks(struct window_mode_entry *,
77
        struct screen *, int, int);
78
static void window_copy_clear_marks(struct window_mode_entry *);
79
static int  window_copy_is_lowercase(const char *);
80
static void window_copy_search_back_overlap(struct grid *, regex_t *,
81
        u_int *, u_int *, u_int *, u_int);
82
static int  window_copy_search_jump(struct window_mode_entry *,
83
        struct grid *, struct grid *, u_int, u_int, u_int, int, int,
84
        int, int);
85
static int  window_copy_search(struct window_mode_entry *, int, int);
86
static int  window_copy_search_up(struct window_mode_entry *, int);
87
static int  window_copy_search_down(struct window_mode_entry *, int);
88
static void window_copy_goto_line(struct window_mode_entry *, const char *);
89
static void window_copy_update_cursor(struct window_mode_entry *, u_int,
90
        u_int);
91
static void window_copy_start_selection(struct window_mode_entry *);
92
static int  window_copy_adjust_selection(struct window_mode_entry *,
93
        u_int *, u_int *);
94
static int  window_copy_set_selection(struct window_mode_entry *, int, int);
95
static int  window_copy_update_selection(struct window_mode_entry *, int,
96
        int);
97
static void window_copy_synchronize_cursor(struct window_mode_entry *, int);
98
static void    *window_copy_get_selection(struct window_mode_entry *, size_t *);
99
static void window_copy_copy_buffer(struct window_mode_entry *,
100
        const char *, void *, size_t, int, int);
101
static void window_copy_pipe(struct window_mode_entry *,
102
        struct session *, const char *);
103
static void window_copy_copy_pipe(struct window_mode_entry *,
104
        struct session *, const char *, const char *,
105
        int, int);
106
static void window_copy_copy_selection(struct window_mode_entry *,
107
        const char *, int, int);
108
static void window_copy_append_selection(struct window_mode_entry *);
109
static void window_copy_clear_selection(struct window_mode_entry *);
110
static void window_copy_copy_line(struct window_mode_entry *, char **,
111
        size_t *, u_int, u_int, u_int);
112
static int  window_copy_in_set(struct window_mode_entry *, u_int, u_int,
113
        const char *);
114
static u_int  window_copy_find_length(struct window_mode_entry *, u_int);
115
static void window_copy_cursor_start_of_line(struct window_mode_entry *);
116
static void window_copy_cursor_back_to_indentation(
117
        struct window_mode_entry *);
118
static void window_copy_cursor_end_of_line(struct window_mode_entry *);
119
static void window_copy_other_end(struct window_mode_entry *);
120
static void window_copy_cursor_left(struct window_mode_entry *);
121
static void window_copy_cursor_right(struct window_mode_entry *, int);
122
static void window_copy_cursor_up(struct window_mode_entry *, int);
123
static void window_copy_cursor_down(struct window_mode_entry *, int);
124
static void window_copy_cursor_jump(struct window_mode_entry *);
125
static void window_copy_cursor_jump_back(struct window_mode_entry *);
126
static void window_copy_cursor_jump_to(struct window_mode_entry *);
127
static void window_copy_cursor_jump_to_back(struct window_mode_entry *);
128
static void window_copy_cursor_next_word(struct window_mode_entry *,
129
        const char *);
130
static void window_copy_cursor_next_word_end_pos(struct window_mode_entry *,
131
        const char *, u_int *, u_int *);
132
static void window_copy_cursor_next_word_end(struct window_mode_entry *,
133
        const char *, int);
134
static void window_copy_cursor_previous_word_pos(struct window_mode_entry *,
135
        const char *, u_int *, u_int *);
136
static void window_copy_cursor_previous_word(struct window_mode_entry *,
137
        const char *, int);
138
static void window_copy_cursor_prompt(struct window_mode_entry *, int,
139
        int);
140
static void window_copy_scroll_up(struct window_mode_entry *, u_int);
141
static void window_copy_scroll_down(struct window_mode_entry *, u_int);
142
static void window_copy_rectangle_set(struct window_mode_entry *, int);
143
static void window_copy_move_mouse(struct mouse_event *);
144
static void window_copy_drag_update(struct client *, struct mouse_event *);
145
static void window_copy_drag_release(struct client *, struct mouse_event *);
146
static void window_copy_jump_to_mark(struct window_mode_entry *);
147
static void window_copy_acquire_cursor_up(struct window_mode_entry *,
148
        u_int, u_int, u_int, u_int, u_int);
149
static void window_copy_acquire_cursor_down(struct window_mode_entry *,
150
        u_int, u_int, u_int, u_int, u_int, u_int, int);
151
static u_int  window_copy_clip_width(u_int, u_int, u_int, u_int);
152
static u_int  window_copy_search_mark_match(struct window_copy_mode_data *,
153
        u_int , u_int, u_int, int);
154
155
const struct window_mode window_copy_mode = {
156
  .name = "copy-mode",
157
158
  .init = window_copy_init,
159
  .free = window_copy_free,
160
  .resize = window_copy_resize,
161
  .key_table = window_copy_key_table,
162
  .command = window_copy_command,
163
  .formats = window_copy_formats,
164
  .get_screen = window_copy_get_screen
165
};
166
167
const struct window_mode window_view_mode = {
168
  .name = "view-mode",
169
170
  .init = window_copy_view_init,
171
  .free = window_copy_free,
172
  .resize = window_copy_resize,
173
  .key_table = window_copy_key_table,
174
  .command = window_copy_command,
175
  .formats = window_copy_formats,
176
  .get_screen = window_copy_get_screen
177
};
178
179
enum {
180
  WINDOW_COPY_OFF,
181
  WINDOW_COPY_SEARCHUP,
182
  WINDOW_COPY_SEARCHDOWN,
183
  WINDOW_COPY_JUMPFORWARD,
184
  WINDOW_COPY_JUMPBACKWARD,
185
  WINDOW_COPY_JUMPTOFORWARD,
186
  WINDOW_COPY_JUMPTOBACKWARD,
187
};
188
189
enum {
190
  WINDOW_COPY_REL_POS_ABOVE,
191
  WINDOW_COPY_REL_POS_ON_SCREEN,
192
  WINDOW_COPY_REL_POS_BELOW,
193
};
194
195
enum window_copy_cmd_action {
196
  WINDOW_COPY_CMD_NOTHING,
197
  WINDOW_COPY_CMD_REDRAW,
198
  WINDOW_COPY_CMD_CANCEL,
199
};
200
201
enum window_copy_cmd_clear {
202
  WINDOW_COPY_CMD_CLEAR_ALWAYS,
203
  WINDOW_COPY_CMD_CLEAR_NEVER,
204
  WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
205
};
206
207
struct window_copy_cmd_state {
208
  struct window_mode_entry  *wme;
209
  struct args     *args;
210
  struct args     *wargs;
211
  struct mouse_event    *m;
212
213
  struct client     *c;
214
  struct session      *s;
215
  struct winlink      *wl;
216
};
217
218
/*
219
 * Copy mode's visible screen (the "screen" field) is filled from one of two
220
 * sources: the original contents of the pane (used when we actually enter via
221
 * the "copy-mode" command, to copy the contents of the current pane), or else
222
 * a series of lines containing the output from an output-writing tmux command
223
 * (such as any of the "show-*" or "list-*" commands).
224
 *
225
 * In either case, the full content of the copy-mode grid is pointed at by the
226
 * "backing" field, and is copied into "screen" as needed (that is, when
227
 * scrolling occurs). When copy-mode is backed by a pane, backing points
228
 * directly at that pane's screen structure (&wp->base); when backed by a list
229
 * of output-lines from a command, it points at a newly-allocated screen
230
 * structure (which is deallocated when the mode ends).
231
 */
232
struct window_copy_mode_data {
233
  struct screen  screen;
234
235
  struct screen *backing;
236
  int    backing_written; /* backing display started */
237
  struct input_ctx *ictx;
238
239
  int    viewmode;  /* view mode entered */
240
241
  u_int    oy;    /* number of lines scrolled up */
242
243
  u_int    selx;    /* beginning of selection */
244
  u_int    sely;
245
246
  u_int    endselx; /* end of selection */
247
  u_int    endsely;
248
249
  enum {
250
    CURSORDRAG_NONE,  /* selection is independent of cursor */
251
    CURSORDRAG_ENDSEL,  /* end is synchronized with cursor */
252
    CURSORDRAG_SEL,   /* start is synchronized with cursor */
253
  } cursordrag;
254
255
  int    modekeys;
256
  enum {
257
    LINE_SEL_NONE,
258
    LINE_SEL_LEFT_RIGHT,
259
    LINE_SEL_RIGHT_LEFT,
260
  } lineflag;     /* line selection mode */
261
  int    rectflag;  /* in rectangle copy mode? */
262
  int    scroll_exit; /* exit on scroll to end? */
263
  int    hide_position; /* hide position marker */
264
265
  enum {
266
    SEL_CHAR,   /* select one char at a time */
267
    SEL_WORD,   /* select one word at a time */
268
    SEL_LINE,   /* select one line at a time */
269
  } selflag;
270
271
  const char  *separators;  /* word separators */
272
273
  u_int    dx;    /* drag start position */
274
  u_int    dy;
275
276
  u_int    selrx;   /* selection reset positions */
277
  u_int    selry;
278
  u_int    endselrx;
279
  u_int    endselry;
280
281
  u_int    cx;
282
  u_int    cy;
283
284
  u_int    lastcx;  /* position in last line w/ content */
285
  u_int    lastsx;  /* size of last line w/ content */
286
287
  u_int    mx;    /* mark position */
288
  u_int    my;
289
  int    showmark;
290
291
  int    searchtype;
292
  int    searchdirection;
293
  int    searchregex;
294
  char    *searchstr;
295
  u_char    *searchmark;
296
  int    searchcount;
297
  int    searchmore;
298
  int    searchall;
299
  int    searchx;
300
  int    searchy;
301
  int    searcho;
302
  u_char     searchgen;
303
304
  int    timeout; /* search has timed out */
305
0
#define WINDOW_COPY_SEARCH_TIMEOUT 10000
306
0
#define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
307
0
#define WINDOW_COPY_SEARCH_MAX_LINE 2000
308
309
  int      jumptype;
310
  struct utf8_data  *jumpchar;
311
312
  struct event   dragtimer;
313
0
#define WINDOW_COPY_DRAG_REPEAT_TIME 50000
314
};
315
316
static void
317
window_copy_scroll_timer(__unused int fd, __unused short events, void *arg)
318
0
{
319
0
  struct window_mode_entry  *wme = arg;
320
0
  struct window_pane    *wp = wme->wp;
321
0
  struct window_copy_mode_data  *data = wme->data;
322
0
  struct timeval       tv = {
323
0
    .tv_usec = WINDOW_COPY_DRAG_REPEAT_TIME
324
0
  };
325
326
0
  evtimer_del(&data->dragtimer);
327
328
0
  if (TAILQ_FIRST(&wp->modes) != wme)
329
0
    return;
330
331
0
  if (data->cy == 0) {
332
0
    evtimer_add(&data->dragtimer, &tv);
333
0
    window_copy_cursor_up(wme, 1);
334
0
  } else if (data->cy == screen_size_y(&data->screen) - 1) {
335
0
    evtimer_add(&data->dragtimer, &tv);
336
0
    window_copy_cursor_down(wme, 1);
337
0
  }
338
0
}
339
340
static struct screen *
341
window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
342
    u_int *cy, int trim)
343
0
{
344
0
  struct screen   *dst;
345
0
  const struct grid_line  *gl;
346
0
  u_int      sy, wx, wy;
347
0
  int      reflow;
348
349
0
  dst = xcalloc(1, sizeof *dst);
350
351
0
  sy = screen_hsize(src) + screen_size_y(src);
352
0
  if (trim) {
353
0
    while (sy > screen_hsize(src)) {
354
0
      gl = grid_peek_line(src->grid, sy - 1);
355
0
      if (gl->cellused != 0)
356
0
        break;
357
0
      sy--;
358
0
    }
359
0
  }
360
0
  log_debug("%s: target screen is %ux%u, source %ux%u", __func__,
361
0
      screen_size_x(src), sy, screen_size_x(hint),
362
0
      screen_hsize(src) + screen_size_y(src));
363
0
  screen_init(dst, screen_size_x(src), sy, screen_hlimit(src));
364
365
  /*
366
   * Ensure history is on for the backing grid so lines are not deleted
367
   * during resizing.
368
   */
369
0
  dst->grid->flags |= GRID_HISTORY;
370
0
  grid_duplicate_lines(dst->grid, 0, src->grid, 0, sy);
371
372
0
  dst->grid->sy = sy - screen_hsize(src);
373
0
  dst->grid->hsize = screen_hsize(src);
374
0
  dst->grid->hscrolled = src->grid->hscrolled;
375
0
  if (src->cy > dst->grid->sy - 1) {
376
0
    dst->cx = 0;
377
0
    dst->cy = dst->grid->sy - 1;
378
0
  } else {
379
0
    dst->cx = src->cx;
380
0
    dst->cy = src->cy;
381
0
  }
382
383
0
  if (cx != NULL && cy != NULL) {
384
0
    *cx = dst->cx;
385
0
    *cy = screen_hsize(dst) + dst->cy;
386
0
    reflow = (screen_size_x(hint) != screen_size_x(dst));
387
0
  }
388
0
  else
389
0
    reflow = 0;
390
0
  if (reflow)
391
0
    grid_wrap_position(dst->grid, *cx, *cy, &wx, &wy);
392
0
  screen_resize_cursor(dst, screen_size_x(hint), screen_size_y(hint), 1,
393
0
      0, 0);
394
0
  if (reflow)
395
0
    grid_unwrap_position(dst->grid, cx, cy, wx, wy);
396
397
0
  return (dst);
398
0
}
399
400
static struct window_copy_mode_data *
401
window_copy_common_init(struct window_mode_entry *wme)
402
0
{
403
0
  struct window_pane    *wp = wme->wp;
404
0
  struct window_copy_mode_data  *data;
405
0
  struct screen     *base = &wp->base;
406
407
0
  wme->data = data = xcalloc(1, sizeof *data);
408
409
0
  data->cursordrag = CURSORDRAG_NONE;
410
0
  data->lineflag = LINE_SEL_NONE;
411
0
  data->selflag = SEL_CHAR;
412
413
0
  if (wp->searchstr != NULL) {
414
0
    data->searchtype = WINDOW_COPY_SEARCHUP;
415
0
    data->searchregex = wp->searchregex;
416
0
    data->searchstr = xstrdup(wp->searchstr);
417
0
  } else {
418
0
    data->searchtype = WINDOW_COPY_OFF;
419
0
    data->searchregex = 0;
420
0
    data->searchstr = NULL;
421
0
  }
422
0
  data->searchx = data->searchy = data->searcho = -1;
423
0
  data->searchall = 1;
424
425
0
  data->jumptype = WINDOW_COPY_OFF;
426
0
  data->jumpchar = NULL;
427
428
0
  screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0);
429
0
  screen_set_default_cursor(&data->screen, global_w_options);
430
0
  data->modekeys = options_get_number(wp->window->options, "mode-keys");
431
432
0
  evtimer_set(&data->dragtimer, window_copy_scroll_timer, wme);
433
434
0
  return (data);
435
0
}
436
437
static struct screen *
438
window_copy_init(struct window_mode_entry *wme,
439
    __unused struct cmd_find_state *fs, struct args *args)
440
0
{
441
0
  struct window_pane    *wp = wme->swp;
442
0
  struct window_copy_mode_data  *data;
443
0
  struct screen     *base = &wp->base;
444
0
  struct screen_write_ctx    ctx;
445
0
  u_int        i, cx, cy;
446
447
0
  data = window_copy_common_init(wme);
448
0
  data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy,
449
0
      wme->swp != wme->wp);
450
451
0
  data->cx = cx;
452
0
  if (cy < screen_hsize(data->backing)) {
453
0
    data->cy = 0;
454
0
    data->oy = screen_hsize(data->backing) - cy;
455
0
  } else {
456
0
    data->cy = cy - screen_hsize(data->backing);
457
0
    data->oy = 0;
458
0
  }
459
460
0
  data->scroll_exit = args_has(args, 'e');
461
0
  data->hide_position = args_has(args, 'H');
462
463
0
  if (base->hyperlinks != NULL)
464
0
    data->screen.hyperlinks = hyperlinks_copy(base->hyperlinks);
465
0
  data->screen.cx = data->cx;
466
0
  data->screen.cy = data->cy;
467
0
  data->mx = data->cx;
468
0
  data->my = screen_hsize(data->backing) + data->cy - data->oy;
469
0
  data->showmark = 0;
470
471
0
  screen_write_start(&ctx, &data->screen);
472
0
  for (i = 0; i < screen_size_y(&data->screen); i++)
473
0
    window_copy_write_line(wme, &ctx, i);
474
0
  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
475
0
  screen_write_stop(&ctx);
476
477
0
  return (&data->screen);
478
0
}
479
480
static struct screen *
481
window_copy_view_init(struct window_mode_entry *wme,
482
    __unused struct cmd_find_state *fs, __unused struct args *args)
483
0
{
484
0
  struct window_pane    *wp = wme->wp;
485
0
  struct window_copy_mode_data  *data;
486
0
  struct screen     *base = &wp->base;
487
0
  u_int        sx = screen_size_x(base);
488
489
0
  data = window_copy_common_init(wme);
490
0
  data->viewmode = 1;
491
492
0
  data->backing = xmalloc(sizeof *data->backing);
493
0
  screen_init(data->backing, sx, screen_size_y(base), UINT_MAX);
494
0
  data->ictx = input_init(NULL, NULL, NULL);
495
0
  data->mx = data->cx;
496
0
  data->my = screen_hsize(data->backing) + data->cy - data->oy;
497
0
  data->showmark = 0;
498
499
0
  return (&data->screen);
500
0
}
501
502
static void
503
window_copy_free(struct window_mode_entry *wme)
504
0
{
505
0
  struct window_copy_mode_data  *data = wme->data;
506
507
0
  evtimer_del(&data->dragtimer);
508
509
0
  free(data->searchmark);
510
0
  free(data->searchstr);
511
0
  free(data->jumpchar);
512
513
0
  if (data->ictx != NULL)
514
0
    input_free(data->ictx);
515
0
  screen_free(data->backing);
516
0
  free(data->backing);
517
518
0
  screen_free(&data->screen);
519
0
  free(data);
520
0
}
521
522
void
523
window_copy_add(struct window_pane *wp, int parse, const char *fmt, ...)
524
0
{
525
0
  va_list ap;
526
527
0
  va_start(ap, fmt);
528
0
  window_copy_vadd(wp, parse, fmt, ap);
529
0
  va_end(ap);
530
0
}
531
532
static void
533
window_copy_init_ctx_cb(__unused struct screen_write_ctx *ctx,
534
    struct tty_ctx *ttyctx)
535
0
{
536
0
  memcpy(&ttyctx->defaults, &grid_default_cell, sizeof ttyctx->defaults);
537
0
  ttyctx->palette = NULL;
538
0
  ttyctx->redraw_cb = NULL;
539
0
  ttyctx->set_client_cb = NULL;
540
0
  ttyctx->arg = NULL;
541
0
}
542
543
void
544
window_copy_vadd(struct window_pane *wp, int parse, const char *fmt, va_list ap)
545
0
{
546
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
547
0
  struct window_copy_mode_data  *data = wme->data;
548
0
  struct screen     *backing = data->backing;
549
0
  struct screen_write_ctx    backing_ctx, ctx;
550
0
  struct grid_cell     gc;
551
0
  u_int        old_hsize, old_cy;
552
0
  char        *text;
553
554
0
  old_hsize = screen_hsize(data->backing);
555
0
  screen_write_start(&backing_ctx, backing);
556
0
  if (data->backing_written) {
557
    /*
558
     * On the second or later line, do a CRLF before writing
559
     * (so it's on a new line).
560
     */
561
0
    screen_write_carriagereturn(&backing_ctx);
562
0
    screen_write_linefeed(&backing_ctx, 0, 8);
563
0
  } else
564
0
    data->backing_written = 1;
565
0
  old_cy = backing->cy;
566
0
  if (parse) {
567
0
    vasprintf(&text, fmt, ap);
568
0
    input_parse_screen(data->ictx, backing, window_copy_init_ctx_cb,
569
0
        data, text, strlen(text));
570
0
    free(text);
571
0
  } else {
572
0
    memcpy(&gc, &grid_default_cell, sizeof gc);
573
0
    screen_write_vnputs(&backing_ctx, 0, &gc, fmt, ap);
574
0
  }
575
0
  screen_write_stop(&backing_ctx);
576
577
0
  data->oy += screen_hsize(data->backing) - old_hsize;
578
579
0
  screen_write_start_pane(&ctx, wp, &data->screen);
580
581
  /*
582
   * If the history has changed, draw the top line.
583
   * (If there's any history at all, it has changed.)
584
   */
585
0
  if (screen_hsize(data->backing))
586
0
    window_copy_redraw_lines(wme, 0, 1);
587
588
  /* Write the new lines. */
589
0
  window_copy_redraw_lines(wme, old_cy, backing->cy - old_cy + 1);
590
591
0
  screen_write_stop(&ctx);
592
0
}
593
594
void
595
window_copy_scroll(struct window_pane *wp, int sl_mpos, u_int my,
596
    int scroll_exit)
597
0
{
598
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
599
600
0
  if (wme != NULL) {
601
0
    window_set_active_pane(wp->window, wp, 0);
602
0
    window_copy_scroll1(wme, wp, sl_mpos, my, scroll_exit);
603
0
  }
604
0
}
605
606
static void
607
window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp,
608
    int sl_mpos, u_int my, int scroll_exit)
609
0
{
610
0
  struct window_copy_mode_data  *data = wme->data;
611
0
  u_int        ox, oy, px, py, n, offset, size;
612
0
  u_int        new_offset;
613
0
  u_int        slider_height = wp->sb_slider_h;
614
0
  u_int        sb_height = wp->sy, sb_top = wp->yoff;
615
0
  u_int        sy = screen_size_y(data->backing);
616
0
  int        new_slider_y, delta;
617
618
  /*
619
   * sl_mpos is where in the slider the user is dragging, mouse is
620
   * dragging this y point relative to top of slider.
621
   */
622
0
  if (my <= sb_top + sl_mpos) {
623
    /* Slider banged into top. */
624
0
    new_slider_y = sb_top - wp->yoff;
625
0
  } else if (my - sl_mpos > sb_top + sb_height - slider_height) {
626
    /* Slider banged into bottom. */
627
0
    new_slider_y = sb_top - wp->yoff + (sb_height - slider_height);
628
0
  } else {
629
    /* Slider is somewhere in the middle. */
630
0
    new_slider_y = my - wp->yoff - sl_mpos;
631
0
  }
632
633
0
  if (TAILQ_FIRST(&wp->modes) == NULL ||
634
0
      window_copy_get_current_offset(wp, &offset, &size) == 0)
635
0
    return;
636
637
  /*
638
   * See screen_redraw_draw_pane_scrollbar - this is the inverse of the
639
   * formula used there.
640
   */
641
0
  new_offset = new_slider_y * ((float)(size + sb_height) / sb_height);
642
0
  delta = (int)offset - new_offset;
643
644
  /*
645
   * Move pane view around based on delta relative to the cursor,
646
   * maintaining the selection.
647
   */
648
0
  oy = screen_hsize(data->backing) + data->cy - data->oy;
649
0
  ox = window_copy_find_length(wme, oy);
650
651
0
  if (data->cx != ox) {
652
0
    data->lastcx = data->cx;
653
0
    data->lastsx = ox;
654
0
  }
655
0
  data->cx = data->lastcx;
656
657
0
  if (delta >= 0) {
658
0
    n = (u_int)delta;
659
0
    if (data->oy + n > screen_hsize(data->backing)) {
660
0
      data->oy = screen_hsize(data->backing);
661
0
      if (data->cy < n)
662
0
        data->cy = 0;
663
0
      else
664
0
        data->cy -= n;
665
0
    } else
666
0
      data->oy += n;
667
0
  } else {
668
0
    n = (u_int)-delta;
669
0
    if (data->oy < n) {
670
0
      data->oy = 0;
671
0
      if (data->cy + (n - data->oy) >= sy)
672
0
        data->cy = sy - 1;
673
0
      else
674
0
        data->cy += n - data->oy;
675
0
    } else
676
0
      data->oy -= n;
677
0
  }
678
679
  /* Don't also drag tail when dragging a scrollbar, it looks weird. */
680
0
  data->cursordrag = CURSORDRAG_NONE;
681
682
0
  if (data->screen.sel == NULL || !data->rectflag) {
683
0
    py = screen_hsize(data->backing) + data->cy - data->oy;
684
0
    px = window_copy_find_length(wme, py);
685
0
    if ((data->cx >= data->lastsx && data->cx != px) ||
686
0
        data->cx > px)
687
0
      window_copy_cursor_end_of_line(wme);
688
0
  }
689
690
0
  if (scroll_exit && data->oy == 0) {
691
0
    window_pane_reset_mode(wp);
692
0
    return;
693
0
  }
694
695
0
  if (data->searchmark != NULL && !data->timeout)
696
0
    window_copy_search_marks(wme, NULL, data->searchregex, 1);
697
0
  window_copy_update_selection(wme, 1, 0);
698
0
  window_copy_redraw_screen(wme);
699
0
}
700
701
void
702
window_copy_pageup(struct window_pane *wp, int half_page)
703
0
{
704
0
  window_copy_pageup1(TAILQ_FIRST(&wp->modes), half_page);
705
0
}
706
707
static void
708
window_copy_pageup1(struct window_mode_entry *wme, int half_page)
709
0
{
710
0
  struct window_copy_mode_data  *data = wme->data;
711
0
  struct screen     *s = &data->screen;
712
0
  u_int        n, ox, oy, px, py;
713
714
0
  oy = screen_hsize(data->backing) + data->cy - data->oy;
715
0
  ox = window_copy_find_length(wme, oy);
716
717
0
  if (data->cx != ox) {
718
0
    data->lastcx = data->cx;
719
0
    data->lastsx = ox;
720
0
  }
721
0
  data->cx = data->lastcx;
722
723
0
  n = 1;
724
0
  if (screen_size_y(s) > 2) {
725
0
    if (half_page)
726
0
      n = screen_size_y(s) / 2;
727
0
    else
728
0
      n = screen_size_y(s) - 2;
729
0
  }
730
731
0
  if (data->oy + n > screen_hsize(data->backing)) {
732
0
    data->oy = screen_hsize(data->backing);
733
0
    if (data->cy < n)
734
0
      data->cy = 0;
735
0
    else
736
0
      data->cy -= n;
737
0
  } else
738
0
    data->oy += n;
739
740
0
  if (data->screen.sel == NULL || !data->rectflag) {
741
0
    py = screen_hsize(data->backing) + data->cy - data->oy;
742
0
    px = window_copy_find_length(wme, py);
743
0
    if ((data->cx >= data->lastsx && data->cx != px) ||
744
0
        data->cx > px)
745
0
      window_copy_cursor_end_of_line(wme);
746
0
  }
747
748
0
  if (data->searchmark != NULL && !data->timeout)
749
0
    window_copy_search_marks(wme, NULL, data->searchregex, 1);
750
0
  window_copy_update_selection(wme, 1, 0);
751
0
  window_copy_redraw_screen(wme);
752
0
}
753
754
void
755
window_copy_pagedown(struct window_pane *wp, int half_page, int scroll_exit)
756
0
{
757
0
  if (window_copy_pagedown1(TAILQ_FIRST(&wp->modes), half_page,
758
0
      scroll_exit)) {
759
0
    window_pane_reset_mode(wp);
760
0
    return;
761
0
  }
762
0
}
763
764
static int
765
window_copy_pagedown1(struct window_mode_entry *wme, int half_page,
766
    int scroll_exit)
767
0
{
768
0
  struct window_copy_mode_data  *data = wme->data;
769
0
  struct screen     *s = &data->screen;
770
0
  u_int        n, ox, oy, px, py;
771
772
0
  oy = screen_hsize(data->backing) + data->cy - data->oy;
773
0
  ox = window_copy_find_length(wme, oy);
774
775
0
  if (data->cx != ox) {
776
0
    data->lastcx = data->cx;
777
0
    data->lastsx = ox;
778
0
  }
779
0
  data->cx = data->lastcx;
780
781
0
  n = 1;
782
0
  if (screen_size_y(s) > 2) {
783
0
    if (half_page)
784
0
      n = screen_size_y(s) / 2;
785
0
    else
786
0
      n = screen_size_y(s) - 2;
787
0
  }
788
789
0
  if (data->oy < n) {
790
0
    data->oy = 0;
791
0
    if (data->cy + (n - data->oy) >= screen_size_y(data->backing))
792
0
      data->cy = screen_size_y(data->backing) - 1;
793
0
    else
794
0
      data->cy += n - data->oy;
795
0
  } else
796
0
    data->oy -= n;
797
798
0
  if (data->screen.sel == NULL || !data->rectflag) {
799
0
    py = screen_hsize(data->backing) + data->cy - data->oy;
800
0
    px = window_copy_find_length(wme, py);
801
0
    if ((data->cx >= data->lastsx && data->cx != px) ||
802
0
        data->cx > px)
803
0
      window_copy_cursor_end_of_line(wme);
804
0
  }
805
806
0
  if (scroll_exit && data->oy == 0)
807
0
    return (1);
808
0
  if (data->searchmark != NULL && !data->timeout)
809
0
    window_copy_search_marks(wme, NULL, data->searchregex, 1);
810
0
  window_copy_update_selection(wme, 1, 0);
811
0
  window_copy_redraw_screen(wme);
812
0
  return (0);
813
0
}
814
815
static void
816
window_copy_previous_paragraph(struct window_mode_entry *wme)
817
0
{
818
0
  struct window_copy_mode_data  *data = wme->data;
819
0
  u_int        oy;
820
821
0
  oy = screen_hsize(data->backing) + data->cy - data->oy;
822
823
0
  while (oy > 0 && window_copy_find_length(wme, oy) == 0)
824
0
    oy--;
825
826
0
  while (oy > 0 && window_copy_find_length(wme, oy) > 0)
827
0
    oy--;
828
829
0
  window_copy_scroll_to(wme, 0, oy, 0);
830
0
}
831
832
static void
833
window_copy_next_paragraph(struct window_mode_entry *wme)
834
0
{
835
0
  struct window_copy_mode_data  *data = wme->data;
836
0
  struct screen     *s = &data->screen;
837
0
  u_int        maxy, ox, oy;
838
839
0
  oy = screen_hsize(data->backing) + data->cy - data->oy;
840
0
  maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
841
842
0
  while (oy < maxy && window_copy_find_length(wme, oy) == 0)
843
0
    oy++;
844
845
0
  while (oy < maxy && window_copy_find_length(wme, oy) > 0)
846
0
    oy++;
847
848
0
  ox = window_copy_find_length(wme, oy);
849
0
  window_copy_scroll_to(wme, ox, oy, 0);
850
0
}
851
852
char *
853
window_copy_get_word(struct window_pane *wp, u_int x, u_int y)
854
0
{
855
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
856
0
  struct window_copy_mode_data  *data = wme->data;
857
0
  struct grid     *gd = data->backing->grid;
858
859
0
  return (format_grid_word(gd, x, gd->hsize + y - data->oy));
860
0
}
861
862
char *
863
window_copy_get_line(struct window_pane *wp, u_int y)
864
0
{
865
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
866
0
  struct window_copy_mode_data  *data = wme->data;
867
0
  struct grid     *gd = data->screen.grid;
868
869
0
  return (format_grid_line(gd, gd->hsize + y));
870
0
}
871
872
char *
873
window_copy_get_hyperlink(struct window_pane *wp, u_int x, u_int y)
874
0
{
875
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
876
0
  struct window_copy_mode_data  *data = wme->data;
877
0
  struct grid     *gd = data->screen.grid;
878
879
0
  return (format_grid_hyperlink(gd, x, gd->hsize + y, wp->screen));
880
0
}
881
882
static void *
883
window_copy_cursor_hyperlink_cb(struct format_tree *ft)
884
0
{
885
0
  struct window_pane    *wp = format_get_pane(ft);
886
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
887
0
  struct window_copy_mode_data  *data = wme->data;
888
0
  struct grid     *gd = data->screen.grid;
889
890
0
  return (format_grid_hyperlink(gd, data->cx, gd->hsize + data->cy,
891
0
      &data->screen));
892
0
}
893
894
static void *
895
window_copy_cursor_word_cb(struct format_tree *ft)
896
0
{
897
0
  struct window_pane    *wp = format_get_pane(ft);
898
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
899
0
  struct window_copy_mode_data  *data = wme->data;
900
901
0
  return (window_copy_get_word(wp, data->cx, data->cy));
902
0
}
903
904
static void *
905
window_copy_cursor_line_cb(struct format_tree *ft)
906
0
{
907
0
  struct window_pane    *wp = format_get_pane(ft);
908
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
909
0
  struct window_copy_mode_data  *data = wme->data;
910
911
0
  return (window_copy_get_line(wp, data->cy));
912
0
}
913
914
static void *
915
window_copy_search_match_cb(struct format_tree *ft)
916
0
{
917
0
  struct window_pane    *wp = format_get_pane(ft);
918
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
919
0
  struct window_copy_mode_data  *data = wme->data;
920
921
0
  return (window_copy_match_at_cursor(data));
922
0
}
923
924
static void
925
window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
926
0
{
927
0
  struct window_copy_mode_data  *data = wme->data;
928
0
  u_int        hsize = screen_hsize(data->backing);
929
0
  struct grid_line    *gl;
930
931
0
  gl = grid_get_line(data->backing->grid, hsize - data->oy);
932
0
  format_add(ft, "top_line_time", "%llu", (unsigned long long)gl->time);
933
934
0
  format_add(ft, "scroll_position", "%d", data->oy);
935
0
  format_add(ft, "rectangle_toggle", "%d", data->rectflag);
936
937
0
  format_add(ft, "copy_cursor_x", "%d", data->cx);
938
0
  format_add(ft, "copy_cursor_y", "%d", data->cy);
939
940
0
  if (data->screen.sel != NULL) {
941
0
    format_add(ft, "selection_start_x", "%d", data->selx);
942
0
    format_add(ft, "selection_start_y", "%d", data->sely);
943
0
    format_add(ft, "selection_end_x", "%d", data->endselx);
944
0
    format_add(ft, "selection_end_y", "%d", data->endsely);
945
946
0
    if (data->cursordrag != CURSORDRAG_NONE)
947
0
      format_add(ft, "selection_active", "1");
948
0
    else
949
0
      format_add(ft, "selection_active", "0");
950
0
    if (data->endselx != data->selx || data->endsely != data->sely)
951
0
      format_add(ft, "selection_present", "1");
952
0
    else
953
0
      format_add(ft, "selection_present", "0");
954
0
  } else {
955
0
    format_add(ft, "selection_active", "0");
956
0
    format_add(ft, "selection_present", "0");
957
0
  }
958
959
0
  format_add(ft, "search_present", "%d", data->searchmark != NULL);
960
0
  format_add(ft, "search_timed_out", "%d", data->timeout);
961
0
  if (data->searchcount != -1) {
962
0
    format_add(ft, "search_count", "%d", data->searchcount);
963
0
    format_add(ft, "search_count_partial", "%d", data->searchmore);
964
0
  }
965
0
  format_add_cb(ft, "search_match", window_copy_search_match_cb);
966
967
0
  format_add_cb(ft, "copy_cursor_word", window_copy_cursor_word_cb);
968
0
  format_add_cb(ft, "copy_cursor_line", window_copy_cursor_line_cb);
969
0
  format_add_cb(ft, "copy_cursor_hyperlink",
970
0
      window_copy_cursor_hyperlink_cb);
971
0
}
972
973
static struct screen *
974
window_copy_get_screen(struct window_mode_entry *wme)
975
0
{
976
0
  struct window_copy_mode_data  *data = wme->data;
977
978
0
  return (data->backing);
979
0
}
980
981
static void
982
window_copy_size_changed(struct window_mode_entry *wme)
983
0
{
984
0
  struct window_copy_mode_data  *data = wme->data;
985
0
  struct screen     *s = &data->screen;
986
0
  struct screen_write_ctx    ctx;
987
0
  int        search = (data->searchmark != NULL);
988
989
0
  window_copy_clear_selection(wme);
990
0
  window_copy_clear_marks(wme);
991
992
0
  screen_write_start(&ctx, s);
993
0
  window_copy_write_lines(wme, &ctx, 0, screen_size_y(s));
994
0
  screen_write_stop(&ctx);
995
996
0
  if (search && !data->timeout)
997
0
    window_copy_search_marks(wme, NULL, data->searchregex, 0);
998
0
  data->searchx = data->cx;
999
0
  data->searchy = data->cy;
1000
0
  data->searcho = data->oy;
1001
0
}
1002
1003
static void
1004
window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
1005
0
{
1006
0
  struct window_copy_mode_data  *data = wme->data;
1007
0
  struct screen     *s = &data->screen;
1008
0
  struct grid     *gd = data->backing->grid;
1009
0
  u_int        cx, cy, wx, wy;
1010
0
  int        reflow;
1011
1012
0
  screen_resize(s, sx, sy, 0);
1013
0
  cx = data->cx;
1014
0
  cy = gd->hsize + data->cy - data->oy;
1015
0
  reflow = (gd->sx != sx);
1016
0
  if (reflow)
1017
0
    grid_wrap_position(gd, cx, cy, &wx, &wy);
1018
0
  screen_resize_cursor(data->backing, sx, sy, 1, 0, 0);
1019
0
  if (reflow)
1020
0
    grid_unwrap_position(gd, &cx, &cy, wx, wy);
1021
1022
0
  data->cx = cx;
1023
0
  if (cy < gd->hsize) {
1024
0
    data->cy = 0;
1025
0
    data->oy = gd->hsize - cy;
1026
0
  } else {
1027
0
    data->cy = cy - gd->hsize;
1028
0
    data->oy = 0;
1029
0
  }
1030
1031
0
  window_copy_size_changed(wme);
1032
0
  window_copy_redraw_screen(wme);
1033
0
}
1034
1035
static const char *
1036
window_copy_key_table(struct window_mode_entry *wme)
1037
0
{
1038
0
  struct window_pane  *wp = wme->wp;
1039
1040
0
  if (options_get_number(wp->window->options, "mode-keys") == MODEKEY_VI)
1041
0
    return ("copy-mode-vi");
1042
0
  return ("copy-mode");
1043
0
}
1044
1045
static int
1046
window_copy_expand_search_string(struct window_copy_cmd_state *cs)
1047
0
{
1048
0
  struct window_mode_entry  *wme = cs->wme;
1049
0
  struct window_copy_mode_data  *data = wme->data;
1050
0
  const char      *ss = args_string(cs->wargs, 0);
1051
0
  char        *expanded;
1052
1053
0
  if (ss == NULL || *ss == '\0')
1054
0
    return (0);
1055
1056
0
  if (args_has(cs->args, 'F')) {
1057
0
    expanded = format_single(NULL, ss, NULL, NULL, NULL, wme->wp);
1058
0
    if (*expanded == '\0') {
1059
0
      free(expanded);
1060
0
      return (0);
1061
0
    }
1062
0
    free(data->searchstr);
1063
0
    data->searchstr = expanded;
1064
0
  } else {
1065
0
    free(data->searchstr);
1066
0
    data->searchstr = xstrdup(ss);
1067
0
  }
1068
0
  return (1);
1069
0
}
1070
1071
static enum window_copy_cmd_action
1072
window_copy_cmd_append_selection(struct window_copy_cmd_state *cs)
1073
0
{
1074
0
  struct window_mode_entry  *wme = cs->wme;
1075
0
  struct session      *s = cs->s;
1076
1077
0
  if (s != NULL)
1078
0
    window_copy_append_selection(wme);
1079
0
  window_copy_clear_selection(wme);
1080
0
  return (WINDOW_COPY_CMD_REDRAW);
1081
0
}
1082
1083
static enum window_copy_cmd_action
1084
window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state *cs)
1085
0
{
1086
0
  struct window_mode_entry  *wme = cs->wme;
1087
0
  struct session      *s = cs->s;
1088
1089
0
  if (s != NULL)
1090
0
    window_copy_append_selection(wme);
1091
0
  window_copy_clear_selection(wme);
1092
0
  return (WINDOW_COPY_CMD_CANCEL);
1093
0
}
1094
1095
static enum window_copy_cmd_action
1096
window_copy_cmd_back_to_indentation(struct window_copy_cmd_state *cs)
1097
0
{
1098
0
  struct window_mode_entry  *wme = cs->wme;
1099
1100
0
  window_copy_cursor_back_to_indentation(wme);
1101
0
  return (WINDOW_COPY_CMD_NOTHING);
1102
0
}
1103
1104
static enum window_copy_cmd_action
1105
window_copy_cmd_begin_selection(struct window_copy_cmd_state *cs)
1106
0
{
1107
0
  struct window_mode_entry  *wme = cs->wme;
1108
0
  struct client     *c = cs->c;
1109
0
  struct mouse_event    *m = cs->m;
1110
0
  struct window_copy_mode_data  *data = wme->data;
1111
1112
0
  if (m != NULL) {
1113
0
    window_copy_start_drag(c, m);
1114
0
    return (WINDOW_COPY_CMD_NOTHING);
1115
0
  }
1116
1117
0
  data->lineflag = LINE_SEL_NONE;
1118
0
  data->selflag = SEL_CHAR;
1119
0
  window_copy_start_selection(wme);
1120
0
  return (WINDOW_COPY_CMD_REDRAW);
1121
0
}
1122
1123
static enum window_copy_cmd_action
1124
window_copy_cmd_stop_selection(struct window_copy_cmd_state *cs)
1125
0
{
1126
0
  struct window_mode_entry  *wme = cs->wme;
1127
0
  struct window_copy_mode_data  *data = wme->data;
1128
1129
0
  data->cursordrag = CURSORDRAG_NONE;
1130
0
  data->lineflag = LINE_SEL_NONE;
1131
0
  data->selflag = SEL_CHAR;
1132
0
  return (WINDOW_COPY_CMD_NOTHING);
1133
0
}
1134
1135
static enum window_copy_cmd_action
1136
window_copy_cmd_bottom_line(struct window_copy_cmd_state *cs)
1137
0
{
1138
0
  struct window_mode_entry  *wme = cs->wme;
1139
0
  struct window_copy_mode_data  *data = wme->data;
1140
1141
0
  data->cx = 0;
1142
0
  data->cy = screen_size_y(&data->screen) - 1;
1143
1144
0
  window_copy_update_selection(wme, 1, 0);
1145
0
  return (WINDOW_COPY_CMD_REDRAW);
1146
0
}
1147
1148
static enum window_copy_cmd_action
1149
window_copy_cmd_cancel(__unused struct window_copy_cmd_state *cs)
1150
0
{
1151
0
  return (WINDOW_COPY_CMD_CANCEL);
1152
0
}
1153
1154
static enum window_copy_cmd_action
1155
window_copy_cmd_clear_selection(struct window_copy_cmd_state *cs)
1156
0
{
1157
0
  struct window_mode_entry  *wme = cs->wme;
1158
1159
0
  window_copy_clear_selection(wme);
1160
0
  return (WINDOW_COPY_CMD_REDRAW);
1161
0
}
1162
1163
static enum window_copy_cmd_action
1164
window_copy_do_copy_end_of_line(struct window_copy_cmd_state *cs, int pipe,
1165
    int cancel)
1166
0
{
1167
0
  struct window_mode_entry   *wme = cs->wme;
1168
0
  struct client      *c = cs->c;
1169
0
  struct session       *s = cs->s;
1170
0
  struct winlink       *wl = cs->wl;
1171
0
  struct window_pane     *wp = wme->wp;
1172
0
  u_int         count = args_count(cs->wargs);
1173
0
  u_int         np = wme->prefix, ocx, ocy, ooy;
1174
0
  struct window_copy_mode_data   *data = wme->data;
1175
0
  char         *prefix = NULL, *command = NULL;
1176
0
  const char       *arg0 = args_string(cs->wargs, 0);
1177
0
  const char       *arg1 = args_string(cs->wargs, 1);
1178
0
  int         set_paste = !args_has(cs->wargs, 'P');
1179
0
  int         set_clip = !args_has(cs->wargs, 'C');
1180
1181
0
  if (pipe) {
1182
0
    if (count == 2)
1183
0
      prefix = format_single(NULL, arg1, c, s, wl, wp);
1184
0
    if (s != NULL && count > 0 && *arg0 != '\0')
1185
0
      command = format_single(NULL, arg0, c, s, wl, wp);
1186
0
  } else {
1187
0
    if (count == 1)
1188
0
      prefix = format_single(NULL, arg0, c, s, wl, wp);
1189
0
  }
1190
1191
0
  ocx = data->cx;
1192
0
  ocy = data->cy;
1193
0
  ooy = data->oy;
1194
1195
0
  window_copy_start_selection(wme);
1196
0
  for (; np > 1; np--)
1197
0
    window_copy_cursor_down(wme, 0);
1198
0
  window_copy_cursor_end_of_line(wme);
1199
1200
0
  if (s != NULL) {
1201
0
    if (pipe)
1202
0
      window_copy_copy_pipe(wme, s, prefix, command,
1203
0
          set_paste, set_clip);
1204
0
    else
1205
0
      window_copy_copy_selection(wme, prefix,
1206
0
          set_paste, set_clip);
1207
1208
0
    if (cancel) {
1209
0
      free(prefix);
1210
0
      free(command);
1211
0
      return (WINDOW_COPY_CMD_CANCEL);
1212
0
    }
1213
0
  }
1214
0
  window_copy_clear_selection(wme);
1215
1216
0
  data->cx = ocx;
1217
0
  data->cy = ocy;
1218
0
  data->oy = ooy;
1219
1220
0
  free(prefix);
1221
0
  free(command);
1222
0
  return (WINDOW_COPY_CMD_REDRAW);
1223
0
}
1224
1225
static enum window_copy_cmd_action
1226
window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state *cs)
1227
0
{
1228
0
  return (window_copy_do_copy_end_of_line(cs, 0, 0));
1229
0
}
1230
1231
static enum window_copy_cmd_action
1232
window_copy_cmd_copy_end_of_line_and_cancel(struct window_copy_cmd_state *cs)
1233
0
{
1234
0
  return (window_copy_do_copy_end_of_line(cs, 0, 1));
1235
0
}
1236
1237
static enum window_copy_cmd_action
1238
window_copy_cmd_copy_pipe_end_of_line(struct window_copy_cmd_state *cs)
1239
0
{
1240
0
  return (window_copy_do_copy_end_of_line(cs, 1, 0));
1241
0
}
1242
1243
static enum window_copy_cmd_action
1244
window_copy_cmd_copy_pipe_end_of_line_and_cancel(
1245
    struct window_copy_cmd_state *cs)
1246
0
{
1247
0
  return (window_copy_do_copy_end_of_line(cs, 1, 1));
1248
0
}
1249
1250
static enum window_copy_cmd_action
1251
window_copy_do_copy_line(struct window_copy_cmd_state *cs, int pipe, int cancel)
1252
0
{
1253
0
  struct window_mode_entry   *wme = cs->wme;
1254
0
  struct client      *c = cs->c;
1255
0
  struct session       *s = cs->s;
1256
0
  struct winlink       *wl = cs->wl;
1257
0
  struct window_pane     *wp = wme->wp;
1258
0
  struct window_copy_mode_data   *data = wme->data;
1259
0
  u_int         count = args_count(cs->wargs);
1260
0
  u_int         np = wme->prefix, ocx, ocy, ooy;
1261
0
  char         *prefix = NULL, *command = NULL;
1262
0
  const char       *arg0 = args_string(cs->wargs, 0);
1263
0
  const char       *arg1 = args_string(cs->wargs, 1);
1264
0
  int         set_paste = !args_has(cs->wargs, 'P');
1265
0
  int         set_clip = !args_has(cs->wargs, 'C');
1266
1267
0
  if (pipe) {
1268
0
    if (count == 2)
1269
0
      prefix = format_single(NULL, arg1, c, s, wl, wp);
1270
0
    if (s != NULL && count > 0 && *arg0 != '\0')
1271
0
      command = format_single(NULL, arg0, c, s, wl, wp);
1272
0
  } else {
1273
0
    if (count == 1)
1274
0
      prefix = format_single(NULL, arg0, c, s, wl, wp);
1275
0
  }
1276
1277
0
  ocx = data->cx;
1278
0
  ocy = data->cy;
1279
0
  ooy = data->oy;
1280
1281
0
  data->selflag = SEL_CHAR;
1282
0
  window_copy_cursor_start_of_line(wme);
1283
0
  window_copy_start_selection(wme);
1284
0
  for (; np > 1; np--)
1285
0
    window_copy_cursor_down(wme, 0);
1286
0
  window_copy_cursor_end_of_line(wme);
1287
1288
0
  if (s != NULL) {
1289
0
    if (pipe)
1290
0
      window_copy_copy_pipe(wme, s, prefix, command,
1291
0
          set_paste, set_clip);
1292
0
    else
1293
0
      window_copy_copy_selection(wme, prefix,
1294
0
          set_paste, set_clip);
1295
1296
0
    if (cancel) {
1297
0
      free(prefix);
1298
0
      free(command);
1299
0
      return (WINDOW_COPY_CMD_CANCEL);
1300
0
    }
1301
0
  }
1302
0
  window_copy_clear_selection(wme);
1303
1304
0
  data->cx = ocx;
1305
0
  data->cy = ocy;
1306
0
  data->oy = ooy;
1307
1308
0
  free(prefix);
1309
0
  free(command);
1310
0
  return (WINDOW_COPY_CMD_REDRAW);
1311
0
}
1312
1313
static enum window_copy_cmd_action
1314
window_copy_cmd_copy_line(struct window_copy_cmd_state *cs)
1315
0
{
1316
0
  return (window_copy_do_copy_line(cs, 0, 0));
1317
0
}
1318
1319
static enum window_copy_cmd_action
1320
window_copy_cmd_copy_line_and_cancel(struct window_copy_cmd_state *cs)
1321
0
{
1322
0
  return (window_copy_do_copy_line(cs, 0, 1));
1323
0
}
1324
1325
static enum window_copy_cmd_action
1326
window_copy_cmd_copy_pipe_line(struct window_copy_cmd_state *cs)
1327
0
{
1328
0
  return (window_copy_do_copy_line(cs, 1, 0));
1329
0
}
1330
1331
static enum window_copy_cmd_action
1332
window_copy_cmd_copy_pipe_line_and_cancel(struct window_copy_cmd_state *cs)
1333
0
{
1334
0
  return (window_copy_do_copy_line(cs, 1, 1));
1335
0
}
1336
1337
static enum window_copy_cmd_action
1338
window_copy_cmd_copy_selection_no_clear(struct window_copy_cmd_state *cs)
1339
0
{
1340
0
  struct window_mode_entry  *wme = cs->wme;
1341
0
  struct client     *c = cs->c;
1342
0
  struct session      *s = cs->s;
1343
0
  struct winlink      *wl = cs->wl;
1344
0
  struct window_pane    *wp = wme->wp;
1345
0
  char        *prefix = NULL;
1346
0
  const char      *arg0 = args_string(cs->wargs, 0);
1347
0
  int        set_paste = !args_has(cs->wargs, 'P');
1348
0
  int        set_clip = !args_has(cs->wargs, 'C');
1349
1350
0
  if (arg0 != NULL)
1351
0
    prefix = format_single(NULL, arg0, c, s, wl, wp);
1352
1353
0
  if (s != NULL)
1354
0
    window_copy_copy_selection(wme, prefix, set_paste, set_clip);
1355
1356
0
  free(prefix);
1357
0
  return (WINDOW_COPY_CMD_NOTHING);
1358
0
}
1359
1360
static enum window_copy_cmd_action
1361
window_copy_cmd_copy_selection(struct window_copy_cmd_state *cs)
1362
0
{
1363
0
  struct window_mode_entry  *wme = cs->wme;
1364
1365
0
  window_copy_cmd_copy_selection_no_clear(cs);
1366
0
  window_copy_clear_selection(wme);
1367
0
  return (WINDOW_COPY_CMD_REDRAW);
1368
0
}
1369
1370
static enum window_copy_cmd_action
1371
window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state *cs)
1372
0
{
1373
0
  struct window_mode_entry  *wme = cs->wme;
1374
1375
0
  window_copy_cmd_copy_selection_no_clear(cs);
1376
0
  window_copy_clear_selection(wme);
1377
0
  return (WINDOW_COPY_CMD_CANCEL);
1378
0
}
1379
1380
static enum window_copy_cmd_action
1381
window_copy_cmd_cursor_down(struct window_copy_cmd_state *cs)
1382
0
{
1383
0
  struct window_mode_entry  *wme = cs->wme;
1384
0
  u_int        np = wme->prefix;
1385
1386
0
  for (; np != 0; np--)
1387
0
    window_copy_cursor_down(wme, 0);
1388
0
  return (WINDOW_COPY_CMD_NOTHING);
1389
0
}
1390
1391
static enum window_copy_cmd_action
1392
window_copy_cmd_cursor_down_and_cancel(struct window_copy_cmd_state *cs)
1393
0
{
1394
0
  struct window_mode_entry  *wme = cs->wme;
1395
0
  struct window_copy_mode_data  *data = wme->data;
1396
0
  u_int        np = wme->prefix, cy;
1397
1398
0
  cy = data->cy;
1399
0
  for (; np != 0; np--)
1400
0
    window_copy_cursor_down(wme, 0);
1401
0
  if (cy == data->cy && data->oy == 0)
1402
0
    return (WINDOW_COPY_CMD_CANCEL);
1403
0
  return (WINDOW_COPY_CMD_NOTHING);
1404
0
}
1405
1406
static enum window_copy_cmd_action
1407
window_copy_cmd_cursor_left(struct window_copy_cmd_state *cs)
1408
0
{
1409
0
  struct window_mode_entry  *wme = cs->wme;
1410
0
  u_int        np = wme->prefix;
1411
1412
0
  for (; np != 0; np--)
1413
0
    window_copy_cursor_left(wme);
1414
0
  return (WINDOW_COPY_CMD_NOTHING);
1415
0
}
1416
1417
static enum window_copy_cmd_action
1418
window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs)
1419
0
{
1420
0
  struct window_mode_entry  *wme = cs->wme;
1421
0
  struct window_copy_mode_data  *data = wme->data;
1422
0
  u_int        np = wme->prefix;
1423
1424
0
  for (; np != 0; np--) {
1425
0
    window_copy_cursor_right(wme, data->screen.sel != NULL &&
1426
0
        data->rectflag);
1427
0
  }
1428
0
  return (WINDOW_COPY_CMD_NOTHING);
1429
0
}
1430
1431
/* Scroll line containing the cursor to the given position. */
1432
static enum window_copy_cmd_action
1433
window_copy_cmd_scroll_to(struct window_copy_cmd_state *cs, u_int to)
1434
0
{
1435
0
  struct window_mode_entry  *wme = cs->wme;
1436
0
  struct window_copy_mode_data  *data = wme->data;
1437
0
  u_int        oy, delta;
1438
0
  int        scroll_up; /* >0 up, <0 down */
1439
1440
0
  scroll_up = data->cy - to;
1441
0
  delta = abs(scroll_up);
1442
0
  oy = screen_hsize(data->backing) - data->oy;
1443
1444
  /*
1445
   * oy is the maximum scroll down amount, while data->oy is the maximum
1446
   * scroll up amount.
1447
   */
1448
0
  if (scroll_up > 0 && data->oy >= delta) {
1449
0
    window_copy_scroll_up(wme, delta);
1450
0
    data->cy -= delta;
1451
0
  } else if (scroll_up < 0 && oy >= delta) {
1452
0
    window_copy_scroll_down(wme, delta);
1453
0
    data->cy += delta;
1454
0
  }
1455
1456
0
  window_copy_update_selection(wme, 0, 0);
1457
0
  return (WINDOW_COPY_CMD_REDRAW);
1458
0
}
1459
1460
/* Scroll line containing the cursor to the bottom. */
1461
static enum window_copy_cmd_action
1462
window_copy_cmd_scroll_bottom(struct window_copy_cmd_state *cs)
1463
0
{
1464
0
  struct window_copy_mode_data  *data = cs->wme->data;
1465
0
  u_int        bottom;
1466
1467
0
  bottom = screen_size_y(&data->screen) - 1;
1468
0
  return (window_copy_cmd_scroll_to(cs, bottom));
1469
0
}
1470
1471
/* Scroll line containing the cursor to the middle. */
1472
static enum window_copy_cmd_action
1473
window_copy_cmd_scroll_middle(struct window_copy_cmd_state *cs)
1474
0
{
1475
0
  struct window_copy_mode_data  *data = cs->wme->data;
1476
0
  u_int        mid_value;
1477
1478
0
  mid_value = (screen_size_y(&data->screen) - 1) / 2;
1479
0
  return (window_copy_cmd_scroll_to(cs, mid_value));
1480
0
}
1481
1482
/* Scroll line containing the cursor to the top. */
1483
static enum window_copy_cmd_action
1484
window_copy_cmd_scroll_top(struct window_copy_cmd_state *cs)
1485
0
{
1486
0
  return (window_copy_cmd_scroll_to(cs, 0));
1487
0
}
1488
1489
static enum window_copy_cmd_action
1490
window_copy_cmd_cursor_up(struct window_copy_cmd_state *cs)
1491
0
{
1492
0
  struct window_mode_entry  *wme = cs->wme;
1493
0
  u_int        np = wme->prefix;
1494
1495
0
  for (; np != 0; np--)
1496
0
    window_copy_cursor_up(wme, 0);
1497
0
  return (WINDOW_COPY_CMD_NOTHING);
1498
0
}
1499
1500
static enum window_copy_cmd_action
1501
window_copy_cmd_centre_vertical(struct window_copy_cmd_state *cs)
1502
0
{
1503
0
  struct window_mode_entry  *wme = cs->wme;
1504
0
  struct window_copy_mode_data  *data = wme->data;
1505
1506
0
  window_copy_update_cursor(wme, data->cx,  wme->wp->sy / 2);
1507
0
  window_copy_update_selection(wme, 1, 0);
1508
0
  return (WINDOW_COPY_CMD_REDRAW);
1509
0
}
1510
1511
static enum window_copy_cmd_action
1512
window_copy_cmd_centre_horizontal(struct window_copy_cmd_state *cs)
1513
0
{
1514
0
  struct window_mode_entry  *wme = cs->wme;
1515
0
  struct window_copy_mode_data  *data = wme->data;
1516
1517
0
  window_copy_update_cursor(wme, wme->wp->sx / 2, data->cy);
1518
0
  window_copy_update_selection(wme, 1, 0);
1519
0
  return (WINDOW_COPY_CMD_REDRAW);
1520
0
}
1521
1522
static enum window_copy_cmd_action
1523
window_copy_cmd_end_of_line(struct window_copy_cmd_state *cs)
1524
0
{
1525
0
  struct window_mode_entry  *wme = cs->wme;
1526
1527
0
  window_copy_cursor_end_of_line(wme);
1528
0
  return (WINDOW_COPY_CMD_NOTHING);
1529
0
}
1530
1531
static enum window_copy_cmd_action
1532
window_copy_cmd_halfpage_down(struct window_copy_cmd_state *cs)
1533
0
{
1534
0
  struct window_mode_entry  *wme = cs->wme;
1535
0
  struct window_copy_mode_data  *data = wme->data;
1536
0
  u_int        np = wme->prefix;
1537
1538
0
  for (; np != 0; np--) {
1539
0
    if (window_copy_pagedown1(wme, 1, data->scroll_exit))
1540
0
      return (WINDOW_COPY_CMD_CANCEL);
1541
0
  }
1542
0
  return (WINDOW_COPY_CMD_NOTHING);
1543
0
}
1544
1545
static enum window_copy_cmd_action
1546
window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state *cs)
1547
0
{
1548
1549
0
  struct window_mode_entry  *wme = cs->wme;
1550
0
  u_int        np = wme->prefix;
1551
1552
0
  for (; np != 0; np--) {
1553
0
    if (window_copy_pagedown1(wme, 1, 1))
1554
0
      return (WINDOW_COPY_CMD_CANCEL);
1555
0
  }
1556
0
  return (WINDOW_COPY_CMD_NOTHING);
1557
0
}
1558
1559
static enum window_copy_cmd_action
1560
window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs)
1561
0
{
1562
0
  struct window_mode_entry  *wme = cs->wme;
1563
0
  u_int        np = wme->prefix;
1564
1565
0
  for (; np != 0; np--)
1566
0
    window_copy_pageup1(wme, 1);
1567
0
  return (WINDOW_COPY_CMD_NOTHING);
1568
0
}
1569
1570
static enum window_copy_cmd_action
1571
window_copy_cmd_toggle_position(struct window_copy_cmd_state *cs)
1572
0
{
1573
0
  struct window_mode_entry  *wme = cs->wme;
1574
0
  struct window_copy_mode_data  *data = wme->data;
1575
1576
0
  data->hide_position = !data->hide_position;
1577
0
  return (WINDOW_COPY_CMD_REDRAW);
1578
0
}
1579
1580
static enum window_copy_cmd_action
1581
window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
1582
0
{
1583
0
  struct window_mode_entry  *wme = cs->wme;
1584
0
  struct window_copy_mode_data  *data = wme->data;
1585
0
  struct screen     *s = data->backing;
1586
0
  u_int        oy;
1587
1588
0
  oy = screen_hsize(s) + data->cy - data->oy;
1589
0
  if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
1590
0
    window_copy_other_end(wme);
1591
1592
0
  data->cy = screen_size_y(&data->screen) - 1;
1593
0
  data->cx = window_copy_find_length(wme, screen_hsize(s) + data->cy);
1594
0
  data->oy = 0;
1595
1596
0
  if (data->searchmark != NULL && !data->timeout)
1597
0
    window_copy_search_marks(wme, NULL, data->searchregex, 1);
1598
0
  window_copy_update_selection(wme, 1, 0);
1599
0
  return (WINDOW_COPY_CMD_REDRAW);
1600
0
}
1601
1602
static enum window_copy_cmd_action
1603
window_copy_cmd_history_top(struct window_copy_cmd_state *cs)
1604
0
{
1605
0
  struct window_mode_entry  *wme = cs->wme;
1606
0
  struct window_copy_mode_data  *data = wme->data;
1607
0
  u_int        oy;
1608
1609
0
  oy = screen_hsize(data->backing) + data->cy - data->oy;
1610
0
  if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
1611
0
    window_copy_other_end(wme);
1612
1613
0
  data->cy = 0;
1614
0
  data->cx = 0;
1615
0
  data->oy = screen_hsize(data->backing);
1616
1617
0
  if (data->searchmark != NULL && !data->timeout)
1618
0
    window_copy_search_marks(wme, NULL, data->searchregex, 1);
1619
0
  window_copy_update_selection(wme, 1, 0);
1620
0
  return (WINDOW_COPY_CMD_REDRAW);
1621
0
}
1622
1623
static enum window_copy_cmd_action
1624
window_copy_cmd_jump_again(struct window_copy_cmd_state *cs)
1625
0
{
1626
0
  struct window_mode_entry  *wme = cs->wme;
1627
0
  struct window_copy_mode_data  *data = wme->data;
1628
0
  u_int        np = wme->prefix;
1629
1630
0
  switch (data->jumptype) {
1631
0
  case WINDOW_COPY_JUMPFORWARD:
1632
0
    for (; np != 0; np--)
1633
0
      window_copy_cursor_jump(wme);
1634
0
    break;
1635
0
  case WINDOW_COPY_JUMPBACKWARD:
1636
0
    for (; np != 0; np--)
1637
0
      window_copy_cursor_jump_back(wme);
1638
0
    break;
1639
0
  case WINDOW_COPY_JUMPTOFORWARD:
1640
0
    for (; np != 0; np--)
1641
0
      window_copy_cursor_jump_to(wme);
1642
0
    break;
1643
0
  case WINDOW_COPY_JUMPTOBACKWARD:
1644
0
    for (; np != 0; np--)
1645
0
      window_copy_cursor_jump_to_back(wme);
1646
0
    break;
1647
0
  }
1648
0
  return (WINDOW_COPY_CMD_NOTHING);
1649
0
}
1650
1651
static enum window_copy_cmd_action
1652
window_copy_cmd_jump_reverse(struct window_copy_cmd_state *cs)
1653
0
{
1654
0
  struct window_mode_entry  *wme = cs->wme;
1655
0
  struct window_copy_mode_data  *data = wme->data;
1656
0
  u_int        np = wme->prefix;
1657
1658
0
  switch (data->jumptype) {
1659
0
  case WINDOW_COPY_JUMPFORWARD:
1660
0
    for (; np != 0; np--)
1661
0
      window_copy_cursor_jump_back(wme);
1662
0
    break;
1663
0
  case WINDOW_COPY_JUMPBACKWARD:
1664
0
    for (; np != 0; np--)
1665
0
      window_copy_cursor_jump(wme);
1666
0
    break;
1667
0
  case WINDOW_COPY_JUMPTOFORWARD:
1668
0
    for (; np != 0; np--)
1669
0
      window_copy_cursor_jump_to_back(wme);
1670
0
    break;
1671
0
  case WINDOW_COPY_JUMPTOBACKWARD:
1672
0
    for (; np != 0; np--)
1673
0
      window_copy_cursor_jump_to(wme);
1674
0
    break;
1675
0
  }
1676
0
  return (WINDOW_COPY_CMD_NOTHING);
1677
0
}
1678
1679
static enum window_copy_cmd_action
1680
window_copy_cmd_middle_line(struct window_copy_cmd_state *cs)
1681
0
{
1682
0
  struct window_mode_entry  *wme = cs->wme;
1683
0
  struct window_copy_mode_data  *data = wme->data;
1684
1685
0
  data->cx = 0;
1686
0
  data->cy = (screen_size_y(&data->screen) - 1) / 2;
1687
1688
0
  window_copy_update_selection(wme, 1, 0);
1689
0
  return (WINDOW_COPY_CMD_REDRAW);
1690
0
}
1691
1692
static enum window_copy_cmd_action
1693
window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state *cs)
1694
0
{
1695
0
  struct window_mode_entry  *wme = cs->wme;
1696
0
  u_int        np = wme->prefix;
1697
0
  struct window_copy_mode_data  *data = wme->data;
1698
0
  struct screen     *s = data->backing;
1699
0
  char         open[] = "{[(", close[] = "}])";
1700
0
  char         tried, found, start, *cp;
1701
0
  u_int        px, py, xx, n;
1702
0
  struct grid_cell     gc;
1703
0
  int        failed;
1704
1705
0
  for (; np != 0; np--) {
1706
    /* Get cursor position and line length. */
1707
0
    px = data->cx;
1708
0
    py = screen_hsize(s) + data->cy - data->oy;
1709
0
    xx = window_copy_find_length(wme, py);
1710
0
    if (xx == 0)
1711
0
      break;
1712
1713
    /*
1714
     * Get the current character. If not on a bracket, try the
1715
     * previous. If still not, then behave like previous-word.
1716
     */
1717
0
    tried = 0;
1718
0
  retry:
1719
0
    grid_get_cell(s->grid, px, py, &gc);
1720
0
    if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING))
1721
0
      cp = NULL;
1722
0
    else {
1723
0
      found = *gc.data.data;
1724
0
      cp = strchr(close, found);
1725
0
    }
1726
0
    if (cp == NULL) {
1727
0
      if (data->modekeys == MODEKEY_EMACS) {
1728
0
        if (!tried && px > 0) {
1729
0
          px--;
1730
0
          tried = 1;
1731
0
          goto retry;
1732
0
        }
1733
0
        window_copy_cursor_previous_word(wme, close, 1);
1734
0
      }
1735
0
      continue;
1736
0
    }
1737
0
    start = open[cp - close];
1738
1739
    /* Walk backward until the matching bracket is reached. */
1740
0
    n = 1;
1741
0
    failed = 0;
1742
0
    do {
1743
0
      if (px == 0) {
1744
0
        if (py == 0) {
1745
0
          failed = 1;
1746
0
          break;
1747
0
        }
1748
0
        do {
1749
0
          py--;
1750
0
          xx = window_copy_find_length(wme, py);
1751
0
        } while (xx == 0 && py > 0);
1752
0
        if (xx == 0 && py == 0) {
1753
0
          failed = 1;
1754
0
          break;
1755
0
        }
1756
0
        px = xx - 1;
1757
0
      } else
1758
0
        px--;
1759
1760
0
      grid_get_cell(s->grid, px, py, &gc);
1761
0
      if (gc.data.size == 1 &&
1762
0
          (~gc.flags & GRID_FLAG_PADDING)) {
1763
0
        if (*gc.data.data == found)
1764
0
          n++;
1765
0
        else if (*gc.data.data == start)
1766
0
          n--;
1767
0
      }
1768
0
    } while (n != 0);
1769
1770
    /* Move the cursor to the found location if any. */
1771
0
    if (!failed)
1772
0
      window_copy_scroll_to(wme, px, py, 0);
1773
0
  }
1774
1775
0
  return (WINDOW_COPY_CMD_NOTHING);
1776
0
}
1777
1778
static enum window_copy_cmd_action
1779
window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state *cs)
1780
0
{
1781
0
  struct window_mode_entry  *wme = cs->wme;
1782
0
  u_int        np = wme->prefix;
1783
0
  struct window_copy_mode_data  *data = wme->data;
1784
0
  struct screen     *s = data->backing;
1785
0
  char         open[] = "{[(", close[] = "}])";
1786
0
  char         tried, found, end, *cp;
1787
0
  u_int        px, py, xx, yy, sx, sy, n;
1788
0
  struct grid_cell     gc;
1789
0
  int        failed;
1790
0
  struct grid_line    *gl;
1791
1792
0
  for (; np != 0; np--) {
1793
    /* Get cursor position and line length. */
1794
0
    px = data->cx;
1795
0
    py = screen_hsize(s) + data->cy - data->oy;
1796
0
    xx = window_copy_find_length(wme, py);
1797
0
    yy = screen_hsize(s) + screen_size_y(s) - 1;
1798
0
    if (xx == 0)
1799
0
      break;
1800
1801
    /*
1802
     * Get the current character. If not on a bracket, try the
1803
     * next. If still not, then behave like next-word.
1804
     */
1805
0
    tried = 0;
1806
0
  retry:
1807
0
    grid_get_cell(s->grid, px, py, &gc);
1808
0
    if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING))
1809
0
      cp = NULL;
1810
0
    else {
1811
0
      found = *gc.data.data;
1812
1813
      /*
1814
       * In vi mode, attempt to move to previous bracket if a
1815
       * closing bracket is found first. If this fails,
1816
       * return to the original cursor position.
1817
       */
1818
0
      cp = strchr(close, found);
1819
0
      if (cp != NULL && data->modekeys == MODEKEY_VI) {
1820
0
        sx = data->cx;
1821
0
        sy = screen_hsize(s) + data->cy - data->oy;
1822
1823
0
        window_copy_scroll_to(wme, px, py, 0);
1824
0
        window_copy_cmd_previous_matching_bracket(cs);
1825
1826
0
        px = data->cx;
1827
0
        py = screen_hsize(s) + data->cy - data->oy;
1828
0
        grid_get_cell(s->grid, px, py, &gc);
1829
0
        if (gc.data.size == 1 &&
1830
0
            (~gc.flags & GRID_FLAG_PADDING) &&
1831
0
            strchr(close, *gc.data.data) != NULL)
1832
0
          window_copy_scroll_to(wme, sx, sy, 0);
1833
0
        break;
1834
0
      }
1835
1836
0
      cp = strchr(open, found);
1837
0
    }
1838
0
    if (cp == NULL) {
1839
0
      if (data->modekeys == MODEKEY_EMACS) {
1840
0
        if (!tried && px <= xx) {
1841
0
          px++;
1842
0
          tried = 1;
1843
0
          goto retry;
1844
0
        }
1845
0
        window_copy_cursor_next_word_end(wme, open, 0);
1846
0
        continue;
1847
0
      }
1848
      /* For vi, continue searching for bracket until EOL. */
1849
0
      if (px > xx) {
1850
0
        if (py == yy)
1851
0
          continue;
1852
0
        gl = grid_get_line(s->grid, py);
1853
0
        if (~gl->flags & GRID_LINE_WRAPPED)
1854
0
          continue;
1855
0
        if (gl->cellsize > s->grid->sx)
1856
0
          continue;
1857
0
        px = 0;
1858
0
        py++;
1859
0
        xx = window_copy_find_length(wme, py);
1860
0
      } else
1861
0
        px++;
1862
0
      goto retry;
1863
0
    }
1864
0
    end = close[cp - open];
1865
1866
    /* Walk forward until the matching bracket is reached. */
1867
0
    n = 1;
1868
0
    failed = 0;
1869
0
    do {
1870
0
      if (px > xx) {
1871
0
        if (py == yy) {
1872
0
          failed = 1;
1873
0
          break;
1874
0
        }
1875
0
        px = 0;
1876
0
        py++;
1877
0
        xx = window_copy_find_length(wme, py);
1878
0
      } else
1879
0
        px++;
1880
1881
0
      grid_get_cell(s->grid, px, py, &gc);
1882
0
      if (gc.data.size == 1 &&
1883
0
          (~gc.flags & GRID_FLAG_PADDING)) {
1884
0
        if (*gc.data.data == found)
1885
0
          n++;
1886
0
        else if (*gc.data.data == end)
1887
0
          n--;
1888
0
      }
1889
0
    } while (n != 0);
1890
1891
    /* Move the cursor to the found location if any. */
1892
0
    if (!failed)
1893
0
      window_copy_scroll_to(wme, px, py, 0);
1894
0
  }
1895
1896
0
  return (WINDOW_COPY_CMD_NOTHING);
1897
0
}
1898
1899
static enum window_copy_cmd_action
1900
window_copy_cmd_next_paragraph(struct window_copy_cmd_state *cs)
1901
0
{
1902
0
  struct window_mode_entry  *wme = cs->wme;
1903
0
  u_int        np = wme->prefix;
1904
1905
0
  for (; np != 0; np--)
1906
0
    window_copy_next_paragraph(wme);
1907
0
  return (WINDOW_COPY_CMD_NOTHING);
1908
0
}
1909
1910
static enum window_copy_cmd_action
1911
window_copy_cmd_next_space(struct window_copy_cmd_state *cs)
1912
0
{
1913
0
  struct window_mode_entry  *wme = cs->wme;
1914
0
  u_int        np = wme->prefix;
1915
1916
0
  for (; np != 0; np--)
1917
0
    window_copy_cursor_next_word(wme, "");
1918
0
  return (WINDOW_COPY_CMD_NOTHING);
1919
0
}
1920
1921
static enum window_copy_cmd_action
1922
window_copy_cmd_next_space_end(struct window_copy_cmd_state *cs)
1923
0
{
1924
0
  struct window_mode_entry  *wme = cs->wme;
1925
0
  u_int        np = wme->prefix;
1926
1927
0
  for (; np != 0; np--)
1928
0
    window_copy_cursor_next_word_end(wme, "", 0);
1929
0
  return (WINDOW_COPY_CMD_NOTHING);
1930
0
}
1931
1932
static enum window_copy_cmd_action
1933
window_copy_cmd_next_word(struct window_copy_cmd_state *cs)
1934
0
{
1935
0
  struct window_mode_entry  *wme = cs->wme;
1936
0
  u_int        np = wme->prefix;
1937
0
  const char      *separators;
1938
1939
0
  separators = options_get_string(cs->s->options, "word-separators");
1940
1941
0
  for (; np != 0; np--)
1942
0
    window_copy_cursor_next_word(wme, separators);
1943
0
  return (WINDOW_COPY_CMD_NOTHING);
1944
0
}
1945
1946
static enum window_copy_cmd_action
1947
window_copy_cmd_next_word_end(struct window_copy_cmd_state *cs)
1948
0
{
1949
0
  struct window_mode_entry  *wme = cs->wme;
1950
0
  u_int        np = wme->prefix;
1951
0
  const char      *separators;
1952
1953
0
  separators = options_get_string(cs->s->options, "word-separators");
1954
1955
0
  for (; np != 0; np--)
1956
0
    window_copy_cursor_next_word_end(wme, separators, 0);
1957
0
  return (WINDOW_COPY_CMD_NOTHING);
1958
0
}
1959
1960
static enum window_copy_cmd_action
1961
window_copy_cmd_other_end(struct window_copy_cmd_state *cs)
1962
0
{
1963
0
  struct window_mode_entry  *wme = cs->wme;
1964
0
  u_int        np = wme->prefix;
1965
0
  struct window_copy_mode_data  *data = wme->data;
1966
1967
0
  data->selflag = SEL_CHAR;
1968
0
  if ((np % 2) != 0)
1969
0
    window_copy_other_end(wme);
1970
0
  return (WINDOW_COPY_CMD_NOTHING);
1971
0
}
1972
1973
static enum window_copy_cmd_action
1974
window_copy_cmd_selection_mode(struct window_copy_cmd_state *cs)
1975
0
{
1976
0
  struct window_mode_entry  *wme = cs->wme;
1977
0
  struct options      *so = cs->s->options;
1978
0
  struct window_copy_mode_data  *data = wme->data;
1979
0
  const char      *s = args_string(cs->wargs, 0);
1980
1981
0
  if (s == NULL || strcasecmp(s, "char") == 0 || strcasecmp(s, "c") == 0)
1982
0
    data->selflag = SEL_CHAR;
1983
0
  else if (strcasecmp(s, "word") == 0 || strcasecmp(s, "w") == 0) {
1984
0
    data->separators = options_get_string(so, "word-separators");
1985
0
    data->selflag = SEL_WORD;
1986
0
  } else if (strcasecmp(s, "line") == 0 || strcasecmp(s, "l") == 0)
1987
0
    data->selflag = SEL_LINE;
1988
0
  return (WINDOW_COPY_CMD_NOTHING);
1989
0
}
1990
1991
static enum window_copy_cmd_action
1992
window_copy_cmd_page_down(struct window_copy_cmd_state *cs)
1993
0
{
1994
0
  struct window_mode_entry  *wme = cs->wme;
1995
0
  struct window_copy_mode_data  *data = wme->data;
1996
0
  u_int        np = wme->prefix;
1997
1998
0
  for (; np != 0; np--) {
1999
0
    if (window_copy_pagedown1(wme, 0, data->scroll_exit))
2000
0
      return (WINDOW_COPY_CMD_CANCEL);
2001
0
  }
2002
0
  return (WINDOW_COPY_CMD_NOTHING);
2003
0
}
2004
2005
static enum window_copy_cmd_action
2006
window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state *cs)
2007
0
{
2008
0
  struct window_mode_entry  *wme = cs->wme;
2009
0
  u_int        np = wme->prefix;
2010
2011
0
  for (; np != 0; np--) {
2012
0
    if (window_copy_pagedown1(wme, 0, 1))
2013
0
      return (WINDOW_COPY_CMD_CANCEL);
2014
0
  }
2015
0
  return (WINDOW_COPY_CMD_NOTHING);
2016
0
}
2017
2018
static enum window_copy_cmd_action
2019
window_copy_cmd_page_up(struct window_copy_cmd_state *cs)
2020
0
{
2021
0
  struct window_mode_entry  *wme = cs->wme;
2022
0
  u_int        np = wme->prefix;
2023
2024
0
  for (; np != 0; np--)
2025
0
    window_copy_pageup1(wme, 0);
2026
0
  return (WINDOW_COPY_CMD_NOTHING);
2027
0
}
2028
2029
static enum window_copy_cmd_action
2030
window_copy_cmd_previous_paragraph(struct window_copy_cmd_state *cs)
2031
0
{
2032
0
  struct window_mode_entry  *wme = cs->wme;
2033
0
  u_int        np = wme->prefix;
2034
2035
0
  for (; np != 0; np--)
2036
0
    window_copy_previous_paragraph(wme);
2037
0
  return (WINDOW_COPY_CMD_NOTHING);
2038
0
}
2039
2040
static enum window_copy_cmd_action
2041
window_copy_cmd_previous_space(struct window_copy_cmd_state *cs)
2042
0
{
2043
0
  struct window_mode_entry  *wme = cs->wme;
2044
0
  u_int        np = wme->prefix;
2045
2046
0
  for (; np != 0; np--)
2047
0
    window_copy_cursor_previous_word(wme, "", 1);
2048
0
  return (WINDOW_COPY_CMD_NOTHING);
2049
0
}
2050
2051
static enum window_copy_cmd_action
2052
window_copy_cmd_previous_word(struct window_copy_cmd_state *cs)
2053
0
{
2054
0
  struct window_mode_entry  *wme = cs->wme;
2055
0
  u_int        np = wme->prefix;
2056
0
  const char      *separators;
2057
2058
0
  separators = options_get_string(cs->s->options, "word-separators");
2059
2060
0
  for (; np != 0; np--)
2061
0
    window_copy_cursor_previous_word(wme, separators, 1);
2062
0
  return (WINDOW_COPY_CMD_NOTHING);
2063
0
}
2064
2065
static enum window_copy_cmd_action
2066
window_copy_cmd_rectangle_on(struct window_copy_cmd_state *cs)
2067
0
{
2068
0
  struct window_mode_entry  *wme = cs->wme;
2069
0
  struct window_copy_mode_data  *data = wme->data;
2070
2071
0
  data->lineflag = LINE_SEL_NONE;
2072
0
  window_copy_rectangle_set(wme, 1);
2073
2074
0
  return (WINDOW_COPY_CMD_NOTHING);
2075
0
}
2076
2077
static enum window_copy_cmd_action
2078
window_copy_cmd_rectangle_off(struct window_copy_cmd_state *cs)
2079
0
{
2080
0
  struct window_mode_entry  *wme = cs->wme;
2081
0
  struct window_copy_mode_data  *data = wme->data;
2082
2083
0
  data->lineflag = LINE_SEL_NONE;
2084
0
  window_copy_rectangle_set(wme, 0);
2085
2086
0
  return (WINDOW_COPY_CMD_NOTHING);
2087
0
}
2088
2089
static enum window_copy_cmd_action
2090
window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state *cs)
2091
0
{
2092
0
  struct window_mode_entry  *wme = cs->wme;
2093
0
  struct window_copy_mode_data  *data = wme->data;
2094
2095
0
  data->lineflag = LINE_SEL_NONE;
2096
0
  window_copy_rectangle_set(wme, !data->rectflag);
2097
2098
0
  return (WINDOW_COPY_CMD_NOTHING);
2099
0
}
2100
2101
static enum window_copy_cmd_action
2102
window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs)
2103
0
{
2104
0
  struct window_mode_entry  *wme = cs->wme;
2105
0
  struct window_copy_mode_data  *data = wme->data;
2106
0
  u_int        np = wme->prefix;
2107
2108
0
  for (; np != 0; np--)
2109
0
    window_copy_cursor_down(wme, 1);
2110
0
  if (data->scroll_exit && data->oy == 0)
2111
0
    return (WINDOW_COPY_CMD_CANCEL);
2112
0
  return (WINDOW_COPY_CMD_NOTHING);
2113
0
}
2114
2115
static enum window_copy_cmd_action
2116
window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state *cs)
2117
0
{
2118
0
  struct window_mode_entry  *wme = cs->wme;
2119
0
  struct window_copy_mode_data  *data = wme->data;
2120
0
  u_int        np = wme->prefix;
2121
2122
0
  for (; np != 0; np--)
2123
0
    window_copy_cursor_down(wme, 1);
2124
0
  if (data->oy == 0)
2125
0
    return (WINDOW_COPY_CMD_CANCEL);
2126
0
  return (WINDOW_COPY_CMD_NOTHING);
2127
0
}
2128
2129
static enum window_copy_cmd_action
2130
window_copy_cmd_scroll_up(struct window_copy_cmd_state *cs)
2131
0
{
2132
0
  struct window_mode_entry  *wme = cs->wme;
2133
0
  u_int        np = wme->prefix;
2134
2135
0
  for (; np != 0; np--)
2136
0
    window_copy_cursor_up(wme, 1);
2137
0
  return (WINDOW_COPY_CMD_NOTHING);
2138
0
}
2139
2140
static enum window_copy_cmd_action
2141
window_copy_cmd_search_again(struct window_copy_cmd_state *cs)
2142
0
{
2143
0
  struct window_mode_entry  *wme = cs->wme;
2144
0
  struct window_copy_mode_data  *data = wme->data;
2145
0
  u_int        np = wme->prefix;
2146
2147
0
  if (data->searchtype == WINDOW_COPY_SEARCHUP) {
2148
0
    for (; np != 0; np--)
2149
0
      window_copy_search_up(wme, data->searchregex);
2150
0
  } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
2151
0
    for (; np != 0; np--)
2152
0
      window_copy_search_down(wme, data->searchregex);
2153
0
  }
2154
0
  return (WINDOW_COPY_CMD_NOTHING);
2155
0
}
2156
2157
static enum window_copy_cmd_action
2158
window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs)
2159
0
{
2160
0
  struct window_mode_entry  *wme = cs->wme;
2161
0
  struct window_copy_mode_data  *data = wme->data;
2162
0
  u_int        np = wme->prefix;
2163
2164
0
  if (data->searchtype == WINDOW_COPY_SEARCHUP) {
2165
0
    for (; np != 0; np--)
2166
0
      window_copy_search_down(wme, data->searchregex);
2167
0
  } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
2168
0
    for (; np != 0; np--)
2169
0
      window_copy_search_up(wme, data->searchregex);
2170
0
  }
2171
0
  return (WINDOW_COPY_CMD_NOTHING);
2172
0
}
2173
2174
static enum window_copy_cmd_action
2175
window_copy_cmd_select_line(struct window_copy_cmd_state *cs)
2176
0
{
2177
0
  struct window_mode_entry  *wme = cs->wme;
2178
0
  struct window_copy_mode_data  *data = wme->data;
2179
0
  u_int        np = wme->prefix;
2180
2181
0
  data->lineflag = LINE_SEL_LEFT_RIGHT;
2182
0
  data->rectflag = 0;
2183
0
  data->selflag = SEL_LINE;
2184
0
  data->dx = data->cx;
2185
0
  data->dy = screen_hsize(data->backing) + data->cy - data->oy;
2186
2187
0
  window_copy_cursor_start_of_line(wme);
2188
0
  data->selrx = data->cx;
2189
0
  data->selry = screen_hsize(data->backing) + data->cy - data->oy;
2190
0
  data->endselry = data->selry;
2191
0
  window_copy_start_selection(wme);
2192
0
  window_copy_cursor_end_of_line(wme);
2193
0
  data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
2194
0
  data->endselrx = window_copy_find_length(wme, data->endselry);
2195
0
  for (; np > 1; np--) {
2196
0
    window_copy_cursor_down(wme, 0);
2197
0
    window_copy_cursor_end_of_line(wme);
2198
0
  }
2199
2200
0
  return (WINDOW_COPY_CMD_REDRAW);
2201
0
}
2202
2203
static enum window_copy_cmd_action
2204
window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
2205
0
{
2206
0
  struct window_mode_entry  *wme = cs->wme;
2207
0
  struct options      *so = cs->s->options;
2208
0
  struct window_copy_mode_data  *data = wme->data;
2209
0
  u_int        px, py, nextx, nexty;
2210
2211
0
  data->lineflag = LINE_SEL_LEFT_RIGHT;
2212
0
  data->rectflag = 0;
2213
0
  data->selflag = SEL_WORD;
2214
0
  data->dx = data->cx;
2215
0
  data->dy = screen_hsize(data->backing) + data->cy - data->oy;
2216
2217
0
  data->separators = options_get_string(so, "word-separators");
2218
0
  window_copy_cursor_previous_word(wme, data->separators, 0);
2219
0
  px = data->cx;
2220
0
  py = screen_hsize(data->backing) + data->cy - data->oy;
2221
0
  data->selrx = px;
2222
0
  data->selry = py;
2223
0
  window_copy_start_selection(wme);
2224
2225
  /* Handle single character words. */
2226
0
  nextx = px + 1;
2227
0
  nexty = py;
2228
0
  if (grid_get_line(data->backing->grid, nexty)->flags &
2229
0
      GRID_LINE_WRAPPED && nextx > screen_size_x(data->backing) - 1) {
2230
0
    nextx = 0;
2231
0
    nexty++;
2232
0
  }
2233
0
  if (px >= window_copy_find_length(wme, py) ||
2234
0
      !window_copy_in_set(wme, nextx, nexty, WHITESPACE))
2235
0
    window_copy_cursor_next_word_end(wme, data->separators, 1);
2236
0
  else {
2237
0
    window_copy_update_cursor(wme, px, data->cy);
2238
0
    if (window_copy_update_selection(wme, 1, 1))
2239
0
      window_copy_redraw_lines(wme, data->cy, 1);
2240
0
  }
2241
0
  data->endselrx = data->cx;
2242
0
  data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
2243
0
  if (data->dy > data->endselry) {
2244
0
    data->dy = data->endselry;
2245
0
    data->dx = data->endselrx;
2246
0
  } else if (data->dx > data->endselrx)
2247
0
    data->dx = data->endselrx;
2248
2249
0
  return (WINDOW_COPY_CMD_REDRAW);
2250
0
}
2251
2252
static enum window_copy_cmd_action
2253
window_copy_cmd_set_mark(struct window_copy_cmd_state *cs)
2254
0
{
2255
0
  struct window_copy_mode_data  *data = cs->wme->data;
2256
2257
0
  data->mx = data->cx;
2258
0
  data->my = screen_hsize(data->backing) + data->cy - data->oy;
2259
0
  data->showmark = 1;
2260
0
  return (WINDOW_COPY_CMD_REDRAW);
2261
0
}
2262
2263
static enum window_copy_cmd_action
2264
window_copy_cmd_start_of_line(struct window_copy_cmd_state *cs)
2265
0
{
2266
0
  struct window_mode_entry  *wme = cs->wme;
2267
2268
0
  window_copy_cursor_start_of_line(wme);
2269
0
  return (WINDOW_COPY_CMD_NOTHING);
2270
0
}
2271
2272
static enum window_copy_cmd_action
2273
window_copy_cmd_top_line(struct window_copy_cmd_state *cs)
2274
0
{
2275
0
  struct window_mode_entry  *wme = cs->wme;
2276
0
  struct window_copy_mode_data  *data = wme->data;
2277
2278
0
  data->cx = 0;
2279
0
  data->cy = 0;
2280
2281
0
  window_copy_update_selection(wme, 1, 0);
2282
0
  return (WINDOW_COPY_CMD_REDRAW);
2283
0
}
2284
2285
static enum window_copy_cmd_action
2286
window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state *cs)
2287
0
{
2288
0
  struct window_mode_entry  *wme = cs->wme;
2289
0
  struct client     *c = cs->c;
2290
0
  struct session      *s = cs->s;
2291
0
  struct winlink      *wl = cs->wl;
2292
0
  struct window_pane    *wp = wme->wp;
2293
0
  char        *command = NULL, *prefix = NULL;
2294
0
  const char      *arg0 = args_string(cs->wargs, 0);
2295
0
  const char      *arg1 = args_string(cs->wargs, 1);
2296
0
  int        set_paste = !args_has(cs->wargs, 'P');
2297
0
  int        set_clip = !args_has(cs->wargs, 'C');
2298
2299
0
  if (arg1 != NULL)
2300
0
    prefix = format_single(NULL, arg1, c, s, wl, wp);
2301
2302
0
  if (s != NULL && arg0 != NULL && *arg0 != '\0')
2303
0
    command = format_single(NULL, arg0, c, s, wl, wp);
2304
0
  window_copy_copy_pipe(wme, s, prefix, command,
2305
0
      set_paste, set_clip);
2306
0
  free(command);
2307
2308
0
  free(prefix);
2309
0
  return (WINDOW_COPY_CMD_NOTHING);
2310
0
}
2311
2312
static enum window_copy_cmd_action
2313
window_copy_cmd_copy_pipe(struct window_copy_cmd_state *cs)
2314
0
{
2315
0
  struct window_mode_entry  *wme = cs->wme;
2316
2317
0
  window_copy_cmd_copy_pipe_no_clear(cs);
2318
0
  window_copy_clear_selection(wme);
2319
0
  return (WINDOW_COPY_CMD_REDRAW);
2320
0
}
2321
2322
static enum window_copy_cmd_action
2323
window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state *cs)
2324
0
{
2325
0
  struct window_mode_entry  *wme = cs->wme;
2326
2327
0
  window_copy_cmd_copy_pipe_no_clear(cs);
2328
0
  window_copy_clear_selection(wme);
2329
0
  return (WINDOW_COPY_CMD_CANCEL);
2330
0
}
2331
2332
static enum window_copy_cmd_action
2333
window_copy_cmd_pipe_no_clear(struct window_copy_cmd_state *cs)
2334
0
{
2335
0
  struct window_mode_entry  *wme = cs->wme;
2336
0
  struct client     *c = cs->c;
2337
0
  struct session      *s = cs->s;
2338
0
  struct winlink      *wl = cs->wl;
2339
0
  struct window_pane    *wp = wme->wp;
2340
0
  char        *command = NULL;
2341
0
  const char      *arg0 = args_string(cs->wargs, 0);
2342
2343
0
  if (s != NULL && arg0 != NULL && *arg0 != '\0')
2344
0
    command = format_single(NULL, arg0, c, s, wl, wp);
2345
0
  window_copy_pipe(wme, s, command);
2346
0
  free(command);
2347
2348
0
  return (WINDOW_COPY_CMD_NOTHING);
2349
0
}
2350
2351
static enum window_copy_cmd_action
2352
window_copy_cmd_pipe(struct window_copy_cmd_state *cs)
2353
0
{
2354
0
  struct window_mode_entry  *wme = cs->wme;
2355
2356
0
  window_copy_cmd_pipe_no_clear(cs);
2357
0
  window_copy_clear_selection(wme);
2358
0
  return (WINDOW_COPY_CMD_REDRAW);
2359
0
}
2360
2361
static enum window_copy_cmd_action
2362
window_copy_cmd_pipe_and_cancel(struct window_copy_cmd_state *cs)
2363
0
{
2364
0
  struct window_mode_entry  *wme = cs->wme;
2365
2366
0
  window_copy_cmd_pipe_no_clear(cs);
2367
0
  window_copy_clear_selection(wme);
2368
0
  return (WINDOW_COPY_CMD_CANCEL);
2369
0
}
2370
2371
static enum window_copy_cmd_action
2372
window_copy_cmd_goto_line(struct window_copy_cmd_state *cs)
2373
0
{
2374
0
  struct window_mode_entry  *wme = cs->wme;
2375
0
  const char      *arg0 = args_string(cs->wargs, 0);
2376
2377
0
  if (*arg0 != '\0')
2378
0
    window_copy_goto_line(wme, arg0);
2379
0
  return (WINDOW_COPY_CMD_NOTHING);
2380
0
}
2381
2382
static enum window_copy_cmd_action
2383
window_copy_cmd_jump_backward(struct window_copy_cmd_state *cs)
2384
0
{
2385
0
  struct window_mode_entry  *wme = cs->wme;
2386
0
  struct window_copy_mode_data  *data = wme->data;
2387
0
  u_int        np = wme->prefix;
2388
0
  const char      *arg0 = args_string(cs->wargs, 0);
2389
2390
0
  if (*arg0 != '\0') {
2391
0
    data->jumptype = WINDOW_COPY_JUMPBACKWARD;
2392
0
    free(data->jumpchar);
2393
0
    data->jumpchar = utf8_fromcstr(arg0);
2394
0
    for (; np != 0; np--)
2395
0
      window_copy_cursor_jump_back(wme);
2396
0
  }
2397
0
  return (WINDOW_COPY_CMD_NOTHING);
2398
0
}
2399
2400
static enum window_copy_cmd_action
2401
window_copy_cmd_jump_forward(struct window_copy_cmd_state *cs)
2402
0
{
2403
0
  struct window_mode_entry  *wme = cs->wme;
2404
0
  struct window_copy_mode_data  *data = wme->data;
2405
0
  u_int        np = wme->prefix;
2406
0
  const char      *arg0 = args_string(cs->wargs, 0);
2407
2408
0
  if (*arg0 != '\0') {
2409
0
    data->jumptype = WINDOW_COPY_JUMPFORWARD;
2410
0
    free(data->jumpchar);
2411
0
    data->jumpchar = utf8_fromcstr(arg0);
2412
0
    for (; np != 0; np--)
2413
0
      window_copy_cursor_jump(wme);
2414
0
  }
2415
0
  return (WINDOW_COPY_CMD_NOTHING);
2416
0
}
2417
2418
static enum window_copy_cmd_action
2419
window_copy_cmd_jump_to_backward(struct window_copy_cmd_state *cs)
2420
0
{
2421
0
  struct window_mode_entry  *wme = cs->wme;
2422
0
  struct window_copy_mode_data  *data = wme->data;
2423
0
  u_int        np = wme->prefix;
2424
0
  const char      *arg0 = args_string(cs->wargs, 0);
2425
2426
0
  if (*arg0 != '\0') {
2427
0
    data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
2428
0
    free(data->jumpchar);
2429
0
    data->jumpchar = utf8_fromcstr(arg0);
2430
0
    for (; np != 0; np--)
2431
0
      window_copy_cursor_jump_to_back(wme);
2432
0
  }
2433
0
  return (WINDOW_COPY_CMD_NOTHING);
2434
0
}
2435
2436
static enum window_copy_cmd_action
2437
window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs)
2438
0
{
2439
0
  struct window_mode_entry  *wme = cs->wme;
2440
0
  struct window_copy_mode_data  *data = wme->data;
2441
0
  u_int        np = wme->prefix;
2442
0
  const char      *arg0 = args_string(cs->wargs, 0);
2443
2444
0
  if (*arg0 != '\0') {
2445
0
    data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
2446
0
    free(data->jumpchar);
2447
0
    data->jumpchar = utf8_fromcstr(arg0);
2448
0
    for (; np != 0; np--)
2449
0
      window_copy_cursor_jump_to(wme);
2450
0
  }
2451
0
  return (WINDOW_COPY_CMD_NOTHING);
2452
0
}
2453
2454
static enum window_copy_cmd_action
2455
window_copy_cmd_jump_to_mark(struct window_copy_cmd_state *cs)
2456
0
{
2457
0
  struct window_mode_entry  *wme = cs->wme;
2458
2459
0
  window_copy_jump_to_mark(wme);
2460
0
  return (WINDOW_COPY_CMD_NOTHING);
2461
0
}
2462
2463
static enum window_copy_cmd_action
2464
window_copy_cmd_next_prompt(struct window_copy_cmd_state *cs)
2465
0
{
2466
0
  struct window_mode_entry  *wme = cs->wme;
2467
2468
0
  window_copy_cursor_prompt(wme, 1, args_has(cs->wargs, 'o'));
2469
0
  return (WINDOW_COPY_CMD_NOTHING);
2470
0
}
2471
2472
static enum window_copy_cmd_action
2473
window_copy_cmd_previous_prompt(struct window_copy_cmd_state *cs)
2474
0
{
2475
0
  struct window_mode_entry  *wme = cs->wme;
2476
2477
0
  window_copy_cursor_prompt(wme, 0, args_has(cs->wargs, 'o'));
2478
0
  return (WINDOW_COPY_CMD_NOTHING);
2479
0
}
2480
2481
static enum window_copy_cmd_action
2482
window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
2483
0
{
2484
0
  struct window_mode_entry  *wme = cs->wme;
2485
0
  struct window_copy_mode_data  *data = wme->data;
2486
0
  u_int        np = wme->prefix;
2487
2488
0
  if (!window_copy_expand_search_string(cs))
2489
0
    return (WINDOW_COPY_CMD_NOTHING);
2490
2491
0
  if (data->searchstr != NULL) {
2492
0
    data->searchtype = WINDOW_COPY_SEARCHUP;
2493
0
    data->searchregex = 1;
2494
0
    data->timeout = 0;
2495
0
    for (; np != 0; np--)
2496
0
      window_copy_search_up(wme, 1);
2497
0
  }
2498
0
  return (WINDOW_COPY_CMD_NOTHING);
2499
0
}
2500
2501
static enum window_copy_cmd_action
2502
window_copy_cmd_search_backward_text(struct window_copy_cmd_state *cs)
2503
0
{
2504
0
  struct window_mode_entry  *wme = cs->wme;
2505
0
  struct window_copy_mode_data  *data = wme->data;
2506
0
  u_int        np = wme->prefix;
2507
2508
0
  if (!window_copy_expand_search_string(cs))
2509
0
    return (WINDOW_COPY_CMD_NOTHING);
2510
2511
0
  if (data->searchstr != NULL) {
2512
0
    data->searchtype = WINDOW_COPY_SEARCHUP;
2513
0
    data->searchregex = 0;
2514
0
    data->timeout = 0;
2515
0
    for (; np != 0; np--)
2516
0
      window_copy_search_up(wme, 0);
2517
0
  }
2518
0
  return (WINDOW_COPY_CMD_NOTHING);
2519
0
}
2520
2521
static enum window_copy_cmd_action
2522
window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
2523
0
{
2524
0
  struct window_mode_entry  *wme = cs->wme;
2525
0
  struct window_copy_mode_data  *data = wme->data;
2526
0
  u_int        np = wme->prefix;
2527
2528
0
  if (!window_copy_expand_search_string(cs))
2529
0
    return (WINDOW_COPY_CMD_NOTHING);
2530
2531
0
  if (data->searchstr != NULL) {
2532
0
    data->searchtype = WINDOW_COPY_SEARCHDOWN;
2533
0
    data->searchregex = 1;
2534
0
    data->timeout = 0;
2535
0
    for (; np != 0; np--)
2536
0
      window_copy_search_down(wme, 1);
2537
0
  }
2538
0
  return (WINDOW_COPY_CMD_NOTHING);
2539
0
}
2540
2541
static enum window_copy_cmd_action
2542
window_copy_cmd_search_forward_text(struct window_copy_cmd_state *cs)
2543
0
{
2544
0
  struct window_mode_entry  *wme = cs->wme;
2545
0
  struct window_copy_mode_data  *data = wme->data;
2546
0
  u_int        np = wme->prefix;
2547
2548
0
  if (!window_copy_expand_search_string(cs))
2549
0
    return (WINDOW_COPY_CMD_NOTHING);
2550
2551
0
  if (data->searchstr != NULL) {
2552
0
    data->searchtype = WINDOW_COPY_SEARCHDOWN;
2553
0
    data->searchregex = 0;
2554
0
    data->timeout = 0;
2555
0
    for (; np != 0; np--)
2556
0
      window_copy_search_down(wme, 0);
2557
0
  }
2558
0
  return (WINDOW_COPY_CMD_NOTHING);
2559
0
}
2560
2561
static enum window_copy_cmd_action
2562
window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
2563
0
{
2564
0
  struct window_mode_entry  *wme = cs->wme;
2565
0
  struct window_copy_mode_data  *data = wme->data;
2566
0
  const char      *arg0 = args_string(cs->wargs, 0);
2567
0
  const char      *ss = data->searchstr;
2568
0
  char         prefix;
2569
0
  enum window_copy_cmd_action  action = WINDOW_COPY_CMD_NOTHING;
2570
2571
0
  data->timeout = 0;
2572
2573
0
  log_debug("%s: %s", __func__, arg0);
2574
2575
0
  prefix = *arg0++;
2576
0
  if (data->searchx == -1 || data->searchy == -1) {
2577
0
    data->searchx = data->cx;
2578
0
    data->searchy = data->cy;
2579
0
    data->searcho = data->oy;
2580
0
  } else if (ss != NULL && strcmp(arg0, ss) != 0) {
2581
0
    data->cx = data->searchx;
2582
0
    data->cy = data->searchy;
2583
0
    data->oy = data->searcho;
2584
0
    action = WINDOW_COPY_CMD_REDRAW;
2585
0
  }
2586
0
  if (*arg0 == '\0') {
2587
0
    window_copy_clear_marks(wme);
2588
0
    return (WINDOW_COPY_CMD_REDRAW);
2589
0
  }
2590
0
  switch (prefix) {
2591
0
  case '=':
2592
0
  case '-':
2593
0
    data->searchtype = WINDOW_COPY_SEARCHUP;
2594
0
    data->searchregex = 0;
2595
0
    free(data->searchstr);
2596
0
    data->searchstr = xstrdup(arg0);
2597
0
    if (!window_copy_search_up(wme, 0)) {
2598
0
      window_copy_clear_marks(wme);
2599
0
      return (WINDOW_COPY_CMD_REDRAW);
2600
0
    }
2601
0
    break;
2602
0
  case '+':
2603
0
    data->searchtype = WINDOW_COPY_SEARCHDOWN;
2604
0
    data->searchregex = 0;
2605
0
    free(data->searchstr);
2606
0
    data->searchstr = xstrdup(arg0);
2607
0
    if (!window_copy_search_down(wme, 0)) {
2608
0
      window_copy_clear_marks(wme);
2609
0
      return (WINDOW_COPY_CMD_REDRAW);
2610
0
    }
2611
0
    break;
2612
0
  }
2613
0
  return (action);
2614
0
}
2615
2616
static enum window_copy_cmd_action
2617
window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
2618
0
{
2619
0
  struct window_mode_entry  *wme = cs->wme;
2620
0
  struct window_copy_mode_data  *data = wme->data;
2621
0
  const char      *arg0 = args_string(cs->wargs, 0);
2622
0
  const char      *ss = data->searchstr;
2623
0
  char         prefix;
2624
0
  enum window_copy_cmd_action  action = WINDOW_COPY_CMD_NOTHING;
2625
2626
0
  data->timeout = 0;
2627
2628
0
  log_debug("%s: %s", __func__, arg0);
2629
2630
0
  prefix = *arg0++;
2631
0
  if (data->searchx == -1 || data->searchy == -1) {
2632
0
    data->searchx = data->cx;
2633
0
    data->searchy = data->cy;
2634
0
    data->searcho = data->oy;
2635
0
  } else if (ss != NULL && strcmp(arg0, ss) != 0) {
2636
0
    data->cx = data->searchx;
2637
0
    data->cy = data->searchy;
2638
0
    data->oy = data->searcho;
2639
0
    action = WINDOW_COPY_CMD_REDRAW;
2640
0
  }
2641
0
  if (*arg0 == '\0') {
2642
0
    window_copy_clear_marks(wme);
2643
0
    return (WINDOW_COPY_CMD_REDRAW);
2644
0
  }
2645
0
  switch (prefix) {
2646
0
  case '=':
2647
0
  case '+':
2648
0
    data->searchtype = WINDOW_COPY_SEARCHDOWN;
2649
0
    data->searchregex = 0;
2650
0
    free(data->searchstr);
2651
0
    data->searchstr = xstrdup(arg0);
2652
0
    if (!window_copy_search_down(wme, 0)) {
2653
0
      window_copy_clear_marks(wme);
2654
0
      return (WINDOW_COPY_CMD_REDRAW);
2655
0
    }
2656
0
    break;
2657
0
  case '-':
2658
0
    data->searchtype = WINDOW_COPY_SEARCHUP;
2659
0
    data->searchregex = 0;
2660
0
    free(data->searchstr);
2661
0
    data->searchstr = xstrdup(arg0);
2662
0
    if (!window_copy_search_up(wme, 0)) {
2663
0
      window_copy_clear_marks(wme);
2664
0
      return (WINDOW_COPY_CMD_REDRAW);
2665
0
    }
2666
0
  }
2667
0
  return (action);
2668
0
}
2669
2670
static enum window_copy_cmd_action
2671
window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
2672
0
{
2673
0
  struct window_mode_entry  *wme = cs->wme;
2674
0
  struct window_pane    *wp = wme->swp;
2675
0
  struct window_copy_mode_data  *data = wme->data;
2676
2677
0
  if (data->viewmode)
2678
0
    return (WINDOW_COPY_CMD_NOTHING);
2679
2680
0
  screen_free(data->backing);
2681
0
  free(data->backing);
2682
0
  data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
2683
0
      NULL, wme->swp != wme->wp);
2684
2685
0
  window_copy_size_changed(wme);
2686
0
  return (WINDOW_COPY_CMD_REDRAW);
2687
0
}
2688
2689
static const struct {
2690
  const char       *command;
2691
  u_int         minargs;
2692
  u_int         maxargs;
2693
  struct args_parse     args;
2694
  enum window_copy_cmd_clear    clear;
2695
  enum window_copy_cmd_action (*f)(struct window_copy_cmd_state *);
2696
} window_copy_cmd_table[] = {
2697
  { .command = "append-selection",
2698
    .args = { "", 0, 0, NULL },
2699
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2700
    .f = window_copy_cmd_append_selection
2701
  },
2702
  { .command = "append-selection-and-cancel",
2703
    .args = { "", 0, 0, NULL },
2704
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2705
    .f = window_copy_cmd_append_selection_and_cancel
2706
  },
2707
  { .command = "back-to-indentation",
2708
    .args = { "", 0, 0, NULL },
2709
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2710
    .f = window_copy_cmd_back_to_indentation
2711
  },
2712
  { .command = "begin-selection",
2713
    .args = { "", 0, 0, NULL },
2714
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2715
    .f = window_copy_cmd_begin_selection
2716
  },
2717
  { .command = "bottom-line",
2718
    .args = { "", 0, 0, NULL },
2719
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2720
    .f = window_copy_cmd_bottom_line
2721
  },
2722
  { .command = "cancel",
2723
    .args = { "", 0, 0, NULL },
2724
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2725
    .f = window_copy_cmd_cancel
2726
  },
2727
  { .command = "clear-selection",
2728
    .args = { "", 0, 0, NULL },
2729
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2730
    .f = window_copy_cmd_clear_selection
2731
  },
2732
  { .command = "copy-end-of-line",
2733
    .args = { "CP", 0, 1, NULL },
2734
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2735
    .f = window_copy_cmd_copy_end_of_line
2736
  },
2737
  { .command = "copy-end-of-line-and-cancel",
2738
    .args = { "CP", 0, 1, NULL },
2739
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2740
    .f = window_copy_cmd_copy_end_of_line_and_cancel
2741
  },
2742
  { .command = "copy-pipe-end-of-line",
2743
    .args = { "CP", 0, 2, NULL },
2744
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2745
    .f = window_copy_cmd_copy_pipe_end_of_line
2746
  },
2747
  { .command = "copy-pipe-end-of-line-and-cancel",
2748
    .args = { "CP", 0, 2, NULL },
2749
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2750
    .f = window_copy_cmd_copy_pipe_end_of_line_and_cancel
2751
  },
2752
  { .command = "copy-line",
2753
    .args = { "CP", 0, 1, NULL },
2754
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2755
    .f = window_copy_cmd_copy_line
2756
  },
2757
  { .command = "copy-line-and-cancel",
2758
    .args = { "CP", 0, 1, NULL },
2759
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2760
    .f = window_copy_cmd_copy_line_and_cancel
2761
  },
2762
  { .command = "copy-pipe-line",
2763
    .args = { "CP", 0, 2, NULL },
2764
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2765
    .f = window_copy_cmd_copy_pipe_line
2766
  },
2767
  { .command = "copy-pipe-line-and-cancel",
2768
    .args = { "CP", 0, 2, NULL },
2769
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2770
    .f = window_copy_cmd_copy_pipe_line_and_cancel
2771
  },
2772
  { .command = "copy-pipe-no-clear",
2773
    .args = { "CP", 0, 2, NULL },
2774
    .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
2775
    .f = window_copy_cmd_copy_pipe_no_clear
2776
  },
2777
  { .command = "copy-pipe",
2778
    .args = { "CP", 0, 2, NULL },
2779
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2780
    .f = window_copy_cmd_copy_pipe
2781
  },
2782
  { .command = "copy-pipe-and-cancel",
2783
    .args = { "CP", 0, 2, NULL },
2784
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2785
    .f = window_copy_cmd_copy_pipe_and_cancel
2786
  },
2787
  { .command = "copy-selection-no-clear",
2788
    .args = { "CP", 0, 1, NULL },
2789
    .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
2790
    .f = window_copy_cmd_copy_selection_no_clear
2791
  },
2792
  { .command = "copy-selection",
2793
    .args = { "CP", 0, 1, NULL },
2794
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2795
    .f = window_copy_cmd_copy_selection
2796
  },
2797
  { .command = "copy-selection-and-cancel",
2798
    .args = { "CP", 0, 1, NULL },
2799
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2800
    .f = window_copy_cmd_copy_selection_and_cancel
2801
  },
2802
  { .command = "cursor-down",
2803
    .args = { "", 0, 0, NULL },
2804
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2805
    .f = window_copy_cmd_cursor_down
2806
  },
2807
  { .command = "cursor-down-and-cancel",
2808
    .args = { "", 0, 0, NULL },
2809
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2810
    .f = window_copy_cmd_cursor_down_and_cancel
2811
  },
2812
  { .command = "cursor-left",
2813
    .args = { "", 0, 0, NULL },
2814
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2815
    .f = window_copy_cmd_cursor_left
2816
  },
2817
  { .command = "cursor-right",
2818
    .args = { "", 0, 0, NULL },
2819
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2820
    .f = window_copy_cmd_cursor_right
2821
  },
2822
  { .command = "cursor-up",
2823
    .args = { "", 0, 0, NULL },
2824
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2825
    .f = window_copy_cmd_cursor_up
2826
  },
2827
  { .command = "cursor-centre-vertical",
2828
    .args = { "", 0, 0, NULL },
2829
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2830
    .f = window_copy_cmd_centre_vertical,
2831
  },
2832
  { .command = "cursor-centre-horizontal",
2833
    .args = { "", 0, 0, NULL },
2834
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2835
    .f = window_copy_cmd_centre_horizontal,
2836
  },
2837
  { .command = "end-of-line",
2838
    .args = { "", 0, 0, NULL },
2839
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2840
    .f = window_copy_cmd_end_of_line
2841
  },
2842
  { .command = "goto-line",
2843
    .args = { "", 1, 1, NULL },
2844
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2845
    .f = window_copy_cmd_goto_line
2846
  },
2847
  { .command = "halfpage-down",
2848
    .args = { "", 0, 0, NULL },
2849
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2850
    .f = window_copy_cmd_halfpage_down
2851
  },
2852
  { .command = "halfpage-down-and-cancel",
2853
    .args = { "", 0, 0, NULL },
2854
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2855
    .f = window_copy_cmd_halfpage_down_and_cancel
2856
  },
2857
  { .command = "halfpage-up",
2858
    .args = { "", 0, 0, NULL },
2859
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2860
    .f = window_copy_cmd_halfpage_up
2861
  },
2862
  { .command = "history-bottom",
2863
    .args = { "", 0, 0, NULL },
2864
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2865
    .f = window_copy_cmd_history_bottom
2866
  },
2867
  { .command = "history-top",
2868
    .args = { "", 0, 0, NULL },
2869
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2870
    .f = window_copy_cmd_history_top
2871
  },
2872
  { .command = "jump-again",
2873
    .args = { "", 0, 0, NULL },
2874
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2875
    .f = window_copy_cmd_jump_again
2876
  },
2877
  { .command = "jump-backward",
2878
    .args = { "", 1, 1, NULL },
2879
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2880
    .f = window_copy_cmd_jump_backward
2881
  },
2882
  { .command = "jump-forward",
2883
    .args = { "", 1, 1, NULL },
2884
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2885
    .f = window_copy_cmd_jump_forward
2886
  },
2887
  { .command = "jump-reverse",
2888
    .args = { "", 0, 0, NULL },
2889
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2890
    .f = window_copy_cmd_jump_reverse
2891
  },
2892
  { .command = "jump-to-backward",
2893
    .args = { "", 1, 1, NULL },
2894
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2895
    .f = window_copy_cmd_jump_to_backward
2896
  },
2897
  { .command = "jump-to-forward",
2898
    .args = { "", 1, 1, NULL },
2899
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2900
    .f = window_copy_cmd_jump_to_forward
2901
  },
2902
  { .command = "jump-to-mark",
2903
    .args = { "", 0, 0, NULL },
2904
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2905
    .f = window_copy_cmd_jump_to_mark
2906
  },
2907
  { .command = "next-prompt",
2908
    .args = { "o", 0, 0, NULL },
2909
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2910
    .f = window_copy_cmd_next_prompt
2911
  },
2912
  { .command = "previous-prompt",
2913
    .args = { "o", 0, 0, NULL },
2914
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2915
    .f = window_copy_cmd_previous_prompt
2916
  },
2917
  { .command = "middle-line",
2918
    .args = { "", 0, 0, NULL },
2919
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2920
    .f = window_copy_cmd_middle_line
2921
  },
2922
  { .command = "next-matching-bracket",
2923
    .args = { "", 0, 0, NULL },
2924
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2925
    .f = window_copy_cmd_next_matching_bracket
2926
  },
2927
  { .command = "next-paragraph",
2928
    .args = { "", 0, 0, NULL },
2929
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2930
    .f = window_copy_cmd_next_paragraph
2931
  },
2932
  { .command = "next-space",
2933
    .args = { "", 0, 0, NULL },
2934
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2935
    .f = window_copy_cmd_next_space
2936
  },
2937
  { .command = "next-space-end",
2938
    .args = { "", 0, 0, NULL },
2939
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2940
    .f = window_copy_cmd_next_space_end
2941
  },
2942
  { .command = "next-word",
2943
    .args = { "", 0, 0, NULL },
2944
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2945
    .f = window_copy_cmd_next_word
2946
  },
2947
  { .command = "next-word-end",
2948
    .args = { "", 0, 0, NULL },
2949
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2950
    .f = window_copy_cmd_next_word_end
2951
  },
2952
  { .command = "other-end",
2953
    .args = { "", 0, 0, NULL },
2954
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2955
    .f = window_copy_cmd_other_end
2956
  },
2957
  { .command = "page-down",
2958
    .args = { "", 0, 0, NULL },
2959
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2960
    .f = window_copy_cmd_page_down
2961
  },
2962
  { .command = "page-down-and-cancel",
2963
    .args = { "", 0, 0, NULL },
2964
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2965
    .f = window_copy_cmd_page_down_and_cancel
2966
  },
2967
  { .command = "page-up",
2968
    .args = { "", 0, 0, NULL },
2969
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2970
    .f = window_copy_cmd_page_up
2971
  },
2972
  { .command = "pipe-no-clear",
2973
    .args = { "", 0, 1, NULL },
2974
    .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
2975
    .f = window_copy_cmd_pipe_no_clear
2976
  },
2977
  { .command = "pipe",
2978
    .args = { "", 0, 1, NULL },
2979
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2980
    .f = window_copy_cmd_pipe
2981
  },
2982
  { .command = "pipe-and-cancel",
2983
    .args = { "", 0, 1, NULL },
2984
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2985
    .f = window_copy_cmd_pipe_and_cancel
2986
  },
2987
  { .command = "previous-matching-bracket",
2988
    .args = { "", 0, 0, NULL },
2989
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
2990
    .f = window_copy_cmd_previous_matching_bracket
2991
  },
2992
  { .command = "previous-paragraph",
2993
    .args = { "", 0, 0, NULL },
2994
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
2995
    .f = window_copy_cmd_previous_paragraph
2996
  },
2997
  { .command = "previous-space",
2998
    .args = { "", 0, 0, NULL },
2999
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
3000
    .f = window_copy_cmd_previous_space
3001
  },
3002
  { .command = "previous-word",
3003
    .args = { "", 0, 0, NULL },
3004
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
3005
    .f = window_copy_cmd_previous_word
3006
  },
3007
  { .command = "rectangle-on",
3008
    .args = { "", 0, 0, NULL },
3009
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3010
    .f = window_copy_cmd_rectangle_on
3011
  },
3012
  { .command = "rectangle-off",
3013
    .args = { "", 0, 0, NULL },
3014
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3015
    .f = window_copy_cmd_rectangle_off
3016
  },
3017
  { .command = "rectangle-toggle",
3018
    .args = { "", 0, 0, NULL },
3019
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3020
    .f = window_copy_cmd_rectangle_toggle
3021
  },
3022
  { .command = "refresh-from-pane",
3023
    .args = { "", 0, 0, NULL },
3024
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3025
    .f = window_copy_cmd_refresh_from_pane
3026
  },
3027
  { .command = "scroll-bottom",
3028
    .args = { "", 0, 0, NULL },
3029
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3030
    .f = window_copy_cmd_scroll_bottom
3031
  },
3032
  { .command = "scroll-down",
3033
    .args = { "", 0, 0, NULL },
3034
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
3035
    .f = window_copy_cmd_scroll_down
3036
  },
3037
  { .command = "scroll-down-and-cancel",
3038
    .args = { "", 0, 0, NULL },
3039
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3040
    .f = window_copy_cmd_scroll_down_and_cancel
3041
  },
3042
  { .command = "scroll-middle",
3043
    .args = { "", 0, 0, NULL },
3044
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3045
    .f = window_copy_cmd_scroll_middle
3046
  },
3047
  { .command = "scroll-top",
3048
    .args = { "", 0, 0, NULL },
3049
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3050
    .f = window_copy_cmd_scroll_top
3051
  },
3052
  { .command = "scroll-up",
3053
    .args = { "", 0, 0, NULL },
3054
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
3055
    .f = window_copy_cmd_scroll_up
3056
  },
3057
  { .command = "search-again",
3058
    .args = { "", 0, 0, NULL },
3059
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3060
    .f = window_copy_cmd_search_again
3061
  },
3062
  { .command = "search-backward",
3063
    .args = { "", 0, 1, NULL },
3064
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3065
    .f = window_copy_cmd_search_backward
3066
  },
3067
  { .command = "search-backward-text",
3068
    .args = { "", 0, 1, NULL },
3069
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3070
    .f = window_copy_cmd_search_backward_text
3071
  },
3072
  { .command = "search-backward-incremental",
3073
    .args = { "", 1, 1, NULL },
3074
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3075
    .f = window_copy_cmd_search_backward_incremental
3076
  },
3077
  { .command = "search-forward",
3078
    .args = { "", 0, 1, NULL },
3079
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3080
    .f = window_copy_cmd_search_forward
3081
  },
3082
  { .command = "search-forward-text",
3083
    .args = { "", 0, 1, NULL },
3084
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3085
    .f = window_copy_cmd_search_forward_text
3086
  },
3087
  { .command = "search-forward-incremental",
3088
    .args = { "", 1, 1, NULL },
3089
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3090
    .f = window_copy_cmd_search_forward_incremental
3091
  },
3092
  { .command = "search-reverse",
3093
    .args = { "", 0, 0, NULL },
3094
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3095
    .f = window_copy_cmd_search_reverse
3096
  },
3097
  { .command = "select-line",
3098
    .args = { "", 0, 0, NULL },
3099
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3100
    .f = window_copy_cmd_select_line
3101
  },
3102
  { .command = "select-word",
3103
    .args = { "", 0, 0, NULL },
3104
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3105
    .f = window_copy_cmd_select_word
3106
  },
3107
  { .command = "selection-mode",
3108
    .args = { "", 0, 1, NULL },
3109
    .clear = 0,
3110
    .f = window_copy_cmd_selection_mode
3111
  },
3112
  { .command = "set-mark",
3113
    .args = { "", 0, 0, NULL },
3114
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3115
    .f = window_copy_cmd_set_mark
3116
  },
3117
  { .command = "start-of-line",
3118
    .args = { "", 0, 0, NULL },
3119
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
3120
    .f = window_copy_cmd_start_of_line
3121
  },
3122
  { .command = "stop-selection",
3123
    .args = { "", 0, 0, NULL },
3124
    .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
3125
    .f = window_copy_cmd_stop_selection
3126
  },
3127
  { .command = "toggle-position",
3128
    .args = { "", 0, 0, NULL },
3129
    .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
3130
    .f = window_copy_cmd_toggle_position
3131
  },
3132
  { .command = "top-line",
3133
    .args = { "", 0, 0, NULL },
3134
    .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
3135
    .f = window_copy_cmd_top_line
3136
  }
3137
};
3138
3139
static void
3140
window_copy_command(struct window_mode_entry *wme, struct client *c,
3141
    struct session *s, struct winlink *wl, struct args *args,
3142
    struct mouse_event *m)
3143
0
{
3144
0
  struct window_copy_mode_data  *data = wme->data;
3145
0
  struct window_pane    *wp = wme->wp;
3146
0
  struct window_copy_cmd_state   cs;
3147
0
  enum window_copy_cmd_action  action;
3148
0
  enum window_copy_cmd_clear   clear = WINDOW_COPY_CMD_CLEAR_NEVER;
3149
0
  const char      *command;
3150
0
  u_int        i, count = args_count(args);
3151
0
  int        keys;
3152
0
  char        *error = NULL;
3153
3154
0
  if (count == 0)
3155
0
    return;
3156
0
  command = args_string(args, 0);
3157
3158
0
  if (m != NULL && m->valid && !MOUSE_WHEEL(m->b))
3159
0
    window_copy_move_mouse(m);
3160
3161
0
  cs.wme = wme;
3162
0
  cs.args = args;
3163
0
  cs.wargs = NULL;
3164
0
  cs.m = m;
3165
3166
0
  cs.c = c;
3167
0
  cs.s = s;
3168
0
  cs.wl = wl;
3169
3170
0
  action = WINDOW_COPY_CMD_NOTHING;
3171
0
  for (i = 0; i < nitems(window_copy_cmd_table); i++) {
3172
0
    if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
3173
0
      cs.wargs = args_parse(&window_copy_cmd_table[i].args,
3174
0
          args_values(args), count, &error);
3175
3176
0
      if (error != NULL) {
3177
0
        free(error);
3178
0
        error = NULL;
3179
0
      }
3180
0
      if (cs.wargs == NULL)
3181
0
        break;
3182
3183
0
      clear = window_copy_cmd_table[i].clear;
3184
0
      action = window_copy_cmd_table[i].f(&cs);
3185
0
      args_free(cs.wargs);
3186
0
      cs.wargs = NULL;
3187
0
      break;
3188
0
    }
3189
0
  }
3190
3191
0
  if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
3192
0
    keys = options_get_number(wp->window->options, "mode-keys");
3193
0
    if (clear == WINDOW_COPY_CMD_CLEAR_EMACS_ONLY &&
3194
0
        keys == MODEKEY_VI)
3195
0
      clear = WINDOW_COPY_CMD_CLEAR_NEVER;
3196
0
    if (clear != WINDOW_COPY_CMD_CLEAR_NEVER) {
3197
0
      window_copy_clear_marks(wme);
3198
0
      data->searchx = data->searchy = -1;
3199
0
    }
3200
0
    if (action == WINDOW_COPY_CMD_NOTHING)
3201
0
      action = WINDOW_COPY_CMD_REDRAW;
3202
0
  }
3203
0
  wme->prefix = 1;
3204
3205
0
  if (action == WINDOW_COPY_CMD_CANCEL)
3206
0
    window_pane_reset_mode(wp);
3207
0
  else if (action == WINDOW_COPY_CMD_REDRAW)
3208
0
    window_copy_redraw_screen(wme);
3209
0
}
3210
3211
static void
3212
window_copy_scroll_to(struct window_mode_entry *wme, u_int px, u_int py,
3213
    int no_redraw)
3214
0
{
3215
0
  struct window_copy_mode_data  *data = wme->data;
3216
0
  struct grid     *gd = data->backing->grid;
3217
0
  u_int        offset, gap;
3218
3219
0
  data->cx = px;
3220
3221
0
  if (py >= gd->hsize - data->oy && py < gd->hsize - data->oy + gd->sy)
3222
0
    data->cy = py - (gd->hsize - data->oy);
3223
0
  else {
3224
0
    gap = gd->sy / 4;
3225
0
    if (py < gd->sy) {
3226
0
      offset = 0;
3227
0
      data->cy = py;
3228
0
    } else if (py > gd->hsize + gd->sy - gap) {
3229
0
      offset = gd->hsize;
3230
0
      data->cy = py - gd->hsize;
3231
0
    } else {
3232
0
      offset = py + gap - gd->sy;
3233
0
      data->cy = py - offset;
3234
0
    }
3235
0
    data->oy = gd->hsize - offset;
3236
0
  }
3237
3238
0
  if (!no_redraw && data->searchmark != NULL && !data->timeout)
3239
0
    window_copy_search_marks(wme, NULL, data->searchregex, 1);
3240
0
  window_copy_update_selection(wme, 1, 0);
3241
0
  if (!no_redraw)
3242
0
    window_copy_redraw_screen(wme);
3243
0
}
3244
3245
static int
3246
window_copy_search_compare(struct grid *gd, u_int px, u_int py,
3247
    struct grid *sgd, u_int spx, int cis)
3248
0
{
3249
0
  struct grid_cell   gc, sgc;
3250
0
  const struct utf8_data  *ud, *sud;
3251
3252
0
  grid_get_cell(gd, px, py, &gc);
3253
0
  ud = &gc.data;
3254
0
  grid_get_cell(sgd, spx, 0, &sgc);
3255
0
  sud = &sgc.data;
3256
3257
0
  if (*sud->data == '\t' && sud->size == 1 && gc.flags & GRID_FLAG_TAB)
3258
0
    return (1);
3259
3260
0
  if (ud->size != sud->size || ud->width != sud->width)
3261
0
    return (0);
3262
3263
0
  if (cis && ud->size == 1)
3264
0
    return (tolower(ud->data[0]) == sud->data[0]);
3265
3266
0
  return (memcmp(ud->data, sud->data, ud->size) == 0);
3267
0
}
3268
3269
static int
3270
window_copy_search_lr(struct grid *gd, struct grid *sgd, u_int *ppx, u_int py,
3271
    u_int first, u_int last, int cis)
3272
0
{
3273
0
  u_int      ax, bx, px, pywrap, endline, padding;
3274
0
  int      matched;
3275
0
  struct grid_line  *gl;
3276
0
  struct grid_cell   gc;
3277
3278
0
  endline = gd->hsize + gd->sy - 1;
3279
0
  for (ax = first; ax < last; ax++) {
3280
0
    padding = 0;
3281
0
    for (bx = 0; bx < sgd->sx; bx++) {
3282
0
      px = ax + bx + padding;
3283
0
      pywrap = py;
3284
      /* Wrap line. */
3285
0
      while (px >= gd->sx && pywrap < endline) {
3286
0
        gl = grid_get_line(gd, pywrap);
3287
0
        if (~gl->flags & GRID_LINE_WRAPPED)
3288
0
          break;
3289
0
        px -= gd->sx;
3290
0
        pywrap++;
3291
0
      }
3292
      /* We have run off the end of the grid. */
3293
0
      if (px - padding >= gd->sx)
3294
0
        break;
3295
3296
0
      grid_get_cell(gd, px, pywrap, &gc);
3297
0
      if (gc.flags & GRID_FLAG_TAB)
3298
0
        padding += gc.data.width - 1;
3299
3300
0
      matched = window_copy_search_compare(gd, px, pywrap,
3301
0
          sgd, bx, cis);
3302
0
      if (!matched)
3303
0
        break;
3304
0
    }
3305
0
    if (bx == sgd->sx) {
3306
0
      *ppx = ax;
3307
0
      return (1);
3308
0
    }
3309
0
  }
3310
0
  return (0);
3311
0
}
3312
3313
static int
3314
window_copy_search_rl(struct grid *gd,
3315
    struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
3316
0
{
3317
0
  u_int      ax, bx, px, pywrap, endline, padding;
3318
0
  int      matched;
3319
0
  struct grid_line  *gl;
3320
0
  struct grid_cell   gc;
3321
3322
0
  endline = gd->hsize + gd->sy - 1;
3323
0
  for (ax = last; ax > first; ax--) {
3324
0
    padding = 0;
3325
0
    for (bx = 0; bx < sgd->sx; bx++) {
3326
0
      px = ax - 1 + bx + padding;
3327
0
      pywrap = py;
3328
      /* Wrap line. */
3329
0
      while (px >= gd->sx && pywrap < endline) {
3330
0
        gl = grid_get_line(gd, pywrap);
3331
0
        if (~gl->flags & GRID_LINE_WRAPPED)
3332
0
          break;
3333
0
        px -= gd->sx;
3334
0
        pywrap++;
3335
0
      }
3336
      /* We have run off the end of the grid. */
3337
0
      if (px - padding >= gd->sx)
3338
0
        break;
3339
3340
0
      grid_get_cell(gd, px, pywrap, &gc);
3341
0
      if (gc.flags & GRID_FLAG_TAB)
3342
0
        padding += gc.data.width - 1;
3343
3344
0
      matched = window_copy_search_compare(gd, px, pywrap,
3345
0
          sgd, bx, cis);
3346
0
      if (!matched)
3347
0
        break;
3348
0
    }
3349
0
    if (bx == sgd->sx) {
3350
0
      *ppx = ax - 1;
3351
0
      return (1);
3352
0
    }
3353
0
  }
3354
0
  return (0);
3355
0
}
3356
3357
static int
3358
window_copy_search_lr_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
3359
    u_int first, u_int last, regex_t *reg)
3360
0
{
3361
0
  int     eflags = 0;
3362
0
  u_int     endline, foundx, foundy, len, pywrap, size = 1;
3363
0
  char           *buf;
3364
0
  regmatch_t    regmatch;
3365
0
  struct grid_line       *gl;
3366
3367
  /*
3368
   * This can happen during search if the last match was the last
3369
   * character on a line.
3370
   */
3371
0
  if (first >= last)
3372
0
    return (0);
3373
3374
  /* Set flags for regex search. */
3375
0
  if (first != 0)
3376
0
    eflags |= REG_NOTBOL;
3377
3378
  /* Need to look at the entire string. */
3379
0
  buf = xmalloc(size);
3380
0
  buf[0] = '\0';
3381
0
  buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
3382
0
  len = gd->sx - first;
3383
0
  endline = gd->hsize + gd->sy - 1;
3384
0
  pywrap = py;
3385
0
  while (buf != NULL &&
3386
0
      pywrap <= endline &&
3387
0
      len < WINDOW_COPY_SEARCH_MAX_LINE) {
3388
0
    gl = grid_get_line(gd, pywrap);
3389
0
    if (~gl->flags & GRID_LINE_WRAPPED)
3390
0
      break;
3391
0
    pywrap++;
3392
0
    buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
3393
0
    len += gd->sx;
3394
0
  }
3395
3396
0
  if (regexec(reg, buf, 1, &regmatch, eflags) == 0 &&
3397
0
      regmatch.rm_so != regmatch.rm_eo) {
3398
0
    foundx = first;
3399
0
    foundy = py;
3400
0
    window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
3401
0
        buf + regmatch.rm_so);
3402
0
    if (foundy == py && foundx < last) {
3403
0
      *ppx = foundx;
3404
0
      len -= foundx - first;
3405
0
      window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
3406
0
          buf + regmatch.rm_eo);
3407
0
      *psx = foundx;
3408
0
      while (foundy > py) {
3409
0
        *psx += gd->sx;
3410
0
        foundy--;
3411
0
      }
3412
0
      *psx -= *ppx;
3413
0
      free(buf);
3414
0
      return (1);
3415
0
    }
3416
0
  }
3417
3418
0
  free(buf);
3419
0
  *ppx = 0;
3420
0
  *psx = 0;
3421
0
  return (0);
3422
0
}
3423
3424
static int
3425
window_copy_search_rl_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
3426
    u_int first, u_int last, regex_t *reg)
3427
0
{
3428
0
  int     eflags = 0;
3429
0
  u_int     endline, len, pywrap, size = 1;
3430
0
  char           *buf;
3431
0
  struct grid_line       *gl;
3432
3433
  /* Set flags for regex search. */
3434
0
  if (first != 0)
3435
0
    eflags |= REG_NOTBOL;
3436
3437
  /* Need to look at the entire string. */
3438
0
  buf = xmalloc(size);
3439
0
  buf[0] = '\0';
3440
0
  buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
3441
0
  len = gd->sx - first;
3442
0
  endline = gd->hsize + gd->sy - 1;
3443
0
  pywrap = py;
3444
0
  while (buf != NULL &&
3445
0
      pywrap <= endline &&
3446
0
      len < WINDOW_COPY_SEARCH_MAX_LINE) {
3447
0
    gl = grid_get_line(gd, pywrap);
3448
0
    if (~gl->flags & GRID_LINE_WRAPPED)
3449
0
      break;
3450
0
    pywrap++;
3451
0
    buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
3452
0
    len += gd->sx;
3453
0
  }
3454
3455
0
  if (window_copy_last_regex(gd, py, first, last, len, ppx, psx, buf,
3456
0
      reg, eflags))
3457
0
  {
3458
0
    free(buf);
3459
0
    return (1);
3460
0
  }
3461
3462
0
  free(buf);
3463
0
  *ppx = 0;
3464
0
  *psx = 0;
3465
0
  return (0);
3466
0
}
3467
3468
static const char *
3469
window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size,
3470
    int *allocated)
3471
0
{
3472
0
  static struct utf8_data  ud;
3473
0
  struct grid_cell_entry  *gce;
3474
0
  char      *copy;
3475
3476
0
  if (px >= gl->cellsize) {
3477
0
    *size = 1;
3478
0
    *allocated = 0;
3479
0
    return (" ");
3480
0
  }
3481
3482
0
  gce = &gl->celldata[px];
3483
0
  if (gce->flags & GRID_FLAG_PADDING) {
3484
0
    *size = 0;
3485
0
    *allocated = 0;
3486
0
    return (NULL);
3487
0
  }
3488
0
  if (~gce->flags & GRID_FLAG_EXTENDED) {
3489
0
    *size = 1;
3490
0
    *allocated = 0;
3491
0
    return (&gce->data.data);
3492
0
  }
3493
0
  if (gce->flags & GRID_FLAG_TAB) {
3494
0
    *size = 1;
3495
0
    *allocated = 0;
3496
0
    return ("\t");
3497
0
  }
3498
3499
0
  utf8_to_data(gl->extddata[gce->offset].data, &ud);
3500
0
  if (ud.size == 0) {
3501
0
    *size = 0;
3502
0
    *allocated = 0;
3503
0
    return (NULL);
3504
0
  }
3505
0
  *size = ud.size;
3506
0
  *allocated = 1;
3507
3508
0
  copy = xmalloc(ud.size);
3509
0
  memcpy(copy, ud.data, ud.size);
3510
0
  return (copy);
3511
0
}
3512
3513
/* Find last match in given range. */
3514
static int
3515
window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last,
3516
    u_int len, u_int *ppx, u_int *psx, const char *buf, const regex_t *preg,
3517
    int eflags)
3518
0
{
3519
0
  u_int   foundx, foundy, oldx, px = 0, savepx, savesx = 0;
3520
0
  regmatch_t  regmatch;
3521
3522
0
  foundx = first;
3523
0
  foundy = py;
3524
0
  oldx = first;
3525
0
  while (regexec(preg, buf + px, 1, &regmatch, eflags) == 0) {
3526
0
    if (regmatch.rm_so == regmatch.rm_eo)
3527
0
      break;
3528
0
    window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
3529
0
        buf + px + regmatch.rm_so);
3530
0
    if (foundy > py || foundx >= last)
3531
0
      break;
3532
0
    len -= foundx - oldx;
3533
0
    savepx = foundx;
3534
0
    window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
3535
0
        buf + px + regmatch.rm_eo);
3536
0
    if (foundy > py || foundx >= last) {
3537
0
      *ppx = savepx;
3538
0
      *psx = foundx;
3539
0
      while (foundy > py) {
3540
0
        *psx += gd->sx;
3541
0
        foundy--;
3542
0
      }
3543
0
      *psx -= *ppx;
3544
0
      return (1);
3545
0
    } else {
3546
0
      savesx = foundx - savepx;
3547
0
      len -= savesx;
3548
0
      oldx = foundx;
3549
0
    }
3550
0
    px += regmatch.rm_eo;
3551
0
  }
3552
3553
0
  if (savesx > 0) {
3554
0
    *ppx = savepx;
3555
0
    *psx = savesx;
3556
0
    return (1);
3557
0
  } else {
3558
0
    *ppx = 0;
3559
0
    *psx = 0;
3560
0
    return (0);
3561
0
  }
3562
0
}
3563
3564
/* Stringify line and append to input buffer. Caller frees. */
3565
static char *
3566
window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
3567
    char *buf, u_int *size)
3568
0
{
3569
0
  u_int      ax, bx, newsize = *size;
3570
0
  const struct grid_line  *gl;
3571
0
  const char    *d;
3572
0
  size_t       bufsize = 1024, dlen;
3573
0
  int      allocated;
3574
3575
0
  while (bufsize < newsize)
3576
0
    bufsize *= 2;
3577
0
  buf = xrealloc(buf, bufsize);
3578
3579
0
  gl = grid_peek_line(gd, py);
3580
0
  bx = *size - 1;
3581
0
  for (ax = first; ax < last; ax++) {
3582
0
    d = window_copy_cellstring(gl, ax, &dlen, &allocated);
3583
0
    newsize += dlen;
3584
0
    while (bufsize < newsize) {
3585
0
      bufsize *= 2;
3586
0
      buf = xrealloc(buf, bufsize);
3587
0
    }
3588
0
    if (dlen == 1)
3589
0
      buf[bx++] = *d;
3590
0
    else {
3591
0
      memcpy(buf + bx, d, dlen);
3592
0
      bx += dlen;
3593
0
    }
3594
0
    if (allocated)
3595
0
      free((void *)d);
3596
0
  }
3597
0
  buf[newsize - 1] = '\0';
3598
3599
0
  *size = newsize;
3600
0
  return (buf);
3601
0
}
3602
3603
/* Map start of C string containing UTF-8 data to grid cell position. */
3604
static void
3605
window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy,
3606
    const char *str)
3607
0
{
3608
0
  u_int      cell, ccell, px, pywrap, pos, len;
3609
0
  int      match;
3610
0
  const struct grid_line  *gl;
3611
0
  const char    *d;
3612
0
  size_t       dlen;
3613
0
  struct {
3614
0
    const char  *d;
3615
0
    size_t     dlen;
3616
0
    int    allocated;
3617
0
  } *cells;
3618
3619
  /* Populate the array of cell data. */
3620
0
  cells = xreallocarray(NULL, ncells, sizeof cells[0]);
3621
0
  cell = 0;
3622
0
  px = *ppx;
3623
0
  pywrap = *ppy;
3624
0
  gl = grid_peek_line(gd, pywrap);
3625
0
  while (cell < ncells) {
3626
0
    cells[cell].d = window_copy_cellstring(gl, px,
3627
0
        &cells[cell].dlen, &cells[cell].allocated);
3628
0
    cell++;
3629
0
    px++;
3630
0
    if (px == gd->sx) {
3631
0
      px = 0;
3632
0
      pywrap++;
3633
0
      gl = grid_peek_line(gd, pywrap);
3634
0
    }
3635
0
  }
3636
3637
  /* Locate starting cell. */
3638
0
  cell = 0;
3639
0
  len = strlen(str);
3640
0
  while (cell < ncells) {
3641
0
    ccell = cell;
3642
0
    pos = 0;
3643
0
    match = 1;
3644
0
    while (ccell < ncells) {
3645
0
      if (str[pos] == '\0') {
3646
0
        match = 0;
3647
0
        break;
3648
0
      }
3649
0
      d = cells[ccell].d;
3650
0
      dlen = cells[ccell].dlen;
3651
0
      if (dlen == 1) {
3652
0
        if (str[pos] != *d) {
3653
0
          match = 0;
3654
0
          break;
3655
0
        }
3656
0
        pos++;
3657
0
      } else {
3658
0
        if (dlen > len - pos)
3659
0
          dlen = len - pos;
3660
0
        if (memcmp(str + pos, d, dlen) != 0) {
3661
0
          match = 0;
3662
0
          break;
3663
0
        }
3664
0
        pos += dlen;
3665
0
      }
3666
0
      ccell++;
3667
0
    }
3668
0
    if (match)
3669
0
      break;
3670
0
    cell++;
3671
0
  }
3672
3673
  /* If not found this will be one past the end. */
3674
0
  px = *ppx + cell;
3675
0
  pywrap = *ppy;
3676
0
  while (px >= gd->sx) {
3677
0
    px -= gd->sx;
3678
0
    pywrap++;
3679
0
  }
3680
3681
0
  *ppx = px;
3682
0
  *ppy = pywrap;
3683
3684
  /* Free cell data. */
3685
0
  for (cell = 0; cell < ncells; cell++) {
3686
0
    if (cells[cell].allocated)
3687
0
      free((void *)cells[cell].d);
3688
0
  }
3689
0
  free(cells);
3690
0
}
3691
3692
static void
3693
window_copy_move_left(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
3694
0
{
3695
0
  if (*fx == 0) { /* left */
3696
0
    if (*fy == 0) { /* top */
3697
0
      if (wrapflag) {
3698
0
        *fx = screen_size_x(s) - 1;
3699
0
        *fy = screen_hsize(s) + screen_size_y(s) - 1;
3700
0
      }
3701
0
      return;
3702
0
    }
3703
0
    *fx = screen_size_x(s) - 1;
3704
0
    *fy = *fy - 1;
3705
0
  } else
3706
0
    *fx = *fx - 1;
3707
0
}
3708
3709
static void
3710
window_copy_move_right(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
3711
0
{
3712
0
  if (*fx == screen_size_x(s) - 1) { /* right */
3713
0
    if (*fy == screen_hsize(s) + screen_size_y(s) - 1) { /* bottom */
3714
0
      if (wrapflag) {
3715
0
        *fx = 0;
3716
0
        *fy = 0;
3717
0
      }
3718
0
      return;
3719
0
    }
3720
0
    *fx = 0;
3721
0
    *fy = *fy + 1;
3722
0
  } else
3723
0
    *fx = *fx + 1;
3724
0
}
3725
3726
static int
3727
window_copy_is_lowercase(const char *ptr)
3728
0
{
3729
0
  while (*ptr != '\0') {
3730
0
    if (*ptr != tolower((u_char)*ptr))
3731
0
      return (0);
3732
0
    ++ptr;
3733
0
  }
3734
0
  return (1);
3735
0
}
3736
3737
/*
3738
 * Handle backward wrapped regex searches with overlapping matches. In this case
3739
 * find the longest overlapping match from previous wrapped lines.
3740
 */
3741
static void
3742
window_copy_search_back_overlap(struct grid *gd, regex_t *preg, u_int *ppx,
3743
    u_int *psx, u_int *ppy, u_int endline)
3744
0
{
3745
0
  u_int endx, endy, oldendx, oldendy, px, py, sx;
3746
0
  int found = 1;
3747
3748
0
  oldendx = *ppx + *psx;
3749
0
  oldendy = *ppy - 1;
3750
0
  while (oldendx > gd->sx - 1) {
3751
0
    oldendx -= gd->sx;
3752
0
    oldendy++;
3753
0
  }
3754
0
  endx = oldendx;
3755
0
  endy = oldendy;
3756
0
  px = *ppx;
3757
0
  py = *ppy;
3758
0
  while (found && px == 0 && py - 1 > endline &&
3759
0
         grid_get_line(gd, py - 2)->flags & GRID_LINE_WRAPPED &&
3760
0
         endx == oldendx && endy == oldendy) {
3761
0
    py--;
3762
0
    found = window_copy_search_rl_regex(gd, &px, &sx, py - 1, 0,
3763
0
        gd->sx, preg);
3764
0
    if (found) {
3765
0
      endx = px + sx;
3766
0
      endy = py - 1;
3767
0
      while (endx > gd->sx - 1) {
3768
0
        endx -= gd->sx;
3769
0
        endy++;
3770
0
      }
3771
0
      if (endx == oldendx && endy == oldendy) {
3772
0
        *ppx = px;
3773
0
        *ppy = py;
3774
0
      }
3775
0
    }
3776
0
  }
3777
0
}
3778
3779
/*
3780
 * Search for text stored in sgd starting from position fx,fy up to endline. If
3781
 * found, jump to it. If cis then ignore case. The direction is 0 for searching
3782
 * up, down otherwise. If wrap then go to begin/end of grid and try again if
3783
 * not found.
3784
 */
3785
static int
3786
window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
3787
    struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
3788
    int direction, int regex)
3789
0
{
3790
0
  u_int  i, px, sx, ssize = 1;
3791
0
  int  found = 0, cflags = REG_EXTENDED;
3792
0
  char  *sbuf;
3793
0
  regex_t  reg;
3794
3795
0
  if (regex) {
3796
0
    sbuf = xmalloc(ssize);
3797
0
    sbuf[0] = '\0';
3798
0
    sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize);
3799
0
    if (cis)
3800
0
      cflags |= REG_ICASE;
3801
0
    if (regcomp(&reg, sbuf, cflags) != 0) {
3802
0
      free(sbuf);
3803
0
      return (0);
3804
0
    }
3805
0
    free(sbuf);
3806
0
  }
3807
3808
0
  if (direction) {
3809
0
    for (i = fy; i <= endline; i++) {
3810
0
      if (regex) {
3811
0
        found = window_copy_search_lr_regex(gd,
3812
0
            &px, &sx, i, fx, gd->sx, &reg);
3813
0
      } else {
3814
0
        found = window_copy_search_lr(gd, sgd,
3815
0
            &px, i, fx, gd->sx, cis);
3816
0
      }
3817
0
      if (found)
3818
0
        break;
3819
0
      fx = 0;
3820
0
    }
3821
0
  } else {
3822
0
    for (i = fy + 1; endline < i; i--) {
3823
0
      if (regex) {
3824
0
        found = window_copy_search_rl_regex(gd,
3825
0
            &px, &sx, i - 1, 0, fx + 1, &reg);
3826
0
        if (found) {
3827
0
          window_copy_search_back_overlap(gd,
3828
0
              &reg, &px, &sx, &i, endline);
3829
0
        }
3830
0
      } else {
3831
0
        found = window_copy_search_rl(gd, sgd,
3832
0
            &px, i - 1, 0, fx + 1, cis);
3833
0
      }
3834
0
      if (found) {
3835
0
        i--;
3836
0
        break;
3837
0
      }
3838
0
      fx = gd->sx - 1;
3839
0
    }
3840
0
  }
3841
0
  if (regex)
3842
0
    regfree(&reg);
3843
3844
0
  if (found) {
3845
0
    window_copy_scroll_to(wme, px, i, 1);
3846
0
    return (1);
3847
0
  }
3848
0
  if (wrap) {
3849
0
    return (window_copy_search_jump(wme, gd, sgd,
3850
0
        direction ? 0 : gd->sx - 1,
3851
0
        direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
3852
0
        direction, regex));
3853
0
  }
3854
0
  return (0);
3855
0
}
3856
3857
static void
3858
window_copy_move_after_search_mark(struct window_copy_mode_data *data,
3859
    u_int *fx, u_int *fy, int wrapflag)
3860
0
{
3861
0
  struct screen  *s = data->backing;
3862
0
  u_int   at, start;
3863
3864
0
  if (window_copy_search_mark_at(data, *fx, *fy, &start) == 0 &&
3865
0
      data->searchmark[start] != 0) {
3866
0
    while (window_copy_search_mark_at(data, *fx, *fy, &at) == 0) {
3867
0
      if (data->searchmark[at] != data->searchmark[start])
3868
0
        break;
3869
      /* Stop if not wrapping and at the end of the grid. */
3870
0
      if (!wrapflag &&
3871
0
          *fx == screen_size_x(s) - 1 &&
3872
0
          *fy == screen_hsize(s) + screen_size_y(s) - 1)
3873
0
        break;
3874
3875
0
      window_copy_move_right(s, fx, fy, wrapflag);
3876
0
    }
3877
0
  }
3878
0
}
3879
3880
/*
3881
 * Search in for text searchstr. If direction is 0 then search up, otherwise
3882
 * down.
3883
 */
3884
static int
3885
window_copy_search(struct window_mode_entry *wme, int direction, int regex)
3886
0
{
3887
0
  struct window_pane    *wp = wme->wp;
3888
0
  struct window_copy_mode_data  *data = wme->data;
3889
0
  struct screen     *s = data->backing, ss;
3890
0
  struct screen_write_ctx    ctx;
3891
0
  struct grid     *gd = s->grid;
3892
0
  const char      *str = data->searchstr;
3893
0
  u_int        at, endline, fx, fy, start, ssx;
3894
0
  int        cis, found, keys, visible_only;
3895
0
  int        wrapflag;
3896
3897
0
  if (regex && str[strcspn(str, "^$*+()?[].\\")] == '\0')
3898
0
    regex = 0;
3899
3900
0
  data->searchdirection = direction;
3901
3902
0
  if (data->timeout)
3903
0
    return (0);
3904
3905
0
  if (data->searchall || wp->searchstr == NULL ||
3906
0
      wp->searchregex != regex) {
3907
0
    visible_only = 0;
3908
0
    data->searchall = 0;
3909
0
  } else
3910
0
    visible_only = (strcmp(wp->searchstr, str) == 0);
3911
0
  if (visible_only == 0 && data->searchmark != NULL)
3912
0
    window_copy_clear_marks(wme);
3913
0
  free(wp->searchstr);
3914
0
  wp->searchstr = xstrdup(str);
3915
0
  wp->searchregex = regex;
3916
3917
0
  fx = data->cx;
3918
0
  fy = screen_hsize(data->backing) - data->oy + data->cy;
3919
3920
0
  if ((ssx = screen_write_strlen("%s", str)) == 0)
3921
0
    return (0);
3922
0
  screen_init(&ss, ssx, 1, 0);
3923
0
  screen_write_start(&ctx, &ss);
3924
0
  screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str);
3925
0
  screen_write_stop(&ctx);
3926
3927
0
  wrapflag = options_get_number(wp->window->options, "wrap-search");
3928
0
  cis = window_copy_is_lowercase(str);
3929
3930
0
  keys = options_get_number(wp->window->options, "mode-keys");
3931
3932
0
  if (direction) {
3933
    /*
3934
     * Behave according to mode-keys. If it is emacs, search forward
3935
     * leaves the cursor after the match. If it is vi, the cursor
3936
     * remains at the beginning of the match, regardless of
3937
     * direction, which means that we need to start the next search
3938
     * after the term the cursor is currently on when searching
3939
     * forward.
3940
     */
3941
0
    if (keys == MODEKEY_VI) {
3942
0
      if (data->searchmark != NULL)
3943
0
        window_copy_move_after_search_mark(data, &fx,
3944
0
            &fy, wrapflag);
3945
0
      else {
3946
        /*
3947
         * When there are no search marks, start the
3948
         * search after the current cursor position.
3949
         */
3950
0
        window_copy_move_right(s, &fx, &fy, wrapflag);
3951
0
      }
3952
0
    }
3953
0
    endline = gd->hsize + gd->sy - 1;
3954
0
  } else {
3955
0
    window_copy_move_left(s, &fx, &fy, wrapflag);
3956
0
    endline = 0;
3957
0
  }
3958
3959
0
  found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
3960
0
      wrapflag, direction, regex);
3961
0
  if (found) {
3962
0
    window_copy_search_marks(wme, &ss, regex, visible_only);
3963
0
    fx = data->cx;
3964
0
    fy = screen_hsize(data->backing) - data->oy + data->cy;
3965
3966
    /*
3967
     * When searching forward, if the cursor is not at the beginning
3968
     * of the mark, search again.
3969
     */
3970
0
    if (direction &&
3971
0
        window_copy_search_mark_at(data, fx, fy, &at) == 0 &&
3972
0
        at > 0 &&
3973
0
        data->searchmark != NULL &&
3974
0
        data->searchmark[at] == data->searchmark[at - 1]) {
3975
0
      window_copy_move_after_search_mark(data, &fx, &fy,
3976
0
          wrapflag);
3977
0
      window_copy_search_jump(wme, gd, ss.grid, fx,
3978
0
          fy, endline, cis, wrapflag, direction,
3979
0
          regex);
3980
0
      fx = data->cx;
3981
0
      fy = screen_hsize(data->backing) - data->oy + data->cy;
3982
0
    }
3983
3984
0
    if (direction) {
3985
      /*
3986
       * When in Emacs mode, position the cursor just after
3987
       * the mark.
3988
       */
3989
0
      if (keys == MODEKEY_EMACS) {
3990
0
        window_copy_move_after_search_mark(data, &fx,
3991
0
            &fy, wrapflag);
3992
0
        data->cx = fx;
3993
0
        data->cy = fy - screen_hsize(data->backing) +
3994
0
            data-> oy;
3995
0
      }
3996
0
    } else {
3997
      /*
3998
       * When searching backward, position the cursor at the
3999
       * beginning of the mark.
4000
       */
4001
0
      if (window_copy_search_mark_at(data, fx, fy,
4002
0
              &start) == 0) {
4003
0
        while (window_copy_search_mark_at(data, fx, fy,
4004
0
                   &at) == 0 &&
4005
0
               data->searchmark != NULL &&
4006
0
               data->searchmark[at] ==
4007
0
                   data->searchmark[start]) {
4008
0
          data->cx = fx;
4009
0
          data->cy = fy -
4010
0
              screen_hsize(data->backing) +
4011
0
              data-> oy;
4012
0
          if (at == 0)
4013
0
            break;
4014
4015
0
          window_copy_move_left(s, &fx, &fy, 0);
4016
0
        }
4017
0
      }
4018
0
    }
4019
0
  }
4020
0
  window_copy_redraw_screen(wme);
4021
4022
0
  screen_free(&ss);
4023
0
  return (found);
4024
0
}
4025
4026
static void
4027
window_copy_visible_lines(struct window_copy_mode_data *data, u_int *start,
4028
    u_int *end)
4029
0
{
4030
0
  struct grid   *gd = data->backing->grid;
4031
0
  const struct grid_line  *gl;
4032
4033
0
  for (*start = gd->hsize - data->oy; *start > 0; (*start)--) {
4034
0
    gl = grid_peek_line(gd, (*start) - 1);
4035
0
    if (~gl->flags & GRID_LINE_WRAPPED)
4036
0
      break;
4037
0
  }
4038
0
  *end = gd->hsize - data->oy + gd->sy;
4039
0
}
4040
4041
static int
4042
window_copy_search_mark_at(struct window_copy_mode_data *data, u_int px,
4043
    u_int py, u_int *at)
4044
0
{
4045
0
  struct screen *s = data->backing;
4046
0
  struct grid *gd = s->grid;
4047
4048
0
  if (py < gd->hsize - data->oy)
4049
0
    return (-1);
4050
0
  if (py > gd->hsize - data->oy + gd->sy - 1)
4051
0
    return (-1);
4052
0
  *at = ((py - (gd->hsize - data->oy)) * gd->sx) + px;
4053
0
  return (0);
4054
0
}
4055
4056
static u_int
4057
window_copy_clip_width(u_int width, u_int b, u_int sx, u_int sy)
4058
0
{
4059
0
  return ((b + width > sx * sy) ? (sx * sy) - b : width);
4060
0
}
4061
4062
static u_int
4063
window_copy_search_mark_match(struct window_copy_mode_data *data, u_int px,
4064
    u_int py, u_int width, int regex)
4065
0
{
4066
0
  struct grid   *gd = data->backing->grid;
4067
0
  struct grid_cell   gc;
4068
0
  u_int      i, b, w = width, sx = gd->sx, sy = gd->sy;
4069
4070
0
  if (window_copy_search_mark_at(data, px, py, &b) == 0) {
4071
0
    width = window_copy_clip_width(width, b, sx, sy);
4072
0
    w = width;
4073
0
    for (i = b; i < b + w; i++) {
4074
0
      if (!regex) {
4075
0
        grid_get_cell(gd, px + (i - b), py, &gc);
4076
0
        if (gc.flags & GRID_FLAG_TAB)
4077
0
          w += gc.data.width - 1;
4078
0
        w = window_copy_clip_width(w, b, sx, sy);
4079
0
      }
4080
0
      if (data->searchmark[i] != 0)
4081
0
        continue;
4082
0
      data->searchmark[i] = data->searchgen;
4083
0
    }
4084
0
    if (data->searchgen == UCHAR_MAX)
4085
0
      data->searchgen = 1;
4086
0
    else
4087
0
      data->searchgen++;
4088
0
  }
4089
4090
0
  return (w);
4091
0
}
4092
4093
static int
4094
window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
4095
    int regex, int visible_only)
4096
0
{
4097
0
  struct window_copy_mode_data  *data = wme->data;
4098
0
  struct screen     *s = data->backing, ss;
4099
0
  struct screen_write_ctx    ctx;
4100
0
  struct grid     *gd = s->grid;
4101
0
  struct grid_cell     gc;
4102
0
  int        found, cis, stopped = 0;
4103
0
  int        cflags = REG_EXTENDED;
4104
0
  u_int        px, py, nfound = 0, width;
4105
0
  u_int        ssize = 1, start, end, sx = gd->sx;
4106
0
  u_int        sy = gd->sy;
4107
0
  char        *sbuf;
4108
0
  regex_t        reg;
4109
0
  uint64_t       stop = 0, tstart, t;
4110
4111
0
  if (ssp == NULL) {
4112
0
    width = screen_write_strlen("%s", data->searchstr);
4113
0
    screen_init(&ss, width, 1, 0);
4114
0
    screen_write_start(&ctx, &ss);
4115
0
    screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
4116
0
        data->searchstr);
4117
0
    screen_write_stop(&ctx);
4118
0
    ssp = &ss;
4119
0
  } else
4120
0
    width = screen_size_x(ssp);
4121
4122
0
  cis = window_copy_is_lowercase(data->searchstr);
4123
4124
0
  if (regex) {
4125
0
    sbuf = xmalloc(ssize);
4126
0
    sbuf[0] = '\0';
4127
0
    sbuf = window_copy_stringify(ssp->grid, 0, 0, ssp->grid->sx,
4128
0
        sbuf, &ssize);
4129
0
    if (cis)
4130
0
      cflags |= REG_ICASE;
4131
0
    if (regcomp(&reg, sbuf, cflags) != 0) {
4132
0
      free(sbuf);
4133
0
      return (0);
4134
0
    }
4135
0
    free(sbuf);
4136
0
  }
4137
0
  tstart = get_timer();
4138
4139
0
  if (visible_only)
4140
0
    window_copy_visible_lines(data, &start, &end);
4141
0
  else {
4142
0
    start = 0;
4143
0
    end = gd->hsize + sy;
4144
0
    stop = get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT;
4145
0
  }
4146
4147
0
again:
4148
0
  free(data->searchmark);
4149
0
  data->searchmark = xcalloc(sx, sy);
4150
0
  data->searchgen = 1;
4151
4152
0
  for (py = start; py < end; py++) {
4153
0
    px = 0;
4154
0
    for (;;) {
4155
0
      if (regex) {
4156
0
        found = window_copy_search_lr_regex(gd,
4157
0
            &px, &width, py, px, sx, &reg);
4158
0
        grid_get_cell(gd, px + width - 1, py, &gc);
4159
0
        if (gc.data.width > 2)
4160
0
          width += gc.data.width - 1;
4161
0
        if (!found)
4162
0
          break;
4163
0
      } else {
4164
0
        found = window_copy_search_lr(gd, ssp->grid,
4165
0
            &px, py, px, sx, cis);
4166
0
        if (!found)
4167
0
          break;
4168
0
      }
4169
0
      nfound++;
4170
0
      px += window_copy_search_mark_match(data, px, py, width,
4171
0
          regex);
4172
0
    }
4173
4174
0
    t = get_timer();
4175
0
    if (t - tstart > WINDOW_COPY_SEARCH_TIMEOUT) {
4176
0
      data->timeout = 1;
4177
0
      break;
4178
0
    }
4179
0
    if (stop != 0 && t > stop) {
4180
0
      stopped = 1;
4181
0
      break;
4182
0
    }
4183
0
  }
4184
0
  if (data->timeout) {
4185
0
    window_copy_clear_marks(wme);
4186
0
    goto out;
4187
0
  }
4188
4189
0
  if (stopped && stop != 0) {
4190
    /* Try again but just the visible context. */
4191
0
    window_copy_visible_lines(data, &start, &end);
4192
0
    stop = 0;
4193
0
    goto again;
4194
0
  }
4195
4196
0
  if (!visible_only) {
4197
0
    if (stopped) {
4198
0
      if (nfound > 1000)
4199
0
        data->searchcount = 1000;
4200
0
      else if (nfound > 100)
4201
0
        data->searchcount = 100;
4202
0
      else if (nfound > 10)
4203
0
        data->searchcount = 10;
4204
0
      else
4205
0
        data->searchcount = -1;
4206
0
      data->searchmore = 1;
4207
0
    } else {
4208
0
      data->searchcount = nfound;
4209
0
      data->searchmore = 0;
4210
0
    }
4211
0
  }
4212
4213
0
out:
4214
0
  if (ssp == &ss)
4215
0
    screen_free(&ss);
4216
0
  if (regex)
4217
0
    regfree(&reg);
4218
0
  return (1);
4219
0
}
4220
4221
static void
4222
window_copy_clear_marks(struct window_mode_entry *wme)
4223
0
{
4224
0
  struct window_copy_mode_data  *data = wme->data;
4225
4226
0
  free(data->searchmark);
4227
0
  data->searchmark = NULL;
4228
0
}
4229
4230
static int
4231
window_copy_search_up(struct window_mode_entry *wme, int regex)
4232
0
{
4233
0
  return (window_copy_search(wme, 0, regex));
4234
0
}
4235
4236
static int
4237
window_copy_search_down(struct window_mode_entry *wme, int regex)
4238
0
{
4239
0
  return (window_copy_search(wme, 1, regex));
4240
0
}
4241
4242
static void
4243
window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
4244
0
{
4245
0
  struct window_copy_mode_data  *data = wme->data;
4246
0
  const char      *errstr;
4247
0
  int        lineno;
4248
4249
0
  lineno = strtonum(linestr, -1, INT_MAX, &errstr);
4250
0
  if (errstr != NULL)
4251
0
    return;
4252
0
  if (lineno < 0 || (u_int)lineno > screen_hsize(data->backing))
4253
0
    lineno = screen_hsize(data->backing);
4254
4255
0
  data->oy = lineno;
4256
0
  window_copy_update_selection(wme, 1, 0);
4257
0
  window_copy_redraw_screen(wme);
4258
0
}
4259
4260
static void
4261
window_copy_match_start_end(struct window_copy_mode_data *data, u_int at,
4262
    u_int *start, u_int *end)
4263
0
{
4264
0
  struct grid *gd = data->backing->grid;
4265
0
  u_int    last = (gd->sy * gd->sx) - 1;
4266
0
  u_char     mark = data->searchmark[at];
4267
4268
0
  *start = *end = at;
4269
0
  while (*start != 0 && data->searchmark[*start] == mark)
4270
0
    (*start)--;
4271
0
  if (data->searchmark[*start] != mark)
4272
0
    (*start)++;
4273
0
  while (*end != last && data->searchmark[*end] == mark)
4274
0
    (*end)++;
4275
0
  if (data->searchmark[*end] != mark)
4276
0
    (*end)--;
4277
0
}
4278
4279
static char *
4280
window_copy_match_at_cursor(struct window_copy_mode_data *data)
4281
0
{
4282
0
  struct grid *gd = data->backing->grid;
4283
0
  struct grid_cell gc;
4284
0
  u_int    at, start, end, cy, px, py;
4285
0
  u_int    sx = screen_size_x(data->backing);
4286
0
  char    *buf = NULL;
4287
0
  size_t     len = 0;
4288
4289
0
  if (data->searchmark == NULL)
4290
0
    return (NULL);
4291
4292
0
  cy = screen_hsize(data->backing) - data->oy + data->cy;
4293
0
  if (window_copy_search_mark_at(data, data->cx, cy, &at) != 0)
4294
0
    return (NULL);
4295
0
  if (data->searchmark[at] == 0) {
4296
    /* Allow one position after the match. */
4297
0
    if (at == 0 || data->searchmark[--at] == 0)
4298
0
      return (NULL);
4299
0
  }
4300
0
  window_copy_match_start_end(data, at, &start, &end);
4301
4302
  /*
4303
   * Cells will not be set in the marked array unless they are valid text
4304
   * and wrapping will be taken care of, so we can just copy.
4305
   */
4306
0
  for (at = start; at <= end; at++) {
4307
0
    py = at / sx;
4308
0
    px = at - (py * sx);
4309
4310
0
    grid_get_cell(gd, px, gd->hsize + py - data->oy, &gc);
4311
0
    if (gc.flags & GRID_FLAG_TAB) {
4312
0
      buf = xrealloc(buf, len + 2);
4313
0
      buf[len] = '\t';
4314
0
      len++;
4315
0
    } else if (gc.flags & GRID_FLAG_PADDING) {
4316
      /* nothing to do */
4317
0
    } else {
4318
0
      buf = xrealloc(buf, len + gc.data.size + 1);
4319
0
      memcpy(buf + len, gc.data.data, gc.data.size);
4320
0
      len += gc.data.size;
4321
0
    }
4322
0
  }
4323
0
  if (len != 0)
4324
0
    buf[len] = '\0';
4325
0
  return (buf);
4326
0
}
4327
4328
static void
4329
window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
4330
    struct grid_cell *gc, const struct grid_cell *mgc,
4331
    const struct grid_cell *cgc, const struct grid_cell *mkgc)
4332
0
{
4333
0
  struct window_pane    *wp = wme->wp;
4334
0
  struct window_copy_mode_data  *data = wme->data;
4335
0
  u_int        mark, start, end, cy, cursor, current;
4336
0
  int        inv = 0, found = 0;
4337
0
  int        keys;
4338
4339
0
  if (data->showmark && fy == data->my) {
4340
0
    gc->attr = mkgc->attr;
4341
0
    if (fx == data->mx)
4342
0
      inv = 1;
4343
0
    if (inv) {
4344
0
      gc->fg = mkgc->bg;
4345
0
      gc->bg = mkgc->fg;
4346
0
    }
4347
0
    else {
4348
0
      gc->fg = mkgc->fg;
4349
0
      gc->bg = mkgc->bg;
4350
0
    }
4351
0
  }
4352
4353
0
  if (data->searchmark == NULL)
4354
0
    return;
4355
4356
0
  if (window_copy_search_mark_at(data, fx, fy, &current) != 0)
4357
0
    return;
4358
0
  mark = data->searchmark[current];
4359
0
  if (mark == 0)
4360
0
    return;
4361
4362
0
  cy = screen_hsize(data->backing) - data->oy + data->cy;
4363
0
  if (window_copy_search_mark_at(data, data->cx, cy, &cursor) == 0) {
4364
0
    keys = options_get_number(wp->window->options, "mode-keys");
4365
0
    if (cursor != 0 &&
4366
0
        keys == MODEKEY_EMACS &&
4367
0
        data->searchdirection) {
4368
0
      if (data->searchmark[cursor - 1] == mark) {
4369
0
        cursor--;
4370
0
        found = 1;
4371
0
      }
4372
0
    } else if (data->searchmark[cursor] == mark)
4373
0
      found = 1;
4374
0
    if (found) {
4375
0
      window_copy_match_start_end(data, cursor, &start, &end);
4376
0
      if (current >= start && current <= end) {
4377
0
        gc->attr = cgc->attr;
4378
0
        if (inv) {
4379
0
          gc->fg = cgc->bg;
4380
0
          gc->bg = cgc->fg;
4381
0
        }
4382
0
        else {
4383
0
          gc->fg = cgc->fg;
4384
0
          gc->bg = cgc->bg;
4385
0
        }
4386
0
        return;
4387
0
      }
4388
0
    }
4389
0
  }
4390
4391
0
  gc->attr = mgc->attr;
4392
0
  if (inv) {
4393
0
    gc->fg = mgc->bg;
4394
0
    gc->bg = mgc->fg;
4395
0
  }
4396
0
  else {
4397
0
    gc->fg = mgc->fg;
4398
0
    gc->bg = mgc->bg;
4399
0
  }
4400
0
}
4401
4402
static void
4403
window_copy_write_one(struct window_mode_entry *wme,
4404
    struct screen_write_ctx *ctx, u_int py, u_int fy, u_int nx,
4405
    const struct grid_cell *mgc, const struct grid_cell *cgc,
4406
    const struct grid_cell *mkgc)
4407
0
{
4408
0
  struct window_copy_mode_data  *data = wme->data;
4409
0
  struct grid     *gd = data->backing->grid;
4410
0
  struct grid_cell     gc;
4411
0
  u_int        fx;
4412
4413
0
  screen_write_cursormove(ctx, 0, py, 0);
4414
0
  for (fx = 0; fx < nx; fx++) {
4415
0
    grid_get_cell(gd, fx, fy, &gc);
4416
0
    if (fx + gc.data.width <= nx) {
4417
0
      window_copy_update_style(wme, fx, fy, &gc, mgc, cgc,
4418
0
          mkgc);
4419
0
      screen_write_cell(ctx, &gc);
4420
0
    }
4421
0
  }
4422
0
}
4423
4424
int
4425
window_copy_get_current_offset(struct window_pane *wp, u_int *offset,
4426
    u_int *size)
4427
0
{
4428
0
  struct window_mode_entry  *wme = TAILQ_FIRST(&wp->modes);
4429
0
  struct window_copy_mode_data  *data = wme->data;
4430
0
  u_int        hsize;
4431
4432
0
  if (data == NULL)
4433
0
    return (0);
4434
0
  hsize = screen_hsize(data->backing);
4435
4436
0
  *offset = hsize - data->oy;
4437
0
  *size = hsize;
4438
0
  return (1);
4439
0
}
4440
4441
static void
4442
window_copy_write_line(struct window_mode_entry *wme,
4443
    struct screen_write_ctx *ctx, u_int py)
4444
0
{
4445
0
  struct window_pane    *wp = wme->wp;
4446
0
  struct window_copy_mode_data  *data = wme->data;
4447
0
  struct screen     *s = &data->screen;
4448
0
  struct options      *oo = wp->window->options;
4449
0
  struct grid_cell     gc, mgc, cgc, mkgc;
4450
0
  u_int        sx = screen_size_x(s);
4451
0
  u_int        hsize = screen_hsize(data->backing);
4452
0
  const char      *value;
4453
0
  char        *expanded;
4454
0
  struct format_tree    *ft;
4455
4456
0
  ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
4457
4458
0
  style_apply(&gc, oo, "copy-mode-position-style", ft);
4459
0
  gc.flags |= GRID_FLAG_NOPALETTE;
4460
0
  style_apply(&mgc, oo, "copy-mode-match-style", ft);
4461
0
  mgc.flags |= GRID_FLAG_NOPALETTE;
4462
0
  style_apply(&cgc, oo, "copy-mode-current-match-style", ft);
4463
0
  cgc.flags |= GRID_FLAG_NOPALETTE;
4464
0
  style_apply(&mkgc, oo, "copy-mode-mark-style", ft);
4465
0
  mkgc.flags |= GRID_FLAG_NOPALETTE;
4466
4467
0
  window_copy_write_one(wme, ctx, py, hsize - data->oy + py,
4468
0
      screen_size_x(s), &mgc, &cgc, &mkgc);
4469
4470
0
  if (py == 0 && s->rupper < s->rlower && !data->hide_position) {
4471
0
    value = options_get_string(oo, "copy-mode-position-format");
4472
0
    if (*value != '\0') {
4473
0
      expanded = format_expand(ft, value);
4474
0
      if (*expanded != '\0') {
4475
0
        screen_write_cursormove(ctx, 0, 0, 0);
4476
0
        format_draw(ctx, &gc, sx, expanded, NULL, 0);
4477
0
      }
4478
0
      free(expanded);
4479
0
    }
4480
0
  }
4481
4482
0
  if (py == data->cy && data->cx == screen_size_x(s)) {
4483
0
    screen_write_cursormove(ctx, screen_size_x(s) - 1, py, 0);
4484
0
    screen_write_putc(ctx, &grid_default_cell, '$');
4485
0
  }
4486
4487
0
  format_free(ft);
4488
0
}
4489
4490
static void
4491
window_copy_write_lines(struct window_mode_entry *wme,
4492
    struct screen_write_ctx *ctx, u_int py, u_int ny)
4493
0
{
4494
0
  u_int yy;
4495
4496
0
  for (yy = py; yy < py + ny; yy++)
4497
0
    window_copy_write_line(wme, ctx, py);
4498
0
}
4499
4500
static void
4501
window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y)
4502
0
{
4503
0
  struct window_copy_mode_data  *data = wme->data;
4504
0
  struct grid     *gd = data->backing->grid;
4505
0
  u_int        new_y, start, end;
4506
4507
0
  new_y = data->cy;
4508
0
  if (old_y <= new_y) {
4509
0
    start = old_y;
4510
0
    end = new_y;
4511
0
  } else {
4512
0
    start = new_y;
4513
0
    end = old_y;
4514
0
  }
4515
4516
  /*
4517
   * In word selection mode the first word on the line below the cursor
4518
   * might be selected, so add this line to the redraw area.
4519
   */
4520
0
  if (data->selflag == SEL_WORD) {
4521
    /* Last grid line in data coordinates. */
4522
0
    if (end < gd->sy + data->oy - 1)
4523
0
      end++;
4524
0
  }
4525
0
  window_copy_redraw_lines(wme, start, end - start + 1);
4526
0
}
4527
4528
static void
4529
window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
4530
0
{
4531
0
  struct window_pane    *wp = wme->wp;
4532
0
  struct window_copy_mode_data  *data = wme->data;
4533
0
  struct screen_write_ctx    ctx;
4534
0
  u_int        i;
4535
4536
0
  screen_write_start_pane(&ctx, wp, NULL);
4537
0
  for (i = py; i < py + ny; i++)
4538
0
    window_copy_write_line(wme, &ctx, i);
4539
0
  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
4540
0
  screen_write_stop(&ctx);
4541
4542
0
  wp->flags |= PANE_REDRAWSCROLLBAR;
4543
0
}
4544
4545
static void
4546
window_copy_redraw_screen(struct window_mode_entry *wme)
4547
0
{
4548
0
  struct window_copy_mode_data  *data = wme->data;
4549
4550
0
  window_copy_redraw_lines(wme, 0, screen_size_y(&data->screen));
4551
0
}
4552
4553
static void
4554
window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin,
4555
    int no_reset)
4556
0
{
4557
0
  struct window_copy_mode_data  *data = wme->data;
4558
0
  u_int        xx, yy;
4559
4560
0
  xx = data->cx;
4561
0
  yy = screen_hsize(data->backing) + data->cy - data->oy;
4562
0
  switch (data->selflag) {
4563
0
  case SEL_WORD:
4564
0
    if (no_reset)
4565
0
      break;
4566
0
    begin = 0;
4567
0
    if (data->dy > yy || (data->dy == yy && data->dx > xx)) {
4568
      /* Right to left selection. */
4569
0
      window_copy_cursor_previous_word_pos(wme,
4570
0
          data->separators, &xx, &yy);
4571
0
      begin = 1;
4572
4573
      /* Reset the end. */
4574
0
      data->endselx = data->endselrx;
4575
0
      data->endsely = data->endselry;
4576
0
    } else {
4577
      /* Left to right selection. */
4578
0
      if (xx >= window_copy_find_length(wme, yy) ||
4579
0
          !window_copy_in_set(wme, xx + 1, yy, WHITESPACE)) {
4580
0
        window_copy_cursor_next_word_end_pos(wme,
4581
0
            data->separators, &xx, &yy);
4582
0
      }
4583
4584
      /* Reset the start. */
4585
0
      data->selx = data->selrx;
4586
0
      data->sely = data->selry;
4587
0
    }
4588
0
    break;
4589
0
  case SEL_LINE:
4590
0
    if (no_reset)
4591
0
      break;
4592
0
    begin = 0;
4593
0
    if (data->dy > yy) {
4594
      /* Right to left selection. */
4595
0
      xx = 0;
4596
0
      begin = 1;
4597
4598
      /* Reset the end. */
4599
0
      data->endselx = data->endselrx;
4600
0
      data->endsely = data->endselry;
4601
0
    } else {
4602
      /* Left to right selection. */
4603
0
      if (yy < data->endselry)
4604
0
        yy = data->endselry;
4605
0
      xx = window_copy_find_length(wme, yy);
4606
4607
      /* Reset the start. */
4608
0
      data->selx = data->selrx;
4609
0
      data->sely = data->selry;
4610
0
    }
4611
0
    break;
4612
0
  case SEL_CHAR:
4613
0
    break;
4614
0
  }
4615
0
  if (begin) {
4616
0
    data->selx = xx;
4617
0
    data->sely = yy;
4618
0
  } else {
4619
0
    data->endselx = xx;
4620
0
    data->endsely = yy;
4621
0
  }
4622
0
}
4623
4624
static void
4625
window_copy_synchronize_cursor(struct window_mode_entry *wme, int no_reset)
4626
0
{
4627
0
  struct window_copy_mode_data  *data = wme->data;
4628
4629
0
  switch (data->cursordrag) {
4630
0
  case CURSORDRAG_ENDSEL:
4631
0
    window_copy_synchronize_cursor_end(wme, 0, no_reset);
4632
0
    break;
4633
0
  case CURSORDRAG_SEL:
4634
0
    window_copy_synchronize_cursor_end(wme, 1, no_reset);
4635
0
    break;
4636
0
  case CURSORDRAG_NONE:
4637
0
    break;
4638
0
  }
4639
0
}
4640
4641
static void
4642
window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
4643
0
{
4644
0
  struct window_pane    *wp = wme->wp;
4645
0
  struct window_copy_mode_data  *data = wme->data;
4646
0
  struct screen     *s = &data->screen;
4647
0
  struct screen_write_ctx    ctx;
4648
0
  u_int        old_cx, old_cy;
4649
4650
0
  old_cx = data->cx; old_cy = data->cy;
4651
0
  data->cx = cx; data->cy = cy;
4652
0
  if (old_cx == screen_size_x(s))
4653
0
    window_copy_redraw_lines(wme, old_cy, 1);
4654
0
  if (data->cx == screen_size_x(s))
4655
0
    window_copy_redraw_lines(wme, data->cy, 1);
4656
0
  else {
4657
0
    screen_write_start_pane(&ctx, wp, NULL);
4658
0
    screen_write_cursormove(&ctx, data->cx, data->cy, 0);
4659
0
    screen_write_stop(&ctx);
4660
0
  }
4661
0
}
4662
4663
static void
4664
window_copy_start_selection(struct window_mode_entry *wme)
4665
0
{
4666
0
  struct window_copy_mode_data  *data = wme->data;
4667
4668
0
  data->selx = data->cx;
4669
0
  data->sely = screen_hsize(data->backing) + data->cy - data->oy;
4670
4671
0
  data->endselx = data->selx;
4672
0
  data->endsely = data->sely;
4673
4674
0
  data->cursordrag = CURSORDRAG_ENDSEL;
4675
4676
0
  window_copy_set_selection(wme, 1, 0);
4677
0
}
4678
4679
static int
4680
window_copy_adjust_selection(struct window_mode_entry *wme, u_int *selx,
4681
    u_int *sely)
4682
0
{
4683
0
  struct window_copy_mode_data  *data = wme->data;
4684
0
  struct screen     *s = &data->screen;
4685
0
  u_int          sx, sy, ty;
4686
0
  int        relpos;
4687
4688
0
  sx = *selx;
4689
0
  sy = *sely;
4690
4691
0
  ty = screen_hsize(data->backing) - data->oy;
4692
0
  if (sy < ty) {
4693
0
    relpos = WINDOW_COPY_REL_POS_ABOVE;
4694
0
    if (!data->rectflag)
4695
0
      sx = 0;
4696
0
    sy = 0;
4697
0
  } else if (sy > ty + screen_size_y(s) - 1) {
4698
0
    relpos = WINDOW_COPY_REL_POS_BELOW;
4699
0
    if (!data->rectflag)
4700
0
      sx = screen_size_x(s) - 1;
4701
0
    sy = screen_size_y(s) - 1;
4702
0
  } else {
4703
0
    relpos = WINDOW_COPY_REL_POS_ON_SCREEN;
4704
0
    sy -= ty;
4705
0
  }
4706
4707
0
  *selx = sx;
4708
0
  *sely = sy;
4709
0
  return (relpos);
4710
0
}
4711
4712
static int
4713
window_copy_update_selection(struct window_mode_entry *wme, int may_redraw,
4714
    int no_reset)
4715
0
{
4716
0
  struct window_copy_mode_data  *data = wme->data;
4717
0
  struct screen     *s = &data->screen;
4718
4719
0
  if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
4720
0
    return (0);
4721
0
  return (window_copy_set_selection(wme, may_redraw, no_reset));
4722
0
}
4723
4724
static int
4725
window_copy_set_selection(struct window_mode_entry *wme, int may_redraw,
4726
    int no_reset)
4727
0
{
4728
0
  struct window_pane    *wp = wme->wp;
4729
0
  struct window_copy_mode_data  *data = wme->data;
4730
0
  struct screen     *s = &data->screen;
4731
0
  struct options      *oo = wp->window->options;
4732
0
  struct grid_cell     gc;
4733
0
  u_int        sx, sy, cy, endsx, endsy;
4734
0
  int        startrelpos, endrelpos;
4735
0
  struct format_tree    *ft;
4736
4737
0
  window_copy_synchronize_cursor(wme, no_reset);
4738
4739
  /* Adjust the selection. */
4740
0
  sx = data->selx;
4741
0
  sy = data->sely;
4742
0
  startrelpos = window_copy_adjust_selection(wme, &sx, &sy);
4743
4744
  /* Adjust the end of selection. */
4745
0
  endsx = data->endselx;
4746
0
  endsy = data->endsely;
4747
0
  endrelpos = window_copy_adjust_selection(wme, &endsx, &endsy);
4748
4749
  /* Selection is outside of the current screen */
4750
0
  if (startrelpos == endrelpos &&
4751
0
      startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) {
4752
0
    screen_hide_selection(s);
4753
0
    return (0);
4754
0
  }
4755
4756
  /* Set colours and selection. */
4757
0
  ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
4758
0
  style_apply(&gc, oo, "copy-mode-selection-style", ft);
4759
0
  gc.flags |= GRID_FLAG_NOPALETTE;
4760
0
  format_free(ft);
4761
0
  screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
4762
0
      data->modekeys, &gc);
4763
4764
0
  if (data->rectflag && may_redraw) {
4765
    /*
4766
     * Can't rely on the caller to redraw the right lines for
4767
     * rectangle selection - find the highest line and the number
4768
     * of lines, and redraw just past that in both directions
4769
     */
4770
0
    cy = data->cy;
4771
0
    if (data->cursordrag == CURSORDRAG_ENDSEL) {
4772
0
      if (sy < cy)
4773
0
        window_copy_redraw_lines(wme, sy, cy - sy + 1);
4774
0
      else
4775
0
        window_copy_redraw_lines(wme, cy, sy - cy + 1);
4776
0
    } else {
4777
0
      if (endsy < cy) {
4778
0
        window_copy_redraw_lines(wme, endsy,
4779
0
            cy - endsy + 1);
4780
0
      } else {
4781
0
        window_copy_redraw_lines(wme, cy,
4782
0
            endsy - cy + 1);
4783
0
      }
4784
0
    }
4785
0
  }
4786
4787
0
  return (1);
4788
0
}
4789
4790
static void *
4791
window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
4792
0
{
4793
0
  struct window_pane    *wp = wme->wp;
4794
0
  struct window_copy_mode_data  *data = wme->data;
4795
0
  struct screen     *s = &data->screen;
4796
0
  char        *buf;
4797
0
  size_t         off;
4798
0
  u_int        i, xx, yy, sx, sy, ex, ey, ey_last;
4799
0
  u_int        firstsx, lastex, restex, restsx, selx;
4800
0
  int        keys;
4801
4802
0
  if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) {
4803
0
    buf = window_copy_match_at_cursor(data);
4804
0
    if (buf != NULL)
4805
0
      *len = strlen(buf);
4806
0
    else
4807
0
      *len = 0;
4808
0
    return (buf);
4809
0
  }
4810
4811
0
  buf = xmalloc(1);
4812
0
  off = 0;
4813
4814
0
  *buf = '\0';
4815
4816
  /*
4817
   * The selection extends from selx,sely to (adjusted) cx,cy on
4818
   * the base screen.
4819
   */
4820
4821
  /* Find start and end. */
4822
0
  xx = data->endselx;
4823
0
  yy = data->endsely;
4824
0
  if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
4825
0
    sx = xx; sy = yy;
4826
0
    ex = data->selx; ey = data->sely;
4827
0
  } else {
4828
0
    sx = data->selx; sy = data->sely;
4829
0
    ex = xx; ey = yy;
4830
0
  }
4831
4832
  /* Trim ex to end of line. */
4833
0
  ey_last = window_copy_find_length(wme, ey);
4834
0
  if (ex > ey_last)
4835
0
    ex = ey_last;
4836
4837
  /*
4838
   * Deal with rectangle-copy if necessary; four situations: start of
4839
   * first line (firstsx), end of last line (lastex), start (restsx) and
4840
   * end (restex) of all other lines.
4841
   */
4842
0
  xx = screen_size_x(s);
4843
4844
  /*
4845
   * Behave according to mode-keys. If it is emacs, copy like emacs,
4846
   * keeping the top-left-most character, and dropping the
4847
   * bottom-right-most, regardless of copy direction. If it is vi, also
4848
   * keep bottom-right-most character.
4849
   */
4850
0
  keys = options_get_number(wp->window->options, "mode-keys");
4851
0
  if (data->rectflag) {
4852
    /*
4853
     * Need to ignore the column with the cursor in it, which for
4854
     * rectangular copy means knowing which side the cursor is on.
4855
     */
4856
0
    if (data->cursordrag == CURSORDRAG_ENDSEL)
4857
0
      selx = data->selx;
4858
0
    else
4859
0
      selx = data->endselx;
4860
0
    if (selx < data->cx) {
4861
      /* Selection start is on the left. */
4862
0
      if (keys == MODEKEY_EMACS) {
4863
0
        lastex = data->cx;
4864
0
        restex = data->cx;
4865
0
      }
4866
0
      else {
4867
0
        lastex = data->cx + 1;
4868
0
        restex = data->cx + 1;
4869
0
      }
4870
0
      firstsx = selx;
4871
0
      restsx = selx;
4872
0
    } else {
4873
      /* Cursor is on the left. */
4874
0
      lastex = selx + 1;
4875
0
      restex = selx + 1;
4876
0
      firstsx = data->cx;
4877
0
      restsx = data->cx;
4878
0
    }
4879
0
  } else {
4880
0
    if (keys == MODEKEY_EMACS)
4881
0
      lastex = ex;
4882
0
    else
4883
0
      lastex = ex + 1;
4884
0
    restex = xx;
4885
0
    firstsx = sx;
4886
0
    restsx = 0;
4887
0
  }
4888
4889
  /* Copy the lines. */
4890
0
  for (i = sy; i <= ey; i++) {
4891
0
    window_copy_copy_line(wme, &buf, &off, i,
4892
0
        (i == sy ? firstsx : restsx),
4893
0
        (i == ey ? lastex : restex));
4894
0
  }
4895
4896
  /* Don't bother if no data. */
4897
0
  if (off == 0) {
4898
0
    free(buf);
4899
0
    *len = 0;
4900
0
    return (NULL);
4901
0
  }
4902
   /* Remove final \n (unless at end in vi mode). */
4903
0
  if (keys == MODEKEY_EMACS || lastex <= ey_last) {
4904
0
    if (~grid_get_line(data->backing->grid, ey)->flags &
4905
0
        GRID_LINE_WRAPPED || lastex != ey_last)
4906
0
      off -= 1;
4907
0
  }
4908
0
  *len = off;
4909
0
  return (buf);
4910
0
}
4911
4912
static void
4913
window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
4914
    void *buf, size_t len, int set_paste, int set_clip)
4915
0
{
4916
0
  struct window_pane  *wp = wme->wp;
4917
0
  struct screen_write_ctx  ctx;
4918
4919
0
  if (set_clip &&
4920
0
      options_get_number(global_options, "set-clipboard") != 0) {
4921
0
    screen_write_start_pane(&ctx, wp, NULL);
4922
0
    screen_write_setselection(&ctx, "", buf, len);
4923
0
    screen_write_stop(&ctx);
4924
0
    notify_pane("pane-set-clipboard", wp);
4925
0
  }
4926
4927
0
  if (set_paste)
4928
0
    paste_add(prefix, buf, len);
4929
0
  else
4930
0
    free(buf);
4931
0
}
4932
4933
static void *
4934
window_copy_pipe_run(struct window_mode_entry *wme, struct session *s,
4935
    const char *cmd, size_t *len)
4936
0
{
4937
0
  void    *buf;
4938
0
  struct job  *job;
4939
4940
0
  buf = window_copy_get_selection(wme, len);
4941
0
  if (cmd == NULL || *cmd == '\0')
4942
0
    cmd = options_get_string(global_options, "copy-command");
4943
0
  if (cmd != NULL && *cmd != '\0') {
4944
0
    job = job_run(cmd, 0, NULL, NULL, s, NULL, NULL, NULL, NULL,
4945
0
        NULL, JOB_NOWAIT, -1, -1);
4946
0
    bufferevent_write(job_get_event(job), buf, *len);
4947
0
  }
4948
0
  return (buf);
4949
0
}
4950
4951
static void
4952
window_copy_pipe(struct window_mode_entry *wme, struct session *s,
4953
    const char *cmd)
4954
0
{
4955
0
  void  *buf;
4956
0
  size_t  len;
4957
4958
0
  buf = window_copy_pipe_run(wme, s, cmd, &len);
4959
0
  free (buf);
4960
0
}
4961
4962
static void
4963
window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
4964
    const char *prefix, const char *cmd, int set_paste, int set_clip)
4965
0
{
4966
0
  void  *buf;
4967
0
  size_t   len;
4968
4969
0
  buf = window_copy_pipe_run(wme, s, cmd, &len);
4970
0
  if (buf != NULL) {
4971
0
    window_copy_copy_buffer(wme, prefix, buf, len, set_paste,
4972
0
        set_clip);
4973
0
  }
4974
0
}
4975
4976
static void
4977
window_copy_copy_selection(struct window_mode_entry *wme, const char *prefix,
4978
    int set_paste, int set_clip)
4979
0
{
4980
0
  char  *buf;
4981
0
  size_t   len;
4982
4983
0
  buf = window_copy_get_selection(wme, &len);
4984
0
  if (buf != NULL) {
4985
0
    window_copy_copy_buffer(wme, prefix, buf, len, set_paste,
4986
0
        set_clip);
4987
0
  }
4988
0
}
4989
4990
static void
4991
window_copy_append_selection(struct window_mode_entry *wme)
4992
0
{
4993
0
  struct window_pane    *wp = wme->wp;
4994
0
  char        *buf;
4995
0
  struct paste_buffer   *pb;
4996
0
  const char      *bufdata, *bufname = NULL;
4997
0
  size_t         len, bufsize;
4998
0
  struct screen_write_ctx    ctx;
4999
5000
0
  buf = window_copy_get_selection(wme, &len);
5001
0
  if (buf == NULL)
5002
0
    return;
5003
5004
0
  if (options_get_number(global_options, "set-clipboard") != 0) {
5005
0
    screen_write_start_pane(&ctx, wp, NULL);
5006
0
    screen_write_setselection(&ctx, "", buf, len);
5007
0
    screen_write_stop(&ctx);
5008
0
    notify_pane("pane-set-clipboard", wp);
5009
0
  }
5010
5011
0
  pb = paste_get_top(&bufname);
5012
0
  if (pb != NULL) {
5013
0
    bufdata = paste_buffer_data(pb, &bufsize);
5014
0
    buf = xrealloc(buf, len + bufsize);
5015
0
    memmove(buf + bufsize, buf, len);
5016
0
    memcpy(buf, bufdata, bufsize);
5017
0
    len += bufsize;
5018
0
  }
5019
0
  if (paste_set(buf, len, bufname, NULL) != 0)
5020
0
    free(buf);
5021
0
}
5022
5023
static void
5024
window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
5025
    u_int sy, u_int sx, u_int ex)
5026
0
{
5027
0
  struct window_copy_mode_data  *data = wme->data;
5028
0
  struct grid     *gd = data->backing->grid;
5029
0
  struct grid_cell     gc;
5030
0
  struct grid_line    *gl;
5031
0
  struct utf8_data     ud;
5032
0
  u_int        i, xx, wrapped = 0;
5033
0
  const char      *s;
5034
5035
0
  if (sx > ex)
5036
0
    return;
5037
5038
  /*
5039
   * Work out if the line was wrapped at the screen edge and all of it is
5040
   * on screen.
5041
   */
5042
0
  gl = grid_get_line(gd, sy);
5043
0
  if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
5044
0
    wrapped = 1;
5045
5046
  /* If the line was wrapped, don't strip spaces (use the full length). */
5047
0
  if (wrapped)
5048
0
    xx = gl->cellsize;
5049
0
  else
5050
0
    xx = window_copy_find_length(wme, sy);
5051
0
  if (ex > xx)
5052
0
    ex = xx;
5053
0
  if (sx > xx)
5054
0
    sx = xx;
5055
5056
0
  if (sx < ex) {
5057
0
    for (i = sx; i < ex; i++) {
5058
0
      grid_get_cell(gd, i, sy, &gc);
5059
0
      if (gc.flags & GRID_FLAG_PADDING)
5060
0
        continue;
5061
0
      if (gc.flags & GRID_FLAG_TAB)
5062
0
        utf8_set(&ud, '\t');
5063
0
      else
5064
0
        utf8_copy(&ud, &gc.data);
5065
0
      if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
5066
0
        s = tty_acs_get(NULL, ud.data[0]);
5067
0
        if (s != NULL && strlen(s) <= sizeof ud.data) {
5068
0
          ud.size = strlen(s);
5069
0
          memcpy(ud.data, s, ud.size);
5070
0
        }
5071
0
      }
5072
5073
0
      *buf = xrealloc(*buf, (*off) + ud.size);
5074
0
      memcpy(*buf + *off, ud.data, ud.size);
5075
0
      *off += ud.size;
5076
0
    }
5077
0
  }
5078
5079
  /* Only add a newline if the line wasn't wrapped. */
5080
0
  if (!wrapped || ex != xx) {
5081
0
    *buf = xrealloc(*buf, (*off) + 1);
5082
0
    (*buf)[(*off)++] = '\n';
5083
0
  }
5084
0
}
5085
5086
static void
5087
window_copy_clear_selection(struct window_mode_entry *wme)
5088
0
{
5089
0
  struct window_copy_mode_data   *data = wme->data;
5090
0
  u_int       px, py;
5091
5092
0
  screen_clear_selection(&data->screen);
5093
5094
0
  data->cursordrag = CURSORDRAG_NONE;
5095
0
  data->lineflag = LINE_SEL_NONE;
5096
0
  data->selflag = SEL_CHAR;
5097
5098
0
  py = screen_hsize(data->backing) + data->cy - data->oy;
5099
0
  px = window_copy_find_length(wme, py);
5100
0
  if (data->cx > px)
5101
0
    window_copy_update_cursor(wme, px, data->cy);
5102
0
}
5103
5104
static int
5105
window_copy_in_set(struct window_mode_entry *wme, u_int px, u_int py,
5106
    const char *set)
5107
0
{
5108
0
  struct window_copy_mode_data  *data = wme->data;
5109
5110
0
  return (grid_in_set(data->backing->grid, px, py, set));
5111
0
}
5112
5113
static u_int
5114
window_copy_find_length(struct window_mode_entry *wme, u_int py)
5115
0
{
5116
0
  struct window_copy_mode_data  *data = wme->data;
5117
5118
0
  return (grid_line_length(data->backing->grid, py));
5119
0
}
5120
5121
static void
5122
window_copy_cursor_start_of_line(struct window_mode_entry *wme)
5123
0
{
5124
0
  struct window_copy_mode_data  *data = wme->data;
5125
0
  struct screen     *back_s = data->backing;
5126
0
  struct grid_reader     gr;
5127
0
  u_int        px, py, oldy, hsize;
5128
5129
0
  px = data->cx;
5130
0
  hsize = screen_hsize(back_s);
5131
0
  py = hsize + data->cy - data->oy;
5132
0
  oldy = data->cy;
5133
5134
0
  grid_reader_start(&gr, back_s->grid, px, py);
5135
0
  grid_reader_cursor_start_of_line(&gr, 1);
5136
0
  grid_reader_get_cursor(&gr, &px, &py);
5137
0
  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
5138
0
}
5139
5140
static void
5141
window_copy_cursor_back_to_indentation(struct window_mode_entry *wme)
5142
0
{
5143
0
  struct window_copy_mode_data  *data = wme->data;
5144
0
  struct screen     *back_s = data->backing;
5145
0
  struct grid_reader     gr;
5146
0
  u_int        px, py, oldy, hsize;
5147
5148
0
  px = data->cx;
5149
0
  hsize = screen_hsize(back_s);
5150
0
  py = hsize + data->cy - data->oy;
5151
0
  oldy = data->cy;
5152
5153
0
  grid_reader_start(&gr, back_s->grid, px, py);
5154
0
  grid_reader_cursor_back_to_indentation(&gr);
5155
0
  grid_reader_get_cursor(&gr, &px, &py);
5156
0
  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
5157
0
}
5158
5159
static void
5160
window_copy_cursor_end_of_line(struct window_mode_entry *wme)
5161
0
{
5162
0
  struct window_copy_mode_data  *data = wme->data;
5163
0
  struct screen     *back_s = data->backing;
5164
0
  struct grid_reader     gr;
5165
0
  u_int        px, py, oldy, hsize;
5166
5167
0
  px = data->cx;
5168
0
  hsize = screen_hsize(back_s);
5169
0
  py =  hsize + data->cy - data->oy;
5170
0
  oldy = data->cy;
5171
5172
0
  grid_reader_start(&gr, back_s->grid, px, py);
5173
0
  if (data->screen.sel != NULL && data->rectflag)
5174
0
    grid_reader_cursor_end_of_line(&gr, 1, 1);
5175
0
  else
5176
0
    grid_reader_cursor_end_of_line(&gr, 1, 0);
5177
0
  grid_reader_get_cursor(&gr, &px, &py);
5178
0
  window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
5179
0
      data->oy, oldy, px, py, 0);
5180
0
}
5181
5182
static void
5183
window_copy_other_end(struct window_mode_entry *wme)
5184
0
{
5185
0
  struct window_copy_mode_data  *data = wme->data;
5186
0
  struct screen     *s = &data->screen;
5187
0
  u_int        selx, sely, cy, yy, hsize;
5188
5189
0
  if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
5190
0
    return;
5191
5192
0
  if (data->lineflag == LINE_SEL_LEFT_RIGHT)
5193
0
    data->lineflag = LINE_SEL_RIGHT_LEFT;
5194
0
  else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
5195
0
    data->lineflag = LINE_SEL_LEFT_RIGHT;
5196
5197
0
  switch (data->cursordrag) {
5198
0
    case CURSORDRAG_NONE:
5199
0
    case CURSORDRAG_SEL:
5200
0
      data->cursordrag = CURSORDRAG_ENDSEL;
5201
0
      break;
5202
0
    case CURSORDRAG_ENDSEL:
5203
0
      data->cursordrag = CURSORDRAG_SEL;
5204
0
      break;
5205
0
  }
5206
5207
0
  selx = data->endselx;
5208
0
  sely = data->endsely;
5209
0
  if (data->cursordrag == CURSORDRAG_SEL) {
5210
0
    selx = data->selx;
5211
0
    sely = data->sely;
5212
0
  }
5213
5214
0
  cy = data->cy;
5215
0
  yy = screen_hsize(data->backing) + data->cy - data->oy;
5216
5217
0
  data->cx = selx;
5218
5219
0
  hsize = screen_hsize(data->backing);
5220
0
  if (sely < hsize - data->oy) { /* above */
5221
0
    data->oy = hsize - sely;
5222
0
    data->cy = 0;
5223
0
  } else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */
5224
0
    data->oy = hsize - sely + screen_size_y(s) - 1;
5225
0
    data->cy = screen_size_y(s) - 1;
5226
0
  } else
5227
0
    data->cy = cy + sely - yy;
5228
5229
0
  window_copy_update_selection(wme, 1, 1);
5230
0
  window_copy_redraw_screen(wme);
5231
0
}
5232
5233
static void
5234
window_copy_cursor_left(struct window_mode_entry *wme)
5235
0
{
5236
0
  struct window_copy_mode_data  *data = wme->data;
5237
0
  struct screen     *back_s = data->backing;
5238
0
  struct grid_reader     gr;
5239
0
  u_int        px, py, oldy, hsize;
5240
5241
0
  px = data->cx;
5242
0
  hsize = screen_hsize(back_s);
5243
0
  py = hsize + data->cy - data->oy;
5244
0
  oldy = data->cy;
5245
5246
0
  grid_reader_start(&gr, back_s->grid, px, py);
5247
0
  grid_reader_cursor_left(&gr, 1);
5248
0
  grid_reader_get_cursor(&gr, &px, &py);
5249
0
  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
5250
0
}
5251
5252
static void
5253
window_copy_cursor_right(struct window_mode_entry *wme, int all)
5254
0
{
5255
0
  struct window_copy_mode_data  *data = wme->data;
5256
0
  struct screen     *back_s = data->backing;
5257
0
  struct grid_reader     gr;
5258
0
  u_int        px, py, oldy, hsize;
5259
5260
0
  px = data->cx;
5261
0
  hsize = screen_hsize(back_s);
5262
0
  py = hsize + data->cy - data->oy;
5263
0
  oldy = data->cy;
5264
5265
0
  grid_reader_start(&gr, back_s->grid, px, py);
5266
0
  grid_reader_cursor_right(&gr, 1, all);
5267
0
  grid_reader_get_cursor(&gr, &px, &py);
5268
0
  window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
5269
0
      data->oy, oldy, px, py, 0);
5270
0
}
5271
5272
static void
5273
window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
5274
0
{
5275
0
  struct window_copy_mode_data  *data = wme->data;
5276
0
  struct screen     *s = &data->screen;
5277
0
  u_int        ox, oy, px, py;
5278
0
  int        norectsel;
5279
5280
0
  norectsel = data->screen.sel == NULL || !data->rectflag;
5281
0
  oy = screen_hsize(data->backing) + data->cy - data->oy;
5282
0
  ox = window_copy_find_length(wme, oy);
5283
0
  if (norectsel && data->cx != ox) {
5284
0
    data->lastcx = data->cx;
5285
0
    data->lastsx = ox;
5286
0
  }
5287
5288
0
  if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
5289
0
    window_copy_other_end(wme);
5290
5291
0
  if (scroll_only || data->cy == 0) {
5292
0
    if (norectsel)
5293
0
      data->cx = data->lastcx;
5294
0
    window_copy_scroll_down(wme, 1);
5295
0
    if (scroll_only) {
5296
0
      if (data->cy == screen_size_y(s) - 1)
5297
0
        window_copy_redraw_lines(wme, data->cy, 1);
5298
0
      else
5299
0
        window_copy_redraw_lines(wme, data->cy, 2);
5300
0
    }
5301
0
  } else {
5302
0
    if (norectsel) {
5303
0
      window_copy_update_cursor(wme, data->lastcx,
5304
0
          data->cy - 1);
5305
0
    } else
5306
0
      window_copy_update_cursor(wme, data->cx, data->cy - 1);
5307
0
    if (window_copy_update_selection(wme, 1, 0)) {
5308
0
      if (data->cy == screen_size_y(s) - 1)
5309
0
        window_copy_redraw_lines(wme, data->cy, 1);
5310
0
      else
5311
0
        window_copy_redraw_lines(wme, data->cy, 2);
5312
0
    }
5313
0
  }
5314
5315
0
  if (norectsel) {
5316
0
    py = screen_hsize(data->backing) + data->cy - data->oy;
5317
0
    px = window_copy_find_length(wme, py);
5318
0
    if ((data->cx >= data->lastsx && data->cx != px) ||
5319
0
        data->cx > px)
5320
0
    {
5321
0
      window_copy_update_cursor(wme, px, data->cy);
5322
0
      if (window_copy_update_selection(wme, 1, 0))
5323
0
        window_copy_redraw_lines(wme, data->cy, 1);
5324
0
    }
5325
0
  }
5326
5327
0
  if (data->lineflag == LINE_SEL_LEFT_RIGHT)
5328
0
  {
5329
0
    py = screen_hsize(data->backing) + data->cy - data->oy;
5330
0
    if (data->rectflag)
5331
0
      px = screen_size_x(data->backing);
5332
0
    else
5333
0
      px = window_copy_find_length(wme, py);
5334
0
    window_copy_update_cursor(wme, px, data->cy);
5335
0
    if (window_copy_update_selection(wme, 1, 0))
5336
0
      window_copy_redraw_lines(wme, data->cy, 1);
5337
0
  }
5338
0
  else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
5339
0
  {
5340
0
    window_copy_update_cursor(wme, 0, data->cy);
5341
0
    if (window_copy_update_selection(wme, 1, 0))
5342
0
      window_copy_redraw_lines(wme, data->cy, 1);
5343
0
  }
5344
0
}
5345
5346
static void
5347
window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
5348
0
{
5349
0
  struct window_copy_mode_data  *data = wme->data;
5350
0
  struct screen     *s = &data->screen;
5351
0
  u_int        ox, oy, px, py;
5352
0
  int        norectsel;
5353
5354
0
  norectsel = data->screen.sel == NULL || !data->rectflag;
5355
0
  oy = screen_hsize(data->backing) + data->cy - data->oy;
5356
0
  ox = window_copy_find_length(wme, oy);
5357
0
  if (norectsel && data->cx != ox) {
5358
0
    data->lastcx = data->cx;
5359
0
    data->lastsx = ox;
5360
0
  }
5361
5362
0
  if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
5363
0
    window_copy_other_end(wme);
5364
5365
0
  if (scroll_only || data->cy == screen_size_y(s) - 1) {
5366
0
    if (norectsel)
5367
0
      data->cx = data->lastcx;
5368
0
    window_copy_scroll_up(wme, 1);
5369
0
    if (scroll_only && data->cy > 0)
5370
0
      window_copy_redraw_lines(wme, data->cy - 1, 2);
5371
0
  } else {
5372
0
    if (norectsel) {
5373
0
      window_copy_update_cursor(wme, data->lastcx,
5374
0
          data->cy + 1);
5375
0
    } else
5376
0
      window_copy_update_cursor(wme, data->cx, data->cy + 1);
5377
0
    if (window_copy_update_selection(wme, 1, 0))
5378
0
      window_copy_redraw_lines(wme, data->cy - 1, 2);
5379
0
  }
5380
5381
0
  if (norectsel) {
5382
0
    py = screen_hsize(data->backing) + data->cy - data->oy;
5383
0
    px = window_copy_find_length(wme, py);
5384
0
    if ((data->cx >= data->lastsx && data->cx != px) ||
5385
0
        data->cx > px)
5386
0
    {
5387
0
      window_copy_update_cursor(wme, px, data->cy);
5388
0
      if (window_copy_update_selection(wme, 1, 0))
5389
0
        window_copy_redraw_lines(wme, data->cy, 1);
5390
0
    }
5391
0
  }
5392
5393
0
  if (data->lineflag == LINE_SEL_LEFT_RIGHT)
5394
0
  {
5395
0
    py = screen_hsize(data->backing) + data->cy - data->oy;
5396
0
    if (data->rectflag)
5397
0
      px = screen_size_x(data->backing);
5398
0
    else
5399
0
      px = window_copy_find_length(wme, py);
5400
0
    window_copy_update_cursor(wme, px, data->cy);
5401
0
    if (window_copy_update_selection(wme, 1, 0))
5402
0
      window_copy_redraw_lines(wme, data->cy, 1);
5403
0
  }
5404
0
  else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
5405
0
  {
5406
0
    window_copy_update_cursor(wme, 0, data->cy);
5407
0
    if (window_copy_update_selection(wme, 1, 0))
5408
0
      window_copy_redraw_lines(wme, data->cy, 1);
5409
0
  }
5410
0
}
5411
5412
static void
5413
window_copy_cursor_jump(struct window_mode_entry *wme)
5414
0
{
5415
0
  struct window_copy_mode_data  *data = wme->data;
5416
0
  struct screen     *back_s = data->backing;
5417
0
  struct grid_reader     gr;
5418
0
  u_int        px, py, oldy, hsize;
5419
5420
0
  px = data->cx + 1;
5421
0
  hsize = screen_hsize(back_s);
5422
0
  py = hsize + data->cy - data->oy;
5423
0
  oldy = data->cy;
5424
5425
0
  grid_reader_start(&gr, back_s->grid, px, py);
5426
0
  if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
5427
0
    grid_reader_get_cursor(&gr, &px, &py);
5428
0
    window_copy_acquire_cursor_down(wme, hsize,
5429
0
        screen_size_y(back_s), data->oy, oldy, px, py, 0);
5430
0
  }
5431
0
}
5432
5433
static void
5434
window_copy_cursor_jump_back(struct window_mode_entry *wme)
5435
0
{
5436
0
  struct window_copy_mode_data  *data = wme->data;
5437
0
  struct screen     *back_s = data->backing;
5438
0
  struct grid_reader     gr;
5439
0
  u_int        px, py, oldy, hsize;
5440
5441
0
  px = data->cx;
5442
0
  hsize = screen_hsize(back_s);
5443
0
  py = hsize + data->cy - data->oy;
5444
0
  oldy = data->cy;
5445
5446
0
  grid_reader_start(&gr, back_s->grid, px, py);
5447
0
  grid_reader_cursor_left(&gr, 0);
5448
0
  if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
5449
0
    grid_reader_get_cursor(&gr, &px, &py);
5450
0
    window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
5451
0
        py);
5452
0
  }
5453
0
}
5454
5455
static void
5456
window_copy_cursor_jump_to(struct window_mode_entry *wme)
5457
0
{
5458
0
  struct window_copy_mode_data  *data = wme->data;
5459
0
  struct screen     *back_s = data->backing;
5460
0
  struct grid_reader     gr;
5461
0
  u_int        px, py, oldy, hsize;
5462
5463
0
  px = data->cx + 2;
5464
0
  hsize = screen_hsize(back_s);
5465
0
  py = hsize + data->cy - data->oy;
5466
0
  oldy = data->cy;
5467
5468
0
  grid_reader_start(&gr, back_s->grid, px, py);
5469
0
  if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
5470
0
    grid_reader_cursor_left(&gr, 1);
5471
0
    grid_reader_get_cursor(&gr, &px, &py);
5472
0
    window_copy_acquire_cursor_down(wme, hsize,
5473
0
        screen_size_y(back_s), data->oy, oldy, px, py, 0);
5474
0
  }
5475
0
}
5476
5477
static void
5478
window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
5479
0
{
5480
0
  struct window_copy_mode_data  *data = wme->data;
5481
0
  struct screen     *back_s = data->backing;
5482
0
  struct grid_reader     gr;
5483
0
  u_int        px, py, oldy, hsize;
5484
5485
0
  px = data->cx;
5486
0
  hsize = screen_hsize(back_s);
5487
0
  py = hsize + data->cy - data->oy;
5488
0
  oldy = data->cy;
5489
5490
0
  grid_reader_start(&gr, back_s->grid, px, py);
5491
0
  grid_reader_cursor_left(&gr, 0);
5492
0
  grid_reader_cursor_left(&gr, 0);
5493
0
  if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
5494
0
    grid_reader_cursor_right(&gr, 1, 0);
5495
0
    grid_reader_get_cursor(&gr, &px, &py);
5496
0
    window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
5497
0
        py);
5498
0
  }
5499
0
}
5500
5501
static void
5502
window_copy_cursor_next_word(struct window_mode_entry *wme,
5503
    const char *separators)
5504
0
{
5505
0
  struct window_copy_mode_data  *data = wme->data;
5506
0
  struct screen     *back_s = data->backing;
5507
0
  struct grid_reader     gr;
5508
0
  u_int        px, py, oldy, hsize;
5509
5510
0
  px = data->cx;
5511
0
  hsize = screen_hsize(back_s);
5512
0
  py =  hsize + data->cy - data->oy;
5513
0
  oldy = data->cy;
5514
5515
0
  grid_reader_start(&gr, back_s->grid, px, py);
5516
0
  grid_reader_cursor_next_word(&gr, separators);
5517
0
  grid_reader_get_cursor(&gr, &px, &py);
5518
0
  window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
5519
0
      data->oy, oldy, px, py, 0);
5520
0
}
5521
5522
/* Compute the next place where a word ends. */
5523
static void
5524
window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme,
5525
    const char *separators, u_int *ppx, u_int *ppy)
5526
0
{
5527
0
  struct window_pane    *wp = wme->wp;
5528
0
  struct window_copy_mode_data  *data = wme->data;
5529
0
  struct options      *oo = wp->window->options;
5530
0
  struct screen     *back_s = data->backing;
5531
0
  struct grid_reader     gr;
5532
0
  u_int        px, py, hsize;
5533
5534
0
  px = data->cx;
5535
0
  hsize = screen_hsize(back_s);
5536
0
  py =  hsize + data->cy - data->oy;
5537
5538
0
  grid_reader_start(&gr, back_s->grid, px, py);
5539
0
  if (options_get_number(oo, "mode-keys") == MODEKEY_VI) {
5540
0
    if (!grid_reader_in_set(&gr, WHITESPACE))
5541
0
      grid_reader_cursor_right(&gr, 0, 0);
5542
0
    grid_reader_cursor_next_word_end(&gr, separators);
5543
0
    grid_reader_cursor_left(&gr, 1);
5544
0
  } else
5545
0
    grid_reader_cursor_next_word_end(&gr, separators);
5546
0
  grid_reader_get_cursor(&gr, &px, &py);
5547
0
  *ppx = px;
5548
0
  *ppy = py;
5549
0
}
5550
5551
/* Move to the next place where a word ends. */
5552
static void
5553
window_copy_cursor_next_word_end(struct window_mode_entry *wme,
5554
    const char *separators, int no_reset)
5555
0
{
5556
0
  struct window_pane    *wp = wme->wp;
5557
0
  struct window_copy_mode_data  *data = wme->data;
5558
0
  struct options      *oo = wp->window->options;
5559
0
  struct screen     *back_s = data->backing;
5560
0
  struct grid_reader     gr;
5561
0
  u_int        px, py, oldy, hsize;
5562
5563
0
  px = data->cx;
5564
0
  hsize = screen_hsize(back_s);
5565
0
  py =  hsize + data->cy - data->oy;
5566
0
  oldy = data->cy;
5567
5568
0
  grid_reader_start(&gr, back_s->grid, px, py);
5569
0
  if (options_get_number(oo, "mode-keys") == MODEKEY_VI) {
5570
0
    if (!grid_reader_in_set(&gr, WHITESPACE))
5571
0
      grid_reader_cursor_right(&gr, 0, 0);
5572
0
    grid_reader_cursor_next_word_end(&gr, separators);
5573
0
    grid_reader_cursor_left(&gr, 1);
5574
0
  } else
5575
0
    grid_reader_cursor_next_word_end(&gr, separators);
5576
0
  grid_reader_get_cursor(&gr, &px, &py);
5577
0
  window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
5578
0
      data->oy, oldy, px, py, no_reset);
5579
0
}
5580
5581
/* Compute the previous place where a word begins. */
5582
static void
5583
window_copy_cursor_previous_word_pos(struct window_mode_entry *wme,
5584
    const char *separators, u_int *ppx, u_int *ppy)
5585
0
{
5586
0
  struct window_copy_mode_data  *data = wme->data;
5587
0
  struct screen     *back_s = data->backing;
5588
0
  struct grid_reader     gr;
5589
0
  u_int        px, py, hsize;
5590
5591
0
  px = data->cx;
5592
0
  hsize = screen_hsize(back_s);
5593
0
  py = hsize + data->cy - data->oy;
5594
5595
0
  grid_reader_start(&gr, back_s->grid, px, py);
5596
0
  grid_reader_cursor_previous_word(&gr, separators, 0, 1);
5597
0
  grid_reader_get_cursor(&gr, &px, &py);
5598
0
  *ppx = px;
5599
0
  *ppy = py;
5600
0
}
5601
5602
/* Move to the previous place where a word begins. */
5603
static void
5604
window_copy_cursor_previous_word(struct window_mode_entry *wme,
5605
    const char *separators, int already)
5606
0
{
5607
0
  struct window_copy_mode_data  *data = wme->data;
5608
0
  struct window     *w = wme->wp->window;
5609
0
  struct screen     *back_s = data->backing;
5610
0
  struct grid_reader     gr;
5611
0
  u_int        px, py, oldy, hsize;
5612
0
  int        stop_at_eol;
5613
5614
0
  if (options_get_number(w->options, "mode-keys") == MODEKEY_EMACS)
5615
0
    stop_at_eol = 1;
5616
0
  else
5617
0
    stop_at_eol = 0;
5618
5619
0
  px = data->cx;
5620
0
  hsize = screen_hsize(back_s);
5621
0
  py = hsize + data->cy - data->oy;
5622
0
  oldy = data->cy;
5623
5624
0
  grid_reader_start(&gr, back_s->grid, px, py);
5625
0
  grid_reader_cursor_previous_word(&gr, separators, already, stop_at_eol);
5626
0
  grid_reader_get_cursor(&gr, &px, &py);
5627
0
  window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
5628
0
}
5629
5630
static void
5631
window_copy_cursor_prompt(struct window_mode_entry *wme, int direction,
5632
    int start_output)
5633
0
{
5634
0
  struct window_copy_mode_data  *data = wme->data;
5635
0
  struct screen     *s = data->backing;
5636
0
  struct grid     *gd = s->grid;
5637
0
  u_int        end_line;
5638
0
  u_int        line = gd->hsize - data->oy + data->cy;
5639
0
  int        add, line_flag;
5640
5641
0
  if (start_output)
5642
0
    line_flag = GRID_LINE_START_OUTPUT;
5643
0
  else
5644
0
    line_flag = GRID_LINE_START_PROMPT;
5645
5646
0
  if (direction == 0) { /* up */
5647
0
    add = -1;
5648
0
    end_line = 0;
5649
0
  } else { /* down */
5650
0
    add = 1;
5651
0
    end_line = gd->hsize + gd->sy - 1;
5652
0
  }
5653
5654
0
  if (line == end_line)
5655
0
    return;
5656
0
  for (;;) {
5657
0
    if (line == end_line)
5658
0
      return;
5659
0
    line += add;
5660
5661
0
    if (grid_get_line(gd, line)->flags & line_flag)
5662
0
      break;
5663
0
  }
5664
5665
0
  data->cx = 0;
5666
0
  if (line > gd->hsize) {
5667
0
    data->cy = line - gd->hsize;
5668
0
    data->oy = 0;
5669
0
  } else {
5670
0
    data->cy = 0;
5671
0
    data->oy = gd->hsize - line;
5672
0
  }
5673
5674
0
  window_copy_update_selection(wme, 1, 0);
5675
0
  window_copy_redraw_screen(wme);
5676
0
}
5677
5678
static void
5679
window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
5680
0
{
5681
0
  struct window_pane    *wp = wme->wp;
5682
0
  struct window_copy_mode_data  *data = wme->data;
5683
0
  struct screen     *s = &data->screen;
5684
0
  struct screen_write_ctx    ctx;
5685
5686
0
  if (data->oy < ny)
5687
0
    ny = data->oy;
5688
0
  if (ny == 0)
5689
0
    return;
5690
0
  data->oy -= ny;
5691
5692
0
  if (data->searchmark != NULL && !data->timeout)
5693
0
    window_copy_search_marks(wme, NULL, data->searchregex, 1);
5694
0
  window_copy_update_selection(wme, 0, 0);
5695
5696
0
  screen_write_start_pane(&ctx, wp, NULL);
5697
0
  screen_write_cursormove(&ctx, 0, 0, 0);
5698
0
  screen_write_deleteline(&ctx, ny, 8);
5699
0
  window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
5700
0
  window_copy_write_line(wme, &ctx, 0);
5701
0
  if (screen_size_y(s) > 1)
5702
0
    window_copy_write_line(wme, &ctx, 1);
5703
0
  if (screen_size_y(s) > 3)
5704
0
    window_copy_write_line(wme, &ctx, screen_size_y(s) - 2);
5705
0
  if (s->sel != NULL && screen_size_y(s) > ny)
5706
0
    window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1);
5707
0
  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
5708
0
  screen_write_stop(&ctx);
5709
0
  wp->flags |= PANE_REDRAWSCROLLBAR;
5710
0
}
5711
5712
static void
5713
window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
5714
0
{
5715
0
  struct window_pane    *wp = wme->wp;
5716
0
  struct window_copy_mode_data  *data = wme->data;
5717
0
  struct screen     *s = &data->screen;
5718
0
  struct screen_write_ctx    ctx;
5719
5720
0
  if (ny > screen_hsize(data->backing))
5721
0
    return;
5722
5723
0
  if (data->oy > screen_hsize(data->backing) - ny)
5724
0
    ny = screen_hsize(data->backing) - data->oy;
5725
0
  if (ny == 0)
5726
0
    return;
5727
0
  data->oy += ny;
5728
5729
0
  if (data->searchmark != NULL && !data->timeout)
5730
0
    window_copy_search_marks(wme, NULL, data->searchregex, 1);
5731
0
  window_copy_update_selection(wme, 0, 0);
5732
5733
0
  screen_write_start_pane(&ctx, wp, NULL);
5734
0
  screen_write_cursormove(&ctx, 0, 0, 0);
5735
0
  screen_write_insertline(&ctx, ny, 8);
5736
0
  window_copy_write_lines(wme, &ctx, 0, ny);
5737
0
  if (s->sel != NULL && screen_size_y(s) > ny)
5738
0
    window_copy_write_line(wme, &ctx, ny);
5739
0
  else if (ny == 1) /* nuke position */
5740
0
    window_copy_write_line(wme, &ctx, 1);
5741
0
  screen_write_cursormove(&ctx, data->cx, data->cy, 0);
5742
0
  screen_write_stop(&ctx);
5743
0
  wp->flags |= PANE_REDRAWSCROLLBAR;
5744
0
}
5745
5746
static void
5747
window_copy_rectangle_set(struct window_mode_entry *wme, int rectflag)
5748
0
{
5749
0
  struct window_copy_mode_data  *data = wme->data;
5750
0
  u_int        px, py;
5751
5752
0
  data->rectflag = rectflag;
5753
5754
0
  py = screen_hsize(data->backing) + data->cy - data->oy;
5755
0
  px = window_copy_find_length(wme, py);
5756
0
  if (data->cx > px)
5757
0
    window_copy_update_cursor(wme, px, data->cy);
5758
5759
0
  window_copy_update_selection(wme, 1, 0);
5760
0
  window_copy_redraw_screen(wme);
5761
0
}
5762
5763
static void
5764
window_copy_move_mouse(struct mouse_event *m)
5765
0
{
5766
0
  struct window_pane    *wp;
5767
0
  struct window_mode_entry  *wme;
5768
0
  u_int        x, y;
5769
5770
0
  wp = cmd_mouse_pane(m, NULL, NULL);
5771
0
  if (wp == NULL)
5772
0
    return;
5773
0
  wme = TAILQ_FIRST(&wp->modes);
5774
0
  if (wme == NULL)
5775
0
    return;
5776
0
  if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
5777
0
    return;
5778
5779
0
  if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
5780
0
    return;
5781
5782
0
  window_copy_update_cursor(wme, x, y);
5783
0
}
5784
5785
void
5786
window_copy_start_drag(struct client *c, struct mouse_event *m)
5787
0
{
5788
0
  struct window_pane    *wp;
5789
0
  struct window_mode_entry  *wme;
5790
0
  struct window_copy_mode_data  *data;
5791
0
  u_int        x, y, yg;
5792
5793
0
  if (c == NULL)
5794
0
    return;
5795
5796
0
  wp = cmd_mouse_pane(m, NULL, NULL);
5797
0
  if (wp == NULL)
5798
0
    return;
5799
0
  wme = TAILQ_FIRST(&wp->modes);
5800
0
  if (wme == NULL)
5801
0
    return;
5802
0
  if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
5803
0
    return;
5804
5805
0
  if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
5806
0
    return;
5807
5808
0
  c->tty.mouse_drag_update = window_copy_drag_update;
5809
0
  c->tty.mouse_drag_release = window_copy_drag_release;
5810
5811
0
  data = wme->data;
5812
0
  yg = screen_hsize(data->backing) + y - data->oy;
5813
0
  if (x < data->selrx || x > data->endselrx || yg != data->selry)
5814
0
    data->selflag = SEL_CHAR;
5815
0
  switch (data->selflag) {
5816
0
  case SEL_WORD:
5817
0
    if (data->separators != NULL) {
5818
0
      window_copy_update_cursor(wme, x, y);
5819
0
      window_copy_cursor_previous_word_pos(wme,
5820
0
          data->separators, &x, &y);
5821
0
      y -= screen_hsize(data->backing) - data->oy;
5822
0
    }
5823
0
    window_copy_update_cursor(wme, x, y);
5824
0
    break;
5825
0
  case SEL_LINE:
5826
0
    window_copy_update_cursor(wme, 0, y);
5827
0
    break;
5828
0
  case SEL_CHAR:
5829
0
    window_copy_update_cursor(wme, x, y);
5830
0
    window_copy_start_selection(wme);
5831
0
    break;
5832
0
  }
5833
5834
0
  window_copy_redraw_screen(wme);
5835
0
  window_copy_drag_update(c, m);
5836
0
}
5837
5838
static void
5839
window_copy_drag_update(struct client *c, struct mouse_event *m)
5840
0
{
5841
0
  struct window_pane    *wp;
5842
0
  struct window_mode_entry  *wme;
5843
0
  struct window_copy_mode_data  *data;
5844
0
  u_int        x, y, old_cx, old_cy;
5845
0
  struct timeval       tv = {
5846
0
    .tv_usec = WINDOW_COPY_DRAG_REPEAT_TIME
5847
0
  };
5848
5849
0
  if (c == NULL)
5850
0
    return;
5851
5852
0
  wp = cmd_mouse_pane(m, NULL, NULL);
5853
0
  if (wp == NULL)
5854
0
    return;
5855
0
  wme = TAILQ_FIRST(&wp->modes);
5856
0
  if (wme == NULL)
5857
0
    return;
5858
0
  if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
5859
0
    return;
5860
5861
0
  data = wme->data;
5862
0
  evtimer_del(&data->dragtimer);
5863
5864
0
  if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
5865
0
    return;
5866
0
  old_cx = data->cx;
5867
0
  old_cy = data->cy;
5868
5869
0
  window_copy_update_cursor(wme, x, y);
5870
0
  if (window_copy_update_selection(wme, 1, 0))
5871
0
    window_copy_redraw_selection(wme, old_cy);
5872
0
  if (old_cy != data->cy || old_cx == data->cx) {
5873
0
    if (y == 0) {
5874
0
      evtimer_add(&data->dragtimer, &tv);
5875
0
      window_copy_cursor_up(wme, 1);
5876
0
    } else if (y == screen_size_y(&data->screen) - 1) {
5877
0
      evtimer_add(&data->dragtimer, &tv);
5878
0
      window_copy_cursor_down(wme, 1);
5879
0
    }
5880
0
  }
5881
0
}
5882
5883
static void
5884
window_copy_drag_release(struct client *c, struct mouse_event *m)
5885
0
{
5886
0
  struct window_pane    *wp;
5887
0
  struct window_mode_entry  *wme;
5888
0
  struct window_copy_mode_data  *data;
5889
5890
0
  if (c == NULL)
5891
0
    return;
5892
5893
0
  wp = cmd_mouse_pane(m, NULL, NULL);
5894
0
  if (wp == NULL)
5895
0
    return;
5896
0
  wme = TAILQ_FIRST(&wp->modes);
5897
0
  if (wme == NULL)
5898
0
    return;
5899
0
  if (wme->mode != &window_copy_mode && wme->mode != &window_view_mode)
5900
0
    return;
5901
5902
0
  data = wme->data;
5903
0
  evtimer_del(&data->dragtimer);
5904
0
}
5905
5906
static void
5907
window_copy_jump_to_mark(struct window_mode_entry *wme)
5908
0
{
5909
0
  struct window_copy_mode_data  *data = wme->data;
5910
0
  u_int        tmx, tmy;
5911
5912
0
  tmx = data->cx;
5913
0
  tmy = screen_hsize(data->backing) + data->cy - data->oy;
5914
0
  data->cx = data->mx;
5915
0
  if (data->my < screen_hsize(data->backing)) {
5916
0
    data->cy = 0;
5917
0
    data->oy = screen_hsize(data->backing) - data->my;
5918
0
  } else {
5919
0
    data->cy = data->my - screen_hsize(data->backing);
5920
0
    data->oy = 0;
5921
0
  }
5922
0
  data->mx = tmx;
5923
0
  data->my = tmy;
5924
0
  data->showmark = 1;
5925
0
  window_copy_update_selection(wme, 0, 0);
5926
0
  window_copy_redraw_screen(wme);
5927
0
}
5928
5929
/* Scroll up if the cursor went off the visible screen. */
5930
static void
5931
window_copy_acquire_cursor_up(struct window_mode_entry *wme, u_int hsize,
5932
    u_int oy, u_int oldy, u_int px, u_int py)
5933
0
{
5934
0
  u_int cy, yy, ny, nd;
5935
5936
0
  yy = hsize - oy;
5937
0
  if (py < yy) {
5938
0
    ny = yy - py;
5939
0
    cy = 0;
5940
0
    nd = 1;
5941
0
  } else {
5942
0
    ny = 0;
5943
0
    cy = py - yy;
5944
0
    nd = oldy - cy + 1;
5945
0
  }
5946
0
  while (ny > 0) {
5947
0
    window_copy_cursor_up(wme, 1);
5948
0
    ny--;
5949
0
  }
5950
0
  window_copy_update_cursor(wme, px, cy);
5951
0
  if (window_copy_update_selection(wme, 1, 0))
5952
0
    window_copy_redraw_lines(wme, cy, nd);
5953
0
}
5954
5955
/* Scroll down if the cursor went off the visible screen. */
5956
static void
5957
window_copy_acquire_cursor_down(struct window_mode_entry *wme, u_int hsize,
5958
    u_int sy, u_int oy, u_int oldy, u_int px, u_int py, int no_reset)
5959
0
{
5960
0
  u_int cy, yy, ny, nd;
5961
5962
0
  cy = py - hsize + oy;
5963
0
  yy = sy - 1;
5964
0
  if (cy > yy) {
5965
0
    ny = cy - yy;
5966
0
    oldy = yy;
5967
0
    nd = 1;
5968
0
  } else {
5969
0
    ny = 0;
5970
0
    nd = cy - oldy + 1;
5971
0
  }
5972
0
  while (ny > 0) {
5973
0
    window_copy_cursor_down(wme, 1);
5974
0
    ny--;
5975
0
  }
5976
0
  if (cy > yy)
5977
0
    window_copy_update_cursor(wme, px, yy);
5978
0
  else
5979
0
    window_copy_update_cursor(wme, px, cy);
5980
0
  if (window_copy_update_selection(wme, 1, no_reset))
5981
0
    window_copy_redraw_lines(wme, oldy, nd);
5982
0
}