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

status.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/time.h>
21 
22 #include <errno.h>
23 #include <limits.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <unistd.h>
29 
30 #include "tmux.h"
31 
32 static void status_message_callback(int, short, void *);
33 static void status_timer_callback(int, short, void *);
34 
35 static char *status_prompt_find_history_file(void);
36 static const char *status_prompt_up_history(u_int *);
37 static const char *status_prompt_down_history(u_int *);
38 static void status_prompt_add_history(const char *);
39 
40 static char *status_prompt_complete(struct client *, const char *, u_int);
41 static char *status_prompt_complete_window_menu(struct client *,
42  struct session *, const char *, u_int, char);
43 
45  struct client *c;
46  u_int start;
47  u_int size;
48  char **list;
49  char flag;
50 };
51 
52 /* Status prompt history. */
53 #define PROMPT_HISTORY 100
54 static char **status_prompt_hlist;
55 static u_int status_prompt_hsize;
56 
57 /* Find the history file to load/save from/to. */
58 static char *
60 {
61  const char *home, *history_file;
62  char *path;
63 
64  history_file = options_get_string(global_options, "history-file");
65  if (*history_file == '\0')
66  return (NULL);
67  if (*history_file == '/')
68  return (xstrdup(history_file));
69 
70  if (history_file[0] != '~' || history_file[1] != '/')
71  return (NULL);
72  if ((home = find_home()) == NULL)
73  return (NULL);
74  xasprintf(&path, "%s%s", home, history_file + 1);
75  return (path);
76 }
77 
78 /* Load status prompt history from file. */
79 void
81 {
82  FILE *f;
83  char *history_file, *line, *tmp;
84  size_t length;
85 
86  if ((history_file = status_prompt_find_history_file()) == NULL)
87  return;
88  log_debug("loading history from %s", history_file);
89 
90  f = fopen(history_file, "r");
91  if (f == NULL) {
92  log_debug("%s: %s", history_file, strerror(errno));
93  free(history_file);
94  return;
95  }
96  free(history_file);
97 
98  for (;;) {
99  if ((line = fgetln(f, &length)) == NULL)
100  break;
101 
102  if (length > 0) {
103  if (line[length - 1] == '\n') {
104  line[length - 1] = '\0';
106  } else {
107  tmp = xmalloc(length + 1);
108  memcpy(tmp, line, length);
109  tmp[length] = '\0';
111  free(tmp);
112  }
113  }
114  }
115  fclose(f);
116 }
117 
118 /* Save status prompt history to file. */
119 void
121 {
122  FILE *f;
123  u_int i;
124  char *history_file;
125 
126  if ((history_file = status_prompt_find_history_file()) == NULL)
127  return;
128  log_debug("saving history to %s", history_file);
129 
130  f = fopen(history_file, "w");
131  if (f == NULL) {
132  log_debug("%s: %s", history_file, strerror(errno));
133  free(history_file);
134  return;
135  }
136  free(history_file);
137 
138  for (i = 0; i < status_prompt_hsize; i++) {
139  fputs(status_prompt_hlist[i], f);
140  fputc('\n', f);
141  }
142  fclose(f);
143 
144 }
145 
146 /* Status timer callback. */
147 static void
148 status_timer_callback(__unused int fd, __unused short events, void *arg)
149 {
150  struct client *c = arg;
151  struct session *s = c->session;
152  struct timeval tv;
153 
154  evtimer_del(&c->status.timer);
155 
156  if (s == NULL)
157  return;
158 
159  if (c->message_string == NULL && c->prompt_string == NULL)
161 
162  timerclear(&tv);
163  tv.tv_sec = options_get_number(s->options, "status-interval");
164 
165  if (tv.tv_sec != 0)
166  evtimer_add(&c->status.timer, &tv);
167  log_debug("client %p, status interval %d", c, (int)tv.tv_sec);
168 }
169 
170 /* Start status timer for client. */
171 void
173 {
174  struct session *s = c->session;
175 
176  if (event_initialized(&c->status.timer))
177  evtimer_del(&c->status.timer);
178  else
179  evtimer_set(&c->status.timer, status_timer_callback, c);
180 
181  if (s != NULL && options_get_number(s->options, "status"))
182  status_timer_callback(-1, 0, c);
183 }
184 
185 /* Start status timer for all clients. */
186 void
188 {
189  struct client *c;
190 
191  TAILQ_FOREACH(c, &clients, entry)
193 }
194 
195 /* Update status cache. */
196 void
198 {
199  s->statuslines = options_get_number(s->options, "status");
200  if (s->statuslines == 0)
201  s->statusat = -1;
202  else if (options_get_number(s->options, "status-position") == 0)
203  s->statusat = 0;
204  else
205  s->statusat = 1;
206 }
207 
208 /* Get screen line of status line. -1 means off. */
209 int
211 {
212  struct session *s = c->session;
213 
215  return (-1);
216  if (s->statusat != 1)
217  return (s->statusat);
218  return (c->tty.sy - status_line_size(c));
219 }
220 
221 /* Get size of status line for client's session. 0 means off. */
222 u_int
224 {
225  struct session *s = c->session;
226 
228  return (0);
229  if (s == NULL)
230  return (options_get_number(global_s_options, "status"));
231  return (s->statuslines);
232 }
233 
234 /* Get window at window list position. */
235 struct style_range *
236 status_get_range(struct client *c, u_int x, u_int y)
237 {
238  struct status_line *sl = &c->status;
239  struct style_range *sr;
240 
241  if (y >= nitems(sl->entries))
242  return (NULL);
243  TAILQ_FOREACH(sr, &sl->entries[y].ranges, entry) {
244  if (x >= sr->start && x < sr->end)
245  return (sr);
246  }
247  return (NULL);
248 }
249 
250 /* Free all ranges. */
251 static void
252 status_free_ranges(struct style_ranges *srs)
253 {
254  struct style_range *sr, *sr1;
255 
256  TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) {
257  TAILQ_REMOVE(srs, sr, entry);
258  free(sr);
259  }
260 }
261 
262 /* Save old status line. */
263 static void
265 {
266  struct status_line *sl = &c->status;
267 
268  if (sl->active == &sl->screen) {
269  sl->active = xmalloc(sizeof *sl->active);
270  screen_init(sl->active, c->tty.sx, status_line_size(c), 0);
271  }
272  sl->references++;
273 }
274 
275 /* Restore old status line. */
276 static void
278 {
279  struct status_line *sl = &c->status;
280 
281  if (--sl->references == 0) {
282  screen_free(sl->active);
283  free(sl->active);
284  sl->active = &sl->screen;
285  }
286 }
287 
288 /* Initialize status line. */
289 void
290 status_init(struct client *c)
291 {
292  struct status_line *sl = &c->status;
293  u_int i;
294 
295  for (i = 0; i < nitems(sl->entries); i++)
296  TAILQ_INIT(&sl->entries[i].ranges);
297 
298  screen_init(&sl->screen, c->tty.sx, 1, 0);
299  sl->active = &sl->screen;
300 }
301 
302 /* Free status line. */
303 void
304 status_free(struct client *c)
305 {
306  struct status_line *sl = &c->status;
307  u_int i;
308 
309  for (i = 0; i < nitems(sl->entries); i++) {
311  free((void *)sl->entries[i].expanded);
312  }
313 
314  if (event_initialized(&sl->timer))
315  evtimer_del(&sl->timer);
316 
317  if (sl->active != &sl->screen) {
318  screen_free(sl->active);
319  free(sl->active);
320  }
321  screen_free(&sl->screen);
322 }
323 
324 /* Draw status line for client. */
325 int
327 {
328  struct status_line *sl = &c->status;
329  struct status_line_entry *sle;
330  struct session *s = c->session;
331  struct screen_write_ctx ctx;
332  struct grid_cell gc;
333  u_int lines, i, n, width = c->tty.sx;
334  int flags, force = 0, changed = 0, fg, bg;
335  struct options_entry *o;
336  union options_value *ov;
337  struct format_tree *ft;
338  char *expanded;
339 
340  log_debug("%s enter", __func__);
341 
342  /* Shouldn't get here if not the active screen. */
343  if (sl->active != &sl->screen)
344  fatalx("not the active screen");
345 
346  /* No status line? */
347  lines = status_line_size(c);
348  if (c->tty.sy == 0 || lines == 0)
349  return (1);
350 
351  /* Create format tree. */
353  if (c->flags & CLIENT_STATUSFORCE)
354  flags |= FORMAT_FORCE;
355  ft = format_create(c, NULL, FORMAT_NONE, flags);
356  format_defaults(ft, c, NULL, NULL, NULL);
357 
358  /* Set up default colour. */
359  style_apply(&gc, s->options, "status-style", ft);
360  fg = options_get_number(s->options, "status-fg");
361  if (fg != 8)
362  gc.fg = fg;
363  bg = options_get_number(s->options, "status-bg");
364  if (bg != 8)
365  gc.bg = bg;
366  if (!grid_cells_equal(&gc, &sl->style)) {
367  force = 1;
368  memcpy(&sl->style, &gc, sizeof sl->style);
369  }
370 
371  /* Resize the target screen. */
372  if (screen_size_x(&sl->screen) != width ||
373  screen_size_y(&sl->screen) != lines) {
374  screen_resize(&sl->screen, width, lines, 0);
375  changed = force = 1;
376  }
377  screen_write_start(&ctx, &sl->screen);
378 
379  /* Write the status lines. */
380  o = options_get(s->options, "status-format");
381  if (o == NULL) {
382  for (n = 0; n < width * lines; n++)
383  screen_write_putc(&ctx, &gc, ' ');
384  } else {
385  for (i = 0; i < lines; i++) {
386  screen_write_cursormove(&ctx, 0, i, 0);
387 
388  ov = options_array_get(o, i);
389  if (ov == NULL) {
390  for (n = 0; n < width; n++)
391  screen_write_putc(&ctx, &gc, ' ');
392  continue;
393  }
394  sle = &sl->entries[i];
395 
396  expanded = format_expand_time(ft, ov->string);
397  if (!force &&
398  sle->expanded != NULL &&
399  strcmp(expanded, sle->expanded) == 0) {
400  free(expanded);
401  continue;
402  }
403  changed = 1;
404 
405  for (n = 0; n < width; n++)
406  screen_write_putc(&ctx, &gc, ' ');
407  screen_write_cursormove(&ctx, 0, i, 0);
408 
409  status_free_ranges(&sle->ranges);
410  format_draw(&ctx, &gc, width, expanded, &sle->ranges);
411 
412  free(sle->expanded);
413  sle->expanded = expanded;
414  }
415  }
416  screen_write_stop(&ctx);
417 
418  /* Free the format tree. */
419  format_free(ft);
420 
421  /* Return if the status line has changed. */
422  log_debug("%s exit: force=%d, changed=%d", __func__, force, changed);
423  return (force || changed);
424 }
425 
426 /* Set a status line message. */
427 void
428 status_message_set(struct client *c, int delay, int ignore_styles,
429  int ignore_keys, const char *fmt, ...)
430 {
431  struct timeval tv;
432  va_list ap;
433 
436 
437  va_start(ap, fmt);
438  xvasprintf(&c->message_string, fmt, ap);
439  va_end(ap);
440 
441  server_add_message("%s message: %s", c->name, c->message_string);
442 
443  /*
444  * With delay -1, the display-time option is used; zero means wait for
445  * key press; more than zero is the actual delay time in milliseconds.
446  */
447  if (delay == -1)
448  delay = options_get_number(c->session->options, "display-time");
449  if (delay > 0) {
450  tv.tv_sec = delay / 1000;
451  tv.tv_usec = (delay % 1000) * 1000L;
452 
453  if (event_initialized(&c->message_timer))
454  evtimer_del(&c->message_timer);
455  evtimer_set(&c->message_timer, status_message_callback, c);
456 
457  evtimer_add(&c->message_timer, &tv);
458  }
459 
460  if (delay != 0)
461  c->message_ignore_keys = ignore_keys;
462  c->message_ignore_styles = ignore_styles;
463 
466 }
467 
468 /* Clear status line message. */
469 void
471 {
472  if (c->message_string == NULL)
473  return;
474 
475  free(c->message_string);
476  c->message_string = NULL;
477 
478  if (c->prompt_string == NULL)
479  c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
480  c->flags |= CLIENT_ALLREDRAWFLAGS; /* was frozen and may have changed */
481 
483 }
484 
485 /* Clear status line message after timer expires. */
486 static void
487 status_message_callback(__unused int fd, __unused short event, void *data)
488 {
489  struct client *c = data;
490 
492 }
493 
494 /* Draw client message on status line of present else on last line. */
495 int
497 {
498  struct status_line *sl = &c->status;
499  struct screen_write_ctx ctx;
500  struct session *s = c->session;
501  struct screen old_screen;
502  size_t len;
503  u_int lines, offset;
504  struct grid_cell gc;
505  struct format_tree *ft;
506 
507  if (c->tty.sx == 0 || c->tty.sy == 0)
508  return (0);
509  memcpy(&old_screen, sl->active, sizeof old_screen);
510 
511  lines = status_line_size(c);
512  if (lines <= 1)
513  lines = 1;
514  screen_init(sl->active, c->tty.sx, lines, 0);
515 
516  len = screen_write_strlen("%s", c->message_string);
517  if (len > c->tty.sx)
518  len = c->tty.sx;
519 
520  ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
521  style_apply(&gc, s->options, "message-style", ft);
522  format_free(ft);
523 
524  screen_write_start(&ctx, sl->active);
525  screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1);
526  screen_write_cursormove(&ctx, 0, lines - 1, 0);
527  for (offset = 0; offset < c->tty.sx; offset++)
528  screen_write_putc(&ctx, &gc, ' ');
529  screen_write_cursormove(&ctx, 0, lines - 1, 0);
531  screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
532  else
533  format_draw(&ctx, &gc, c->tty.sx, c->message_string, NULL);
534  screen_write_stop(&ctx);
535 
536  if (grid_compare(sl->active->grid, old_screen.grid) == 0) {
537  screen_free(&old_screen);
538  return (0);
539  }
540  screen_free(&old_screen);
541  return (1);
542 }
543 
544 /* Enable status line prompt. */
545 void
547  const char *msg, const char *input, prompt_input_cb inputcb,
548  prompt_free_cb freecb, void *data, int flags)
549 {
550  struct format_tree *ft;
551  char *tmp;
552 
553  if (fs != NULL)
554  ft = format_create_from_state(NULL, c, fs);
555  else
556  ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
557 
558  if (input == NULL)
559  input = "";
560  if (flags & PROMPT_NOFORMAT)
561  tmp = xstrdup(input);
562  else
563  tmp = format_expand_time(ft, input);
564 
568 
569  c->prompt_string = format_expand_time(ft, msg);
570 
571  if (flags & PROMPT_INCREMENTAL) {
572  c->prompt_last = xstrdup(tmp);
574  } else {
575  c->prompt_last = NULL;
576  c->prompt_buffer = utf8_fromcstr(tmp);
577  }
579 
580  c->prompt_inputcb = inputcb;
581  c->prompt_freecb = freecb;
582  c->prompt_data = data;
583 
584  c->prompt_hindex = 0;
585 
586  c->prompt_flags = flags;
587  c->prompt_mode = PROMPT_ENTRY;
588 
589  if (~flags & PROMPT_INCREMENTAL)
592 
594  c->prompt_inputcb(c, c->prompt_data, "=", 0);
595 
596  free(tmp);
597  format_free(ft);
598 }
599 
600 /* Remove status line prompt. */
601 void
603 {
604  if (c->prompt_string == NULL)
605  return;
606 
607  if (c->prompt_freecb != NULL && c->prompt_data != NULL)
609 
610  free(c->prompt_last);
611  c->prompt_last = NULL;
612 
613  free(c->prompt_string);
614  c->prompt_string = NULL;
615 
616  free(c->prompt_buffer);
617  c->prompt_buffer = NULL;
618 
619  free(c->prompt_saved);
620  c->prompt_saved = NULL;
621 
623  c->flags |= CLIENT_ALLREDRAWFLAGS; /* was frozen and may have changed */
624 
626 }
627 
628 /* Update status line prompt with a new prompt string. */
629 void
630 status_prompt_update(struct client *c, const char *msg, const char *input)
631 {
632  struct format_tree *ft;
633  char *tmp;
634 
635  ft = format_create(c, NULL, FORMAT_NONE, 0);
636  format_defaults(ft, c, NULL, NULL, NULL);
637 
638  tmp = format_expand_time(ft, input);
639 
640  free(c->prompt_string);
641  c->prompt_string = format_expand_time(ft, msg);
642 
643  free(c->prompt_buffer);
644  c->prompt_buffer = utf8_fromcstr(tmp);
646 
647  c->prompt_hindex = 0;
648 
650 
651  free(tmp);
652  format_free(ft);
653 }
654 
655 /* Draw client prompt on status line of present else on last line. */
656 int
658 {
659  struct status_line *sl = &c->status;
660  struct screen_write_ctx ctx;
661  struct session *s = c->session;
662  struct screen old_screen;
663  u_int i, lines, offset, left, start, width;
664  u_int pcursor, pwidth;
665  struct grid_cell gc, cursorgc;
666  struct format_tree *ft;
667 
668  if (c->tty.sx == 0 || c->tty.sy == 0)
669  return (0);
670  memcpy(&old_screen, sl->active, sizeof old_screen);
671 
672  lines = status_line_size(c);
673  if (lines <= 1)
674  lines = 1;
675  screen_init(sl->active, c->tty.sx, lines, 0);
676 
677  ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
678  if (c->prompt_mode == PROMPT_COMMAND)
679  style_apply(&gc, s->options, "message-command-style", ft);
680  else
681  style_apply(&gc, s->options, "message-style", ft);
682  format_free(ft);
683 
684  memcpy(&cursorgc, &gc, sizeof cursorgc);
685  cursorgc.attr ^= GRID_ATTR_REVERSE;
686 
687  start = screen_write_strlen("%s", c->prompt_string);
688  if (start > c->tty.sx)
689  start = c->tty.sx;
690 
691  screen_write_start(&ctx, sl->active);
692  screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1);
693  screen_write_cursormove(&ctx, 0, lines - 1, 0);
694  for (offset = 0; offset < c->tty.sx; offset++)
695  screen_write_putc(&ctx, &gc, ' ');
696  screen_write_cursormove(&ctx, 0, lines - 1, 0);
697  screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string);
698  screen_write_cursormove(&ctx, start, lines - 1, 0);
699 
700  left = c->tty.sx - start;
701  if (left == 0)
702  goto finished;
703 
705  pwidth = utf8_strwidth(c->prompt_buffer, -1);
706  if (pcursor >= left) {
707  /*
708  * The cursor would be outside the screen so start drawing
709  * with it on the right.
710  */
711  offset = (pcursor - left) + 1;
712  pwidth = left;
713  } else
714  offset = 0;
715  if (pwidth > left)
716  pwidth = left;
717 
718  width = 0;
719  for (i = 0; c->prompt_buffer[i].size != 0; i++) {
720  if (width < offset) {
721  width += c->prompt_buffer[i].width;
722  continue;
723  }
724  if (width >= offset + pwidth)
725  break;
726  width += c->prompt_buffer[i].width;
727  if (width > offset + pwidth)
728  break;
729 
730  if (i != c->prompt_index) {
731  utf8_copy(&gc.data, &c->prompt_buffer[i]);
732  screen_write_cell(&ctx, &gc);
733  } else {
734  utf8_copy(&cursorgc.data, &c->prompt_buffer[i]);
735  screen_write_cell(&ctx, &cursorgc);
736  }
737  }
738  if (sl->active->cx < screen_size_x(sl->active) && c->prompt_index >= i)
739  screen_write_putc(&ctx, &cursorgc, ' ');
740 
741 finished:
742  screen_write_stop(&ctx);
743 
744  if (grid_compare(sl->active->grid, old_screen.grid) == 0) {
745  screen_free(&old_screen);
746  return (0);
747  }
748  screen_free(&old_screen);
749  return (1);
750 }
751 
752 /* Is this a separator? */
753 static int
754 status_prompt_in_list(const char *ws, const struct utf8_data *ud)
755 {
756  if (ud->size != 1 || ud->width != 1)
757  return (0);
758  return (strchr(ws, *ud->data) != NULL);
759 }
760 
761 /* Is this a space? */
762 static int
764 {
765  if (ud->size != 1 || ud->width != 1)
766  return (0);
767  return (*ud->data == ' ');
768 }
769 
770 /*
771  * Translate key from emacs to vi. Return 0 to drop key, 1 to process the key
772  * as an emacs key; return 2 to append to the buffer.
773  */
774 static int
776 {
777  if (c->prompt_mode == PROMPT_ENTRY) {
778  switch (key) {
779  case '\003': /* C-c */
780  case '\007': /* C-g */
781  case '\010': /* C-h */
782  case '\011': /* Tab */
783  case '\025': /* C-u */
784  case '\027': /* C-w */
785  case '\n':
786  case '\r':
787  case KEYC_BSPACE:
788  case KEYC_DC:
789  case KEYC_DOWN:
790  case KEYC_END:
791  case KEYC_HOME:
792  case KEYC_LEFT:
793  case KEYC_RIGHT:
794  case KEYC_UP:
795  *new_key = key;
796  return (1);
797  case '\033': /* Escape */
798  c->prompt_mode = PROMPT_COMMAND;
800  return (0);
801  }
802  *new_key = key;
803  return (2);
804  }
805 
806  switch (key) {
807  case 'A':
808  case 'I':
809  case 'C':
810  case 's':
811  case 'a':
812  c->prompt_mode = PROMPT_ENTRY;
814  break; /* switch mode and... */
815  case 'S':
816  c->prompt_mode = PROMPT_ENTRY;
818  *new_key = '\025'; /* C-u */
819  return (1);
820  case 'i':
821  case '\033': /* Escape */
822  c->prompt_mode = PROMPT_ENTRY;
824  return (0);
825  }
826 
827  switch (key) {
828  case 'A':
829  case '$':
830  *new_key = KEYC_END;
831  return (1);
832  case 'I':
833  case '0':
834  case '^':
835  *new_key = KEYC_HOME;
836  return (1);
837  case 'C':
838  case 'D':
839  *new_key = '\013'; /* C-k */
840  return (1);
841  case KEYC_BSPACE:
842  case 'X':
843  *new_key = KEYC_BSPACE;
844  return (1);
845  case 'b':
846  case 'B':
847  *new_key = 'b'|KEYC_META;
848  return (1);
849  case 'd':
850  *new_key = '\025';
851  return (1);
852  case 'e':
853  case 'E':
854  case 'w':
855  case 'W':
856  *new_key = 'f'|KEYC_META;
857  return (1);
858  case 'p':
859  *new_key = '\031'; /* C-y */
860  return (1);
861  case 'q':
862  *new_key = '\003'; /* C-c */
863  return (1);
864  case 's':
865  case KEYC_DC:
866  case 'x':
867  *new_key = KEYC_DC;
868  return (1);
869  case KEYC_DOWN:
870  case 'j':
871  *new_key = KEYC_DOWN;
872  return (1);
873  case KEYC_LEFT:
874  case 'h':
875  *new_key = KEYC_LEFT;
876  return (1);
877  case 'a':
878  case KEYC_RIGHT:
879  case 'l':
880  *new_key = KEYC_RIGHT;
881  return (1);
882  case KEYC_UP:
883  case 'k':
884  *new_key = KEYC_UP;
885  return (1);
886  case '\010' /* C-h */:
887  case '\003' /* C-c */:
888  case '\n':
889  case '\r':
890  return (1);
891  }
892  return (0);
893 }
894 
895 /* Paste into prompt. */
896 static int
898 {
899  struct paste_buffer *pb;
900  const char *bufdata;
901  size_t size, n, bufsize;
902  u_int i;
903  struct utf8_data *ud, *udp;
904  enum utf8_state more;
905 
907  if (c->prompt_saved != NULL) {
908  ud = c->prompt_saved;
909  n = utf8_strlen(c->prompt_saved);
910  } else {
911  if ((pb = paste_get_top(NULL)) == NULL)
912  return (0);
913  bufdata = paste_buffer_data(pb, &bufsize);
914  ud = xreallocarray(NULL, bufsize + 1, sizeof *ud);
915  udp = ud;
916  for (i = 0; i != bufsize; /* nothing */) {
917  more = utf8_open(udp, bufdata[i]);
918  if (more == UTF8_MORE) {
919  while (++i != bufsize && more == UTF8_MORE)
920  more = utf8_append(udp, bufdata[i]);
921  if (more == UTF8_DONE) {
922  udp++;
923  continue;
924  }
925  i -= udp->have;
926  }
927  if (bufdata[i] <= 31 || bufdata[i] >= 127)
928  break;
929  utf8_set(udp, bufdata[i]);
930  udp++;
931  i++;
932  }
933  udp->size = 0;
934  n = udp - ud;
935  }
936  if (n == 0)
937  return (0);
938 
940  sizeof *c->prompt_buffer);
941  if (c->prompt_index == size) {
942  memcpy(c->prompt_buffer + c->prompt_index, ud,
943  n * sizeof *c->prompt_buffer);
944  c->prompt_index += n;
945  c->prompt_buffer[c->prompt_index].size = 0;
946  } else {
947  memmove(c->prompt_buffer + c->prompt_index + n,
948  c->prompt_buffer + c->prompt_index,
949  (size + 1 - c->prompt_index) * sizeof *c->prompt_buffer);
950  memcpy(c->prompt_buffer + c->prompt_index, ud,
951  n * sizeof *c->prompt_buffer);
952  c->prompt_index += n;
953  }
954 
955  if (ud != c->prompt_saved)
956  free(ud);
957  return (1);
958 }
959 
960 /* Finish completion. */
961 static int
962 status_prompt_replace_complete(struct client *c, const char *s)
963 {
964  char word[64], *allocated = NULL;
965  size_t size, n, off, idx, used;
966  struct utf8_data *first, *last, *ud;
967 
968  /* Work out where the cursor currently is. */
969  idx = c->prompt_index;
970  if (idx != 0)
971  idx--;
973 
974  /* Find the word we are in. */
975  first = &c->prompt_buffer[idx];
976  while (first > c->prompt_buffer && !status_prompt_space(first))
977  first--;
978  while (first->size != 0 && status_prompt_space(first))
979  first++;
980  last = &c->prompt_buffer[idx];
981  while (last->size != 0 && !status_prompt_space(last))
982  last++;
983  while (last > c->prompt_buffer && status_prompt_space(last))
984  last--;
985  if (last->size != 0)
986  last++;
987  if (last < first)
988  return (0);
989  if (s == NULL) {
990  used = 0;
991  for (ud = first; ud < last; ud++) {
992  if (used + ud->size >= sizeof word)
993  break;
994  memcpy(word + used, ud->data, ud->size);
995  used += ud->size;
996  }
997  if (ud != last)
998  return (0);
999  word[used] = '\0';
1000  }
1001 
1002  /* Try to complete it. */
1003  if (s == NULL) {
1004  allocated = status_prompt_complete(c, word,
1005  first - c->prompt_buffer);
1006  if (allocated == NULL)
1007  return (0);
1008  s = allocated;
1009  }
1010 
1011  /* Trim out word. */
1012  n = size - (last - c->prompt_buffer) + 1; /* with \0 */
1013  memmove(first, last, n * sizeof *c->prompt_buffer);
1014  size -= last - first;
1015 
1016  /* Insert the new word. */
1017  size += strlen(s);
1018  off = first - c->prompt_buffer;
1020  sizeof *c->prompt_buffer);
1021  first = c->prompt_buffer + off;
1022  memmove(first + strlen(s), first, n * sizeof *c->prompt_buffer);
1023  for (idx = 0; idx < strlen(s); idx++)
1024  utf8_set(&first[idx], s[idx]);
1025  c->prompt_index = (first - c->prompt_buffer) + strlen(s);
1026 
1027  free(allocated);
1028  return (1);
1029 }
1030 
1031 /* Handle keys in prompt. */
1032 int
1034 {
1035  struct options *oo = c->session->options;
1036  char *s, *cp, prefix = '=';
1037  const char *histstr, *ws = NULL, *keystring;
1038  size_t size, idx;
1039  struct utf8_data tmp;
1040  int keys;
1041 
1042  if (c->prompt_flags & PROMPT_KEY) {
1043  keystring = key_string_lookup_key(key, 0);
1044  c->prompt_inputcb(c, c->prompt_data, keystring, 1);
1046  return (0);
1047  }
1049 
1050  if (c->prompt_flags & PROMPT_NUMERIC) {
1051  if (key >= '0' && key <= '9')
1052  goto append_key;
1053  s = utf8_tocstr(c->prompt_buffer);
1054  c->prompt_inputcb(c, c->prompt_data, s, 1);
1056  free(s);
1057  return (1);
1058  }
1059  key &= ~~KEYC_MASK_FLAGS;
1060 
1061  keys = options_get_number(c->session->options, "status-keys");
1062  if (keys == MODEKEY_VI) {
1063  switch (status_prompt_translate_key(c, key, &key)) {
1064  case 1:
1065  goto process_key;
1066  case 2:
1067  goto append_key;
1068  default:
1069  return (0);
1070  }
1071  }
1072 
1073 process_key:
1074  switch (key) {
1075  case KEYC_LEFT:
1076  case '\002': /* C-b */
1077  if (c->prompt_index > 0) {
1078  c->prompt_index--;
1079  break;
1080  }
1081  break;
1082  case KEYC_RIGHT:
1083  case '\006': /* C-f */
1084  if (c->prompt_index < size) {
1085  c->prompt_index++;
1086  break;
1087  }
1088  break;
1089  case KEYC_HOME:
1090  case '\001': /* C-a */
1091  if (c->prompt_index != 0) {
1092  c->prompt_index = 0;
1093  break;
1094  }
1095  break;
1096  case KEYC_END:
1097  case '\005': /* C-e */
1098  if (c->prompt_index != size) {
1099  c->prompt_index = size;
1100  break;
1101  }
1102  break;
1103  case '\011': /* Tab */
1104  if (status_prompt_replace_complete(c, NULL))
1105  goto changed;
1106  break;
1107  case KEYC_BSPACE:
1108  case '\010': /* C-h */
1109  if (c->prompt_index != 0) {
1110  if (c->prompt_index == size)
1111  c->prompt_buffer[--c->prompt_index].size = 0;
1112  else {
1113  memmove(c->prompt_buffer + c->prompt_index - 1,
1114  c->prompt_buffer + c->prompt_index,
1115  (size + 1 - c->prompt_index) *
1116  sizeof *c->prompt_buffer);
1117  c->prompt_index--;
1118  }
1119  goto changed;
1120  }
1121  break;
1122  case KEYC_DC:
1123  case '\004': /* C-d */
1124  if (c->prompt_index != size) {
1125  memmove(c->prompt_buffer + c->prompt_index,
1126  c->prompt_buffer + c->prompt_index + 1,
1127  (size + 1 - c->prompt_index) *
1128  sizeof *c->prompt_buffer);
1129  goto changed;
1130  }
1131  break;
1132  case '\025': /* C-u */
1133  c->prompt_buffer[0].size = 0;
1134  c->prompt_index = 0;
1135  goto changed;
1136  case '\013': /* C-k */
1137  if (c->prompt_index < size) {
1138  c->prompt_buffer[c->prompt_index].size = 0;
1139  goto changed;
1140  }
1141  break;
1142  case '\027': /* C-w */
1143  ws = options_get_string(oo, "word-separators");
1144  idx = c->prompt_index;
1145 
1146  /* Find a non-separator. */
1147  while (idx != 0) {
1148  idx--;
1149  if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
1150  break;
1151  }
1152 
1153  /* Find the separator at the beginning of the word. */
1154  while (idx != 0) {
1155  idx--;
1156  if (status_prompt_in_list(ws, &c->prompt_buffer[idx])) {
1157  /* Go back to the word. */
1158  idx++;
1159  break;
1160  }
1161  }
1162 
1163  free(c->prompt_saved);
1164  c->prompt_saved = xcalloc(sizeof *c->prompt_buffer,
1165  (c->prompt_index - idx) + 1);
1166  memcpy(c->prompt_saved, c->prompt_buffer + idx,
1167  (c->prompt_index - idx) * sizeof *c->prompt_buffer);
1168 
1169  memmove(c->prompt_buffer + idx,
1170  c->prompt_buffer + c->prompt_index,
1171  (size + 1 - c->prompt_index) *
1172  sizeof *c->prompt_buffer);
1173  memset(c->prompt_buffer + size - (c->prompt_index - idx),
1174  '\0', (c->prompt_index - idx) * sizeof *c->prompt_buffer);
1175  c->prompt_index = idx;
1176 
1177  goto changed;
1178  case 'f'|KEYC_META:
1179  case KEYC_RIGHT|KEYC_CTRL:
1180  ws = options_get_string(oo, "word-separators");
1181 
1182  /* Find a word. */
1183  while (c->prompt_index != size) {
1184  idx = ++c->prompt_index;
1185  if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
1186  break;
1187  }
1188 
1189  /* Find the separator at the end of the word. */
1190  while (c->prompt_index != size) {
1191  idx = ++c->prompt_index;
1192  if (status_prompt_in_list(ws, &c->prompt_buffer[idx]))
1193  break;
1194  }
1195 
1196  /* Back up to the end-of-word like vi. */
1197  if (options_get_number(oo, "status-keys") == MODEKEY_VI &&
1198  c->prompt_index != 0)
1199  c->prompt_index--;
1200 
1201  goto changed;
1202  case 'b'|KEYC_META:
1203  case KEYC_LEFT|KEYC_CTRL:
1204  ws = options_get_string(oo, "word-separators");
1205 
1206  /* Find a non-separator. */
1207  while (c->prompt_index != 0) {
1208  idx = --c->prompt_index;
1209  if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
1210  break;
1211  }
1212 
1213  /* Find the separator at the beginning of the word. */
1214  while (c->prompt_index != 0) {
1215  idx = --c->prompt_index;
1216  if (status_prompt_in_list(ws, &c->prompt_buffer[idx])) {
1217  /* Go back to the word. */
1218  c->prompt_index++;
1219  break;
1220  }
1221  }
1222  goto changed;
1223  case KEYC_UP:
1224  case '\020': /* C-p */
1225  histstr = status_prompt_up_history(&c->prompt_hindex);
1226  if (histstr == NULL)
1227  break;
1228  free(c->prompt_buffer);
1229  c->prompt_buffer = utf8_fromcstr(histstr);
1231  goto changed;
1232  case KEYC_DOWN:
1233  case '\016': /* C-n */
1235  if (histstr == NULL)
1236  break;
1237  free(c->prompt_buffer);
1238  c->prompt_buffer = utf8_fromcstr(histstr);
1240  goto changed;
1241  case '\031': /* C-y */
1242  if (status_prompt_paste(c))
1243  goto changed;
1244  break;
1245  case '\024': /* C-t */
1246  idx = c->prompt_index;
1247  if (idx < size)
1248  idx++;
1249  if (idx >= 2) {
1250  utf8_copy(&tmp, &c->prompt_buffer[idx - 2]);
1251  utf8_copy(&c->prompt_buffer[idx - 2],
1252  &c->prompt_buffer[idx - 1]);
1253  utf8_copy(&c->prompt_buffer[idx - 1], &tmp);
1254  c->prompt_index = idx;
1255  goto changed;
1256  }
1257  break;
1258  case '\r':
1259  case '\n':
1260  s = utf8_tocstr(c->prompt_buffer);
1261  if (*s != '\0')
1263  if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0)
1265  free(s);
1266  break;
1267  case '\033': /* Escape */
1268  case '\003': /* C-c */
1269  case '\007': /* C-g */
1270  if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0)
1272  break;
1273  case '\022': /* C-r */
1274  if (~c->prompt_flags & PROMPT_INCREMENTAL)
1275  break;
1276  if (c->prompt_buffer[0].size == 0) {
1277  prefix = '=';
1278  free (c->prompt_buffer);
1281  } else
1282  prefix = '-';
1283  goto changed;
1284  case '\023': /* C-s */
1285  if (~c->prompt_flags & PROMPT_INCREMENTAL)
1286  break;
1287  if (c->prompt_buffer[0].size == 0) {
1288  prefix = '=';
1289  free (c->prompt_buffer);
1292  } else
1293  prefix = '+';
1294  goto changed;
1295  default:
1296  goto append_key;
1297  }
1298 
1299  c->flags |= CLIENT_REDRAWSTATUS;
1300  return (0);
1301 
1302 append_key:
1303  if (key <= 0x1f || (key >= KEYC_BASE && key < KEYC_BASE_END))
1304  return (0);
1305  if (key <= 0x7f)
1306  utf8_set(&tmp, key);
1307  else
1308  utf8_to_data(key, &tmp);
1309 
1311  sizeof *c->prompt_buffer);
1312 
1313  if (c->prompt_index == size) {
1314  utf8_copy(&c->prompt_buffer[c->prompt_index], &tmp);
1315  c->prompt_index++;
1316  c->prompt_buffer[c->prompt_index].size = 0;
1317  } else {
1318  memmove(c->prompt_buffer + c->prompt_index + 1,
1319  c->prompt_buffer + c->prompt_index,
1320  (size + 1 - c->prompt_index) *
1321  sizeof *c->prompt_buffer);
1322  utf8_copy(&c->prompt_buffer[c->prompt_index], &tmp);
1323  c->prompt_index++;
1324  }
1325 
1326  if (c->prompt_flags & PROMPT_SINGLE) {
1327  if (utf8_strlen(c->prompt_buffer) != 1)
1329  else {
1330  s = utf8_tocstr(c->prompt_buffer);
1331  if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0)
1333  free(s);
1334  }
1335  }
1336 
1337 changed:
1338  c->flags |= CLIENT_REDRAWSTATUS;
1339  if (c->prompt_flags & PROMPT_INCREMENTAL) {
1340  s = utf8_tocstr(c->prompt_buffer);
1341  xasprintf(&cp, "%c%s", prefix, s);
1342  c->prompt_inputcb(c, c->prompt_data, cp, 0);
1343  free(cp);
1344  free(s);
1345  }
1346  return (0);
1347 }
1348 
1349 /* Get previous line from the history. */
1350 static const char *
1352 {
1353  /*
1354  * History runs from 0 to size - 1. Index is from 0 to size. Zero is
1355  * empty.
1356  */
1357 
1358  if (status_prompt_hsize == 0 || *idx == status_prompt_hsize)
1359  return (NULL);
1360  (*idx)++;
1361  return (status_prompt_hlist[status_prompt_hsize - *idx]);
1362 }
1363 
1364 /* Get next line from the history. */
1365 static const char *
1367 {
1368  if (status_prompt_hsize == 0 || *idx == 0)
1369  return ("");
1370  (*idx)--;
1371  if (*idx == 0)
1372  return ("");
1373  return (status_prompt_hlist[status_prompt_hsize - *idx]);
1374 }
1375 
1376 /* Add line to the history. */
1377 static void
1378 status_prompt_add_history(const char *line)
1379 {
1380  size_t size;
1381 
1382  if (status_prompt_hsize > 0 &&
1383  strcmp(status_prompt_hlist[status_prompt_hsize - 1], line) == 0)
1384  return;
1385 
1387  free(status_prompt_hlist[0]);
1388 
1389  size = (PROMPT_HISTORY - 1) * sizeof *status_prompt_hlist;
1390  memmove(&status_prompt_hlist[0], &status_prompt_hlist[1], size);
1391 
1393  return;
1394  }
1395 
1399 }
1400 
1401 /* Build completion list. */
1402 static char **
1403 status_prompt_complete_list(u_int *size, const char *s, int at_start)
1404 {
1405  char **list = NULL;
1406  const char **layout, *value, *cp;
1407  const struct cmd_entry **cmdent;
1408  const struct options_table_entry *oe;
1409  size_t slen = strlen(s), valuelen;
1410  struct options_entry *o;
1411  struct options_array_item *a;
1412  const char *layouts[] = {
1413  "even-horizontal", "even-vertical", "main-horizontal",
1414  "main-vertical", "tiled", NULL
1415  };
1416 
1417  *size = 0;
1418  for (cmdent = cmd_table; *cmdent != NULL; cmdent++) {
1419  if (strncmp((*cmdent)->name, s, slen) == 0) {
1420  list = xreallocarray(list, (*size) + 1, sizeof *list);
1421  list[(*size)++] = xstrdup((*cmdent)->name);
1422  }
1423  if ((*cmdent)->alias != NULL &&
1424  strncmp((*cmdent)->alias, s, slen) == 0) {
1425  list = xreallocarray(list, (*size) + 1, sizeof *list);
1426  list[(*size)++] = xstrdup((*cmdent)->alias);
1427  }
1428  }
1429  o = options_get_only(global_options, "command-alias");
1430  if (o != NULL) {
1431  a = options_array_first(o);
1432  while (a != NULL) {
1434  if ((cp = strchr(value, '=')) == NULL)
1435  goto next;
1436  valuelen = cp - value;
1437  if (slen > valuelen || strncmp(value, s, slen) != 0)
1438  goto next;
1439 
1440  list = xreallocarray(list, (*size) + 1, sizeof *list);
1441  list[(*size)++] = xstrndup(value, valuelen);
1442 
1443  next:
1444  a = options_array_next(a);
1445  }
1446  }
1447  if (at_start)
1448  return (list);
1449 
1450  for (oe = options_table; oe->name != NULL; oe++) {
1451  if (strncmp(oe->name, s, slen) == 0) {
1452  list = xreallocarray(list, (*size) + 1, sizeof *list);
1453  list[(*size)++] = xstrdup(oe->name);
1454  }
1455  }
1456  for (layout = layouts; *layout != NULL; layout++) {
1457  if (strncmp(*layout, s, slen) == 0) {
1458  list = xreallocarray(list, (*size) + 1, sizeof *list);
1459  list[(*size)++] = xstrdup(*layout);
1460  }
1461  }
1462  return (list);
1463 }
1464 
1465 /* Find longest prefix. */
1466 static char *
1467 status_prompt_complete_prefix(char **list, u_int size)
1468 {
1469  char *out;
1470  u_int i;
1471  size_t j;
1472 
1473  if (list == NULL || size == 0)
1474  return (NULL);
1475  out = xstrdup(list[0]);
1476  for (i = 1; i < size; i++) {
1477  j = strlen(list[i]);
1478  if (j > strlen(out))
1479  j = strlen(out);
1480  for (; j > 0; j--) {
1481  if (out[j - 1] != list[i][j - 1])
1482  out[j - 1] = '\0';
1483  }
1484  }
1485  return (out);
1486 }
1487 
1488 /* Complete word menu callback. */
1489 static void
1491  void *data)
1492 {
1493  struct status_prompt_menu *spm = data;
1494  struct client *c = spm->c;
1495  u_int i;
1496  char *s;
1497 
1498  if (key != KEYC_NONE) {
1499  idx += spm->start;
1500  if (spm->flag == '\0')
1501  s = xstrdup(spm->list[idx]);
1502  else
1503  xasprintf(&s, "-%c%s", spm->flag, spm->list[idx]);
1504  if (c->prompt_flags & PROMPT_WINDOW) {
1505  free(c->prompt_buffer);
1506  c->prompt_buffer = utf8_fromcstr(s);
1508  c->flags |= CLIENT_REDRAWSTATUS;
1509  } else if (status_prompt_replace_complete(c, s))
1510  c->flags |= CLIENT_REDRAWSTATUS;
1511  free(s);
1512  }
1513 
1514  for (i = 0; i < spm->size; i++)
1515  free(spm->list[i]);
1516  free(spm->list);
1517 }
1518 
1519 /* Show complete word menu. */
1520 static int
1521 status_prompt_complete_list_menu(struct client *c, char **list, u_int size,
1522  u_int offset, char flag)
1523 {
1524  struct menu *menu;
1525  struct menu_item item;
1526  struct status_prompt_menu *spm;
1527  u_int lines = status_line_size(c), height, i;
1528  u_int py;
1529 
1530  if (size <= 1)
1531  return (0);
1532  if (c->tty.sy - lines < 3)
1533  return (0);
1534 
1535  spm = xmalloc(sizeof *spm);
1536  spm->c = c;
1537  spm->size = size;
1538  spm->list = list;
1539  spm->flag = flag;
1540 
1541  height = c->tty.sy - lines - 2;
1542  if (height > 10)
1543  height = 10;
1544  if (height > size)
1545  height = size;
1546  spm->start = size - height;
1547 
1548  menu = menu_create("");
1549  for (i = spm->start; i < size; i++) {
1550  item.name = list[i];
1551  item.key = '0' + (i - spm->start);
1552  item.command = NULL;
1553  menu_add_item(menu, &item, NULL, NULL, NULL);
1554  }
1555 
1556  if (options_get_number(c->session->options, "status-position") == 0)
1557  py = lines;
1558  else
1559  py = c->tty.sy - 3 - height;
1560  offset += utf8_cstrwidth(c->prompt_string);
1561  if (offset > 2)
1562  offset -= 2;
1563  else
1564  offset = 0;
1565 
1566  if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, NULL, offset,
1567  py, c, NULL, status_prompt_menu_callback, spm) != 0) {
1568  menu_free(menu);
1569  free(spm);
1570  return (0);
1571  }
1572  return (1);
1573 }
1574 
1575 /* Show complete word menu. */
1576 static char *
1578  const char *word, u_int offset, char flag)
1579 {
1580  struct menu *menu;
1581  struct menu_item item;
1582  struct status_prompt_menu *spm;
1583  struct winlink *wl;
1584  char **list = NULL, *tmp;
1585  u_int lines = status_line_size(c), height;
1586  u_int py, size = 0;
1587 
1588  if (c->tty.sy - lines < 3)
1589  return (NULL);
1590 
1591  spm = xmalloc(sizeof *spm);
1592  spm->c = c;
1593  spm->flag = flag;
1594 
1595  height = c->tty.sy - lines - 2;
1596  if (height > 10)
1597  height = 10;
1598  spm->start = 0;
1599 
1600  menu = menu_create("");
1601  RB_FOREACH(wl, winlinks, &s->windows) {
1602  if (word != NULL && *word != '\0') {
1603  xasprintf(&tmp, "%d", wl->idx);
1604  if (strncmp(tmp, word, strlen(word)) != 0) {
1605  free(tmp);
1606  continue;
1607  }
1608  free(tmp);
1609  }
1610 
1611  list = xreallocarray(list, size + 1, sizeof *list);
1612  if (c->prompt_flags & PROMPT_WINDOW) {
1613  xasprintf(&tmp, "%d (%s)", wl->idx, wl->window->name);
1614  xasprintf(&list[size++], "%d", wl->idx);
1615  } else {
1616  xasprintf(&tmp, "%s:%d (%s)", s->name, wl->idx,
1617  wl->window->name);
1618  xasprintf(&list[size++], "%s:%d", s->name, wl->idx);
1619  }
1620  item.name = tmp;
1621  item.key = '0' + size - 1;
1622  item.command = NULL;
1623  menu_add_item(menu, &item, NULL, NULL, NULL);
1624  free(tmp);
1625 
1626  if (size == height)
1627  break;
1628  }
1629  if (size == 0) {
1630  menu_free(menu);
1631  return (NULL);
1632  }
1633  if (size == 1) {
1634  menu_free(menu);
1635  if (flag != '\0') {
1636  xasprintf(&tmp, "-%c%s", flag, list[0]);
1637  free(list[0]);
1638  } else
1639  tmp = list[0];
1640  free(list);
1641  return (tmp);
1642  }
1643  if (height > size)
1644  height = size;
1645 
1646  spm->size = size;
1647  spm->list = list;
1648 
1649  if (options_get_number(c->session->options, "status-position") == 0)
1650  py = lines;
1651  else
1652  py = c->tty.sy - 3 - height;
1653  offset += utf8_cstrwidth(c->prompt_string);
1654  if (offset > 2)
1655  offset -= 2;
1656  else
1657  offset = 0;
1658 
1659  if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, NULL, offset,
1660  py, c, NULL, status_prompt_menu_callback, spm) != 0) {
1661  menu_free(menu);
1662  free(spm);
1663  return (NULL);
1664  }
1665  return (NULL);
1666 }
1667 
1668 /* Sort complete list. */
1669 static int
1670 status_prompt_complete_sort(const void *a, const void *b)
1671 {
1672  const char **aa = (const char **)a, **bb = (const char **)b;
1673 
1674  return (strcmp(*aa, *bb));
1675 }
1676 
1677 /* Complete a session. */
1678 static char *
1679 status_prompt_complete_session(char ***list, u_int *size, const char *s,
1680  char flag)
1681 {
1682  struct session *loop;
1683  char *out, *tmp, n[11];
1684 
1685  RB_FOREACH(loop, sessions, &sessions) {
1686  if (*s == '\0' || strncmp(loop->name, s, strlen(s)) == 0) {
1687  *list = xreallocarray(*list, (*size) + 2,
1688  sizeof **list);
1689  xasprintf(&(*list)[(*size)++], "%s:", loop->name);
1690  } else if (*s == '$') {
1691  xsnprintf(n, sizeof n, "%u", loop->id);
1692  if (s[1] == '\0' ||
1693  strncmp(n, s + 1, strlen(s) - 1) == 0) {
1694  *list = xreallocarray(*list, (*size) + 2,
1695  sizeof **list);
1696  xasprintf(&(*list)[(*size)++], "$%s:", n);
1697  }
1698  }
1699  }
1700  out = status_prompt_complete_prefix(*list, *size);
1701  if (out != NULL && flag != '\0') {
1702  xasprintf(&tmp, "-%c%s", flag, out);
1703  free(out);
1704  out = tmp;
1705  }
1706  return (out);
1707 }
1708 
1709 /* Complete word. */
1710 static char *
1711 status_prompt_complete(struct client *c, const char *word, u_int offset)
1712 {
1713  struct session *session;
1714  const char *s, *colon;
1715  char **list = NULL, *copy = NULL, *out = NULL;
1716  char flag = '\0';
1717  u_int size = 0, i;
1718 
1719  if (*word == '\0' &&
1720  ((c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) == 0))
1721  return (NULL);
1722 
1723  if (((c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) == 0) &&
1724  strncmp(word, "-t", 2) != 0 &&
1725  strncmp(word, "-s", 2) != 0) {
1726  list = status_prompt_complete_list(&size, word, offset == 0);
1727  if (size == 0)
1728  out = NULL;
1729  else if (size == 1)
1730  xasprintf(&out, "%s ", list[0]);
1731  else
1732  out = status_prompt_complete_prefix(list, size);
1733  goto found;
1734  }
1735 
1737  s = word;
1738  flag = '\0';
1739  } else {
1740  s = word + 2;
1741  flag = word[1];
1742  offset += 2;
1743  }
1744 
1745  /* If this is a window completion, open the window menu. */
1746  if (c->prompt_flags & PROMPT_WINDOW) {
1748  offset, '\0');
1749  goto found;
1750  }
1751  colon = strchr(s, ':');
1752 
1753  /* If there is no colon, complete as a session. */
1754  if (colon == NULL) {
1755  out = status_prompt_complete_session(&list, &size, s, flag);
1756  goto found;
1757  }
1758 
1759  /* If there is a colon but no period, find session and show a menu. */
1760  if (strchr(colon + 1, '.') == NULL) {
1761  if (*s == ':')
1762  session = c->session;
1763  else {
1764  copy = xstrdup(s);
1765  *strchr(copy, ':') = '\0';
1766  session = session_find(copy);
1767  free(copy);
1768  if (session == NULL)
1769  goto found;
1770  }
1771  out = status_prompt_complete_window_menu(c, session, colon + 1,
1772  offset, flag);
1773  if (out == NULL)
1774  return (NULL);
1775  }
1776 
1777 found:
1778  if (size != 0) {
1779  qsort(list, size, sizeof *list, status_prompt_complete_sort);
1780  for (i = 0; i < size; i++)
1781  log_debug("complete %u: %s", i, list[i]);
1782  }
1783 
1784  if (out != NULL && strcmp(word, out) == 0) {
1785  free(out);
1786  out = NULL;
1787  }
1788  if (out != NULL ||
1789  !status_prompt_complete_list_menu(c, list, size, offset, flag)) {
1790  for (i = 0; i < size; i++)
1791  free(list[i]);
1792  free(list);
1793  }
1794  return (out);
1795 }
const struct cmd_entry * cmd_table[]
Definition: cmd.c:120
#define __unused
Definition: compat.h:60
char * fgetln(FILE *, size_t *)
void format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, u_int available, const char *expanded, struct style_ranges *srs)
Definition: format-draw.c:649
struct format_tree * format_create_defaults(struct cmdq_item *item, struct client *c, struct session *s, struct winlink *wl, struct window_pane *wp)
Definition: format.c:4652
void format_defaults(struct format_tree *ft, struct client *c, struct session *s, struct winlink *wl, struct window_pane *wp)
Definition: format.c:4684
struct format_tree * format_create_from_state(struct cmdq_item *item, struct client *c, struct cmd_find_state *fs)
Definition: format.c:4667
struct format_tree * format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
Definition: format.c:3042
void format_free(struct format_tree *ft)
Definition: format.c:3066
char * format_expand_time(struct format_tree *ft, const char *fmt)
Definition: format.c:4597
int grid_compare(struct grid *ga, struct grid *gb)
Definition: grid.c:310
int grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
Definition: grid.c:239
key_code key
Definition: key-string.c:32
const char * key_string_lookup_key(key_code key, int with_flags)
Definition: key-string.c:265
void fatalx(const char *msg,...)
Definition: log.c:159
void log_debug(const char *msg,...)
Definition: log.c:130
void menu_add_item(struct menu *menu, const struct menu_item *item, struct cmdq_item *qitem, struct client *c, struct cmd_find_state *fs)
Definition: menu.c:54
struct menu * menu_create(const char *title)
Definition: menu.c:108
int menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px, u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb, void *data)
Definition: menu.c:346
void menu_free(struct menu *menu)
Definition: menu.c:120
const struct options_table_entry options_table[]
union options_value * options_array_item_value(struct options_array_item *a)
Definition: options.c:549
const char * options_get_string(struct options *oo, const char *name)
Definition: options.c:686
struct options_array_item * options_array_first(struct options_entry *o)
Definition: options.c:529
long long options_get_number(struct options *oo, const char *name)
Definition: options.c:699
struct options_array_item * options_array_next(struct options_array_item *a)
Definition: options.c:537
struct options_entry * options_get(struct options *oo, const char *name)
Definition: options.c:229
union options_value * options_array_get(struct options_entry *o, u_int idx)
Definition: options.c:409
struct options_entry * options_get_only(struct options *oo, const char *name)
Definition: options.c:216
#define nitems(_a)
struct paste_buffer * paste_get_top(const char **name)
Definition: paste.c:116
const char * paste_buffer_data(struct paste_buffer *pb, size_t *size)
Definition: paste.c:98
void screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px, u_int py, u_int nx, u_int ny)
Definition: screen-write.c:548
void screen_write_start(struct screen_write_ctx *ctx, struct screen *s)
Definition: screen-write.c:284
void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
void screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp, u_char ch)
Definition: screen-write.c:321
void screen_write_cursormove(struct screen_write_ctx *ctx, int px, int py, int origin)
void screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen, const struct grid_cell *gcp, const char *fmt,...)
Definition: screen-write.c:476
void screen_write_stop(struct screen_write_ctx *ctx)
Definition: screen-write.c:296
size_t screen_write_strlen(const char *fmt,...)
Definition: screen-write.c:334
void screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
Definition: screen.c:276
void screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
Definition: screen.c:74
void screen_free(struct screen *s)
Definition: screen.c:122
struct clients clients
Definition: server.c:42
void server_add_message(const char *fmt,...)
Definition: server.c:513
struct sessions sessions
Definition: session.c:29
struct session * session_find(const char *name)
Definition: session.c:75
static char ** status_prompt_complete_list(u_int *size, const char *s, int at_start)
Definition: status.c:1403
static int status_prompt_space(const struct utf8_data *ud)
Definition: status.c:763
static void status_timer_callback(int, short, void *)
Definition: status.c:148
void status_free(struct client *c)
Definition: status.c:304
static void status_free_ranges(struct style_ranges *srs)
Definition: status.c:252
void status_prompt_save_history(void)
Definition: status.c:120
static int status_prompt_in_list(const char *ws, const struct utf8_data *ud)
Definition: status.c:754
int status_at_line(struct client *c)
Definition: status.c:210
static int status_prompt_complete_list_menu(struct client *c, char **list, u_int size, u_int offset, char flag)
Definition: status.c:1521
static char ** status_prompt_hlist
Definition: status.c:54
static void status_pop_screen(struct client *c)
Definition: status.c:277
static u_int status_prompt_hsize
Definition: status.c:55
static char * status_prompt_complete_window_menu(struct client *, struct session *, const char *, u_int, char)
Definition: status.c:1577
void status_update_cache(struct session *s)
Definition: status.c:197
int status_redraw(struct client *c)
Definition: status.c:326
void status_init(struct client *c)
Definition: status.c:290
static char * status_prompt_complete_prefix(char **list, u_int size)
Definition: status.c:1467
static int status_prompt_complete_sort(const void *a, const void *b)
Definition: status.c:1670
static void status_push_screen(struct client *c)
Definition: status.c:264
u_int status_line_size(struct client *c)
Definition: status.c:223
int status_prompt_redraw(struct client *c)
Definition: status.c:657
static void status_prompt_add_history(const char *)
Definition: status.c:1378
static int status_prompt_paste(struct client *c)
Definition: status.c:897
static const char * status_prompt_down_history(u_int *)
Definition: status.c:1366
static char * status_prompt_complete_session(char ***list, u_int *size, const char *s, char flag)
Definition: status.c:1679
#define PROMPT_HISTORY
Definition: status.c:53
static int status_prompt_replace_complete(struct client *c, const char *s)
Definition: status.c:962
void status_prompt_clear(struct client *c)
Definition: status.c:602
int status_prompt_key(struct client *c, key_code key)
Definition: status.c:1033
void status_message_clear(struct client *c)
Definition: status.c:470
int status_message_redraw(struct client *c)
Definition: status.c:496
static void status_message_callback(int, short, void *)
Definition: status.c:487
void status_prompt_update(struct client *c, const char *msg, const char *input)
Definition: status.c:630
void status_message_set(struct client *c, int delay, int ignore_styles, int ignore_keys, const char *fmt,...)
Definition: status.c:428
static int status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
Definition: status.c:775
void status_timer_start_all(void)
Definition: status.c:187
static const char * status_prompt_up_history(u_int *)
Definition: status.c:1351
static char * status_prompt_find_history_file(void)
Definition: status.c:59
void status_prompt_set(struct client *c, struct cmd_find_state *fs, const char *msg, const char *input, prompt_input_cb inputcb, prompt_free_cb freecb, void *data, int flags)
Definition: status.c:546
static void status_prompt_menu_callback(struct menu *menu, u_int idx, key_code key, void *data)
Definition: status.c:1490
void status_timer_start(struct client *c)
Definition: status.c:172
static char * status_prompt_complete(struct client *, const char *, u_int)
Definition: status.c:1711
struct style_range * status_get_range(struct client *c, u_int x, u_int y)
Definition: status.c:236
void status_prompt_load_history(void)
Definition: status.c:80
Definition: tmux.h:1608
int message_ignore_keys
Definition: tmux.h:1718
struct tty tty
Definition: tmux.h:1640
struct utf8_data * prompt_saved
Definition: tmux.h:1732
size_t prompt_index
Definition: tmux.h:1726
u_int prompt_hindex
Definition: tmux.h:1730
struct status_line status
Definition: tmux.h:1652
prompt_free_cb prompt_freecb
Definition: tmux.h:1728
int message_ignore_styles
Definition: tmux.h:1719
char * prompt_string
Definition: tmux.h:1723
const char * name
Definition: tmux.h:1609
struct session * session
Definition: tmux.h:1743
int fd
Definition: tmux.h:1619
void * prompt_data
Definition: tmux.h:1729
uint64_t flags
Definition: tmux.h:1703
struct event message_timer
Definition: tmux.h:1721
char * prompt_last
Definition: tmux.h:1725
prompt_input_cb prompt_inputcb
Definition: tmux.h:1727
int prompt_flags
Definition: tmux.h:1741
struct utf8_data * prompt_buffer
Definition: tmux.h:1724
enum client::@18 prompt_mode
char * message_string
Definition: tmux.h:1720
Definition: tmux.h:1525
int flags
Definition: format.c:141
struct session * s
Definition: format.c:133
struct client * c
Definition: format.c:132
u_char flags
Definition: tmux.h:691
int bg
Definition: tmux.h:693
struct utf8_data data
Definition: tmux.h:689
u_short attr
Definition: tmux.h:690
int fg
Definition: tmux.h:692
key_code key
Definition: tmux.h:889
const char * command
Definition: tmux.h:890
const char * name
Definition: tmux.h:888
Definition: tmux.h:892
union options_value value
Definition: options.c:36
Definition: options.c:50
Definition: tmux.h:1830
const char * name
Definition: tmux.h:1831
size_t size
Definition: paste.c:34
Definition: tmux.h:816
u_int cx
Definition: tmux.h:823
struct grid * grid
Definition: tmux.h:821
Definition: tmux.h:1179
char * name
Definition: tmux.h:1182
u_int id
Definition: tmux.h:1180
u_int statuslines
Definition: tmux.h:1197
struct winlinks windows
Definition: tmux.h:1194
int statusat
Definition: tmux.h:1196
struct options * options
Definition: tmux.h:1199
Definition: tmux.h:1552
struct style_ranges ranges
Definition: tmux.h:1554
char * expanded
Definition: tmux.h:1553
struct status_line_entry entries[5]
Definition: tmux.h:1564
struct event timer
Definition: tmux.h:1557
struct screen screen
Definition: tmux.h:1559
struct screen * active
Definition: tmux.h:1560
int references
Definition: tmux.h:1561
struct grid_cell style
Definition: tmux.h:1563
struct client * c
Definition: status.c:45
char ** list
Definition: status.c:48
u_int end
Definition: tmux.h:785
u_int start
Definition: tmux.h:784
u_int sx
Definition: tmux.h:1308
u_int sy
Definition: tmux.h:1309
int flags
Definition: tmux.h:1355
u_char data[21]
Definition: tmux.h:629
u_char size
Definition: tmux.h:632
u_char have
Definition: tmux.h:631
u_char width
Definition: tmux.h:634
char * name
Definition: tmux.h:1045
void style_apply(struct grid_cell *gc, struct options *oo, const char *name, struct format_tree *ft)
Definition: style.c:298
const char * find_home(void)
Definition: tmux.c:299
struct options * global_s_options
Definition: tmux.c:37
struct options * global_options
Definition: tmux.c:36
int(* prompt_input_cb)(struct client *, void *, const char *, int)
Definition: tmux.h:1601
#define MENU_NOMOUSE
Definition: tmux.h:3062
#define KEYC_BASE
Definition: tmux.h:120
#define KEYC_META
Definition: tmux.h:124
#define PROMPT_SINGLE
Definition: tmux.h:1734
#define KEYC_CTRL
Definition: tmux.h:125
#define FORMAT_FORCE
Definition: tmux.h:1970
size_t utf8_strlen(const struct utf8_data *)
Definition: utf8.c:443
#define PROMPT_WINDOW
Definition: tmux.h:1739
void(* prompt_free_cb)(void *)
Definition: tmux.h:1602
struct utf8_data * utf8_fromcstr(const char *)
Definition: utf8.c:472
#define PROMPT_INCREMENTAL
Definition: tmux.h:1736
enum utf8_state utf8_open(struct utf8_data *, u_char)
Definition: utf8.c:266
#define CLIENT_STATUSOFF
Definition: tmux.h:1677
#define PROMPT_NUMERIC
Definition: tmux.h:1735
unsigned long long key_code
Definition: tmux.h:177
#define KEYC_NONE
Definition: tmux.h:113
u_int utf8_strwidth(const struct utf8_data *, ssize_t)
Definition: utf8.c:454
void utf8_copy(struct utf8_data *, const struct utf8_data *)
Definition: utf8.c:203
void utf8_to_data(utf8_char, struct utf8_data *)
Definition: utf8.c:159
char * utf8_tocstr(struct utf8_data *)
Definition: utf8.c:500
#define FORMAT_NONE
Definition: tmux.h:1973
void utf8_set(struct utf8_data *, u_char)
Definition: utf8.c:193
#define PROMPT_NOFORMAT
Definition: tmux.h:1737
#define CLIENT_CONTROL
Definition: tmux.h:1667
#define TTY_NOCURSOR
Definition: tmux.h:1344
#define MODEKEY_VI
Definition: tmux.h:595
#define CLIENT_STATUSFORCE
Definition: tmux.h:1673
#define screen_size_y(s)
Definition: tmux.h:882
#define MENU_TAB
Definition: tmux.h:3063
#define CLIENT_ALLREDRAWFLAGS
Definition: tmux.h:1688
#define screen_size_x(s)
Definition: tmux.h:881
#define CLIENT_REDRAWSTATUS
Definition: tmux.h:1658
#define PROMPT_TARGET
Definition: tmux.h:1740
u_int utf8_cstrwidth(const char *)
Definition: utf8.c:517
#define GRID_ATTR_REVERSE
Definition: tmux.h:654
utf8_state
Definition: tmux.h:636
@ UTF8_DONE
Definition: tmux.h:638
@ UTF8_MORE
Definition: tmux.h:637
@ KEYC_HOME
Definition: tmux.h:239
@ KEYC_UP
Definition: tmux.h:246
@ KEYC_END
Definition: tmux.h:240
@ KEYC_LEFT
Definition: tmux.h:248
@ KEYC_BASE_END
Definition: tmux.h:270
@ KEYC_DOWN
Definition: tmux.h:247
@ KEYC_BSPACE
Definition: tmux.h:222
@ KEYC_DC
Definition: tmux.h:238
@ KEYC_RIGHT
Definition: tmux.h:249
#define PROMPT_KEY
Definition: tmux.h:1738
#define TTY_FREEZE
Definition: tmux.h:1345
#define FORMAT_STATUS
Definition: tmux.h:1969
enum utf8_state utf8_append(struct utf8_data *, u_char)
Definition: utf8.c:283
char * string
Definition: tmux.h:1802
enum window_copy_cmd_action(* f)(struct window_copy_cmd_state *)
Definition: window-copy.c:2248
char * xstrndup(const char *str, size_t maxlen)
Definition: xmalloc.c:99
void * xmalloc(size_t size)
Definition: xmalloc.c:27
int xsnprintf(char *str, size_t len, const char *fmt,...)
Definition: xmalloc.c:135
void * xreallocarray(void *ptr, size_t nmemb, size_t size)
Definition: xmalloc.c:61
int xasprintf(char **ret, const char *fmt,...)
Definition: xmalloc.c:109
void * xcalloc(size_t nmemb, size_t size)
Definition: xmalloc.c:41
char * xstrdup(const char *str)
Definition: xmalloc.c:89
int xvasprintf(char **ret, const char *fmt, va_list ap)
Definition: xmalloc.c:122