Coverage Report

Created: 2026-09-13 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/cmd-display-message.c
Line
Count
Source
1
/* $OpenBSD: cmd-display-message.c,v 1.66 2026/09/08 08:33:10 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
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 <stdlib.h>
22
#include <time.h>
23
24
#include "tmux.h"
25
26
/*
27
 * Displays a message in the status line.
28
 */
29
30
#define DISPLAY_MESSAGE_TEMPLATE      \
31
0
  "[#{session_name}] #{window_index}:"    \
32
0
  "#{window_name}, current pane #{pane_index} " \
33
0
  "- (%H:%M %d-%b-%y)"
34
35
static enum cmd_retval  cmd_display_message_exec(struct cmd *,
36
          struct cmdq_item *);
37
38
const struct cmd_entry cmd_display_message_entry = {
39
  .name = "display-message",
40
  .alias = "display",
41
42
  .args = { "aCc:d:jlINpt:F:v", 0, 1, NULL },
43
  .usage = "[-aCIjlNpv] [-c target-client] [-d delay] [-F format] "
44
     CMD_TARGET_PANE_USAGE " [message]",
45
46
  .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
47
48
  .flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL,
49
  .exec = cmd_display_message_exec
50
};
51
52
static void
53
cmd_display_message_each(const char *key, const char *value, void *arg)
54
0
{
55
0
  struct cmdq_item  *item = arg;
56
57
0
  cmdq_print(item, "%s=%s", key, value);
58
0
}
59
60
static enum cmd_retval
61
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
62
0
{
63
0
  struct args   *args = cmd_get_args(self);
64
0
  struct cmd_find_state *target = cmdq_get_target(item);
65
0
  struct client   *tc = cmdq_get_target_client(item), *c;
66
0
  struct session    *s = target->s;
67
0
  struct winlink    *wl = target->wl;
68
0
  struct window_pane  *wp = target->wp;
69
0
  const char    *template;
70
0
  char      *msg, *cause = NULL;
71
0
  int      delay = -1, flags, Nflag = args_has(args, 'N');
72
0
  int      Cflag = args_has(args, 'C');
73
0
  struct format_tree  *ft;
74
0
  u_int      count = args_count(args);
75
0
  struct evbuffer   *evb;
76
0
  struct json_node  *jn;
77
78
0
  if (args_has(args, 'I') && !args_has(args, 'j')) {
79
0
    if (wp == NULL)
80
0
      return (CMD_RETURN_NORMAL);
81
0
    switch (window_pane_start_input(wp, item, &cause)) {
82
0
    case -1:
83
0
      cmdq_error(item, "%s", cause);
84
0
      free(cause);
85
0
      return (CMD_RETURN_ERROR);
86
0
    case 1:
87
0
      return (CMD_RETURN_NORMAL);
88
0
    case 0:
89
0
      return (CMD_RETURN_WAIT);
90
0
    }
91
0
  }
92
93
0
  if (args_has(args, 'F') && count != 0) {
94
0
    cmdq_error(item, "only one of -F or argument must be given");
95
0
    return (CMD_RETURN_ERROR);
96
0
  }
97
98
0
  if (args_has(args, 'd')) {
99
0
    delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
100
0
    if (cause != NULL) {
101
0
      cmdq_error(item, "delay %s", cause);
102
0
      free(cause);
103
0
      return (CMD_RETURN_ERROR);
104
0
    }
105
0
  }
106
107
0
  if (count != 0)
108
0
    template = args_string(args, 0);
109
0
  else
110
0
    template = args_get(args, 'F');
111
0
  if (args_has(args, 'j') && template == NULL)
112
0
    template = "";
113
0
  else if (template == NULL)
114
0
    template = DISPLAY_MESSAGE_TEMPLATE;
115
116
  /*
117
   * -c is intended to be the client where the message should be
118
   * displayed if -p is not given. But it makes sense to use it for the
119
   * formats too, assuming it matches the session. If it doesn't, use the
120
   * best client for the session.
121
   */
122
0
  if (tc != NULL && tc->session == s)
123
0
    c = tc;
124
0
  else if (s != NULL)
125
0
    c = cmd_find_best_client(s);
126
0
  else
127
0
    c = NULL;
128
0
  if (args_has(args, 'v'))
129
0
    flags = FORMAT_VERBOSE;
130
0
  else
131
0
    flags = 0;
132
0
  ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, flags);
133
0
  format_defaults(ft, c, s, wl, wp);
134
135
0
  if (args_has(args, 'a') && !args_has(args, 'j')) {
136
0
    format_each(ft, cmd_display_message_each, item);
137
0
    format_free(ft);
138
0
    return (CMD_RETURN_NORMAL);
139
0
  }
140
141
0
  if (args_has(args, 'l'))
142
0
    msg = xstrdup(template);
143
0
  else
144
0
    msg = format_expand_time(ft, template);
145
0
  if (args_has(args, 'j')) {
146
0
    jn = json_parse(msg, &cause);
147
0
    if (jn == NULL) {
148
0
      cmdq_error(item, "%s", cause);
149
0
      free(cause);
150
0
      free(msg);
151
0
      format_free(ft);
152
0
      return (CMD_RETURN_ERROR);
153
0
    }
154
0
    free(msg);
155
0
    msg = json_to_string(jn);
156
0
    json_destroy_node(jn);
157
0
  }
158
159
0
  if (cmdq_get_client(item) == NULL)
160
0
    cmdq_error(item, "%s", msg);
161
0
  else if (args_has(args, 'p'))
162
0
    cmdq_print(item, "%s", msg);
163
0
  else if (tc != NULL && (tc->flags & CLIENT_CONTROL)) {
164
0
    evb = evbuffer_new();
165
0
    if (evb == NULL)
166
0
      fatalx("out of memory");
167
0
    evbuffer_add_printf(evb, "%%message %s", msg);
168
0
    server_client_print(tc, 0, evb);
169
0
    evbuffer_free(evb);
170
0
  } else if (tc != NULL)
171
0
    status_message_set(tc, delay, 0, Nflag, Cflag, "%s", msg);
172
0
  free(msg);
173
174
0
  format_free(ft);
175
0
  return (CMD_RETURN_NORMAL);
176
0
}