mirror of
https://github.com/tmux/tmux.git
synced 2025-01-06 07:48:48 +00:00
Merge branch 'obsd-master'
This commit is contained in:
commit
aa13bd4016
@ -71,6 +71,7 @@ dist_tmux_SOURCES = \
|
||||
cmd-confirm-before.c \
|
||||
cmd-copy-mode.c \
|
||||
cmd-detach-client.c \
|
||||
cmd-display-menu.c \
|
||||
cmd-display-message.c \
|
||||
cmd-display-panes.c \
|
||||
cmd-find-window.c \
|
||||
@ -143,6 +144,7 @@ dist_tmux_SOURCES = \
|
||||
layout-set.c \
|
||||
layout.c \
|
||||
log.c \
|
||||
menu.c \
|
||||
mode-tree.c \
|
||||
names.c \
|
||||
notify.c \
|
||||
|
163
cmd-display-menu.c
Normal file
163
cmd-display-menu.c
Normal file
@ -0,0 +1,163 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Display a menu on a client.
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
|
||||
const struct cmd_entry cmd_display_menu_entry = {
|
||||
.name = "display-menu",
|
||||
.alias = "menu",
|
||||
|
||||
.args = { "c:FM:t:T:x:y:", 0, 0 },
|
||||
.usage = "[-F] [-c target-client] [-M menu] " CMD_TARGET_PANE_USAGE " "
|
||||
"[-T title] [-x position] [-y position]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_display_menu_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct client *c;
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window_pane *wp = item->target.wp;
|
||||
struct cmd_find_state *fs = &item->target;
|
||||
struct menu *menu = NULL;
|
||||
struct style_range *sr;
|
||||
const char *string, *xp, *yp;
|
||||
int at, flags;
|
||||
u_int px, py, ox, oy, sx, sy;
|
||||
char *title;
|
||||
|
||||
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
|
||||
return (CMD_RETURN_ERROR);
|
||||
if (c->overlay_draw != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
at = status_at_line(c);
|
||||
|
||||
string = args_get(args, 'M');
|
||||
if (string == NULL) {
|
||||
cmdq_error(item, "no menu specified");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_has(args, 'F'))
|
||||
string = format_single(NULL, string, c, s, wl, wp);
|
||||
else
|
||||
string = xstrdup(string);
|
||||
if (args_has(args, 'T'))
|
||||
title = format_single(NULL, args_get(args, 'T'), c, s, wl, wp);
|
||||
else
|
||||
title = xstrdup("");
|
||||
menu = menu_create_from_string(string, c, fs, title);
|
||||
free(title);
|
||||
if (menu == NULL) {
|
||||
cmdq_error(item, "invalid menu %s", string);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (menu->count == 0) {
|
||||
menu_free(menu);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
xp = args_get(args, 'x');
|
||||
if (xp == NULL)
|
||||
px = 0;
|
||||
else if (strcmp(xp, "R") == 0)
|
||||
px = c->tty.sx - 1;
|
||||
else if (strcmp(xp, "P") == 0) {
|
||||
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
|
||||
if (wp->xoff >= ox)
|
||||
px = wp->xoff - ox;
|
||||
else
|
||||
px = 0;
|
||||
} else if (strcmp(xp, "M") == 0 && item->shared->mouse.valid) {
|
||||
if (item->shared->mouse.x > (menu->width + 4) / 2)
|
||||
px = item->shared->mouse.x - (menu->width + 4) / 2;
|
||||
else
|
||||
px = 0;
|
||||
}
|
||||
else if (strcmp(xp, "W") == 0) {
|
||||
if (at == -1)
|
||||
px = 0;
|
||||
else {
|
||||
TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
|
||||
if (sr->type != STYLE_RANGE_WINDOW)
|
||||
continue;
|
||||
if (sr->argument == (u_int)wl->idx)
|
||||
break;
|
||||
}
|
||||
if (sr != NULL)
|
||||
px = sr->start;
|
||||
else
|
||||
px = 0;
|
||||
}
|
||||
} else
|
||||
px = strtoul(xp, NULL, 10);
|
||||
if (px + menu->width + 4 >= c->tty.sx)
|
||||
px = c->tty.sx - menu->width - 4;
|
||||
|
||||
yp = args_get(args, 'y');
|
||||
if (yp == NULL)
|
||||
py = 0;
|
||||
else if (strcmp(yp, "P") == 0) {
|
||||
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
|
||||
if (wp->yoff + wp->sy >= oy)
|
||||
py = wp->yoff + wp->sy - oy;
|
||||
else
|
||||
py = 0;
|
||||
} else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
|
||||
py = item->shared->mouse.y + menu->count + 2;
|
||||
else if (strcmp(yp, "S") == 0) {
|
||||
if (at == -1)
|
||||
py = c->tty.sy;
|
||||
else if (at == 0)
|
||||
py = status_line_size(c) + menu->count + 2;
|
||||
else
|
||||
py = at;
|
||||
} else
|
||||
py = strtoul(yp, NULL, 10);
|
||||
if (py < menu->count + 2)
|
||||
py = 0;
|
||||
else
|
||||
py -= menu->count + 2;
|
||||
if (py + menu->count + 2 >= c->tty.sy)
|
||||
py = c->tty.sy - menu->count - 2;
|
||||
|
||||
flags = 0;
|
||||
if (!item->shared->mouse.valid)
|
||||
flags |= MENU_NOMOUSE;
|
||||
if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
2
cmd.c
2
cmd.c
@ -41,6 +41,7 @@ extern const struct cmd_entry cmd_confirm_before_entry;
|
||||
extern const struct cmd_entry cmd_copy_mode_entry;
|
||||
extern const struct cmd_entry cmd_delete_buffer_entry;
|
||||
extern const struct cmd_entry cmd_detach_client_entry;
|
||||
extern const struct cmd_entry cmd_display_menu_entry;
|
||||
extern const struct cmd_entry cmd_display_message_entry;
|
||||
extern const struct cmd_entry cmd_display_panes_entry;
|
||||
extern const struct cmd_entry cmd_down_pane_entry;
|
||||
@ -129,6 +130,7 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_copy_mode_entry,
|
||||
&cmd_delete_buffer_entry,
|
||||
&cmd_detach_client_entry,
|
||||
&cmd_display_menu_entry,
|
||||
&cmd_display_message_entry,
|
||||
&cmd_display_panes_entry,
|
||||
&cmd_find_window_entry,
|
||||
|
48
format.c
48
format.c
@ -54,6 +54,49 @@ static void format_defaults_session(struct format_tree *,
|
||||
static void format_defaults_client(struct format_tree *, struct client *);
|
||||
static void format_defaults_winlink(struct format_tree *, struct winlink *);
|
||||
|
||||
/* Default menus. */
|
||||
#define DEFAULT_CLIENT_MENU \
|
||||
"Detach,d,detach-client|" \
|
||||
"Detach & Kill,X,detach-client -P|" \
|
||||
"Detach Others,o,detach-client -a|" \
|
||||
"|" \
|
||||
"#{?#{lock-command},Lock,},l,lock-client"
|
||||
#define DEFAULT_SESSION_MENU \
|
||||
"Next,n,switch-client -n|" \
|
||||
"Previous,p,switch-client -p|" \
|
||||
"|" \
|
||||
"Renumber,N,move-window -r|" \
|
||||
"Rename,n,command-prompt -I \"#S\" \"rename-session -- '%%'\"|" \
|
||||
"|" \
|
||||
"New Session,s,new-session|" \
|
||||
"New Window,w,new-window"
|
||||
#define DEFAULT_WINDOW_MENU \
|
||||
"Swap Left,l,swap-window -t:-1|" \
|
||||
"Swap Right,r,swap-window -t:+1|" \
|
||||
"#{?pane_marked_set,,#[dim]}Swap Marked,s,swap-window|" \
|
||||
"|" \
|
||||
"Kill,X,kill-window|" \
|
||||
"Respawn,R,respawn-window -k|" \
|
||||
"|" \
|
||||
"#{?pane_marked,Unmark,Mark},m,select-pane -m|" \
|
||||
"Rename,n,command-prompt -I \"#W\" \"rename-window -- '%%'\"|" \
|
||||
"|" \
|
||||
"New After,w,new-window -a|" \
|
||||
"New At End,W,new-window"
|
||||
#define DEFAULT_PANE_MENU \
|
||||
"Horizontal Split,h,split-window -h|" \
|
||||
"Vertical Split,v,split-window -v|" \
|
||||
"|" \
|
||||
"Swap Up,u,swap-pane -U|" \
|
||||
"Swap Down,d,swap-pane -D|" \
|
||||
"#{?pane_marked_set,,#[dim]}Swap Marked,s,swap-pane|" \
|
||||
"|" \
|
||||
"Kill,X,kill-pane|" \
|
||||
"Respawn,R,respawn-pane -k|" \
|
||||
"|" \
|
||||
"#{?pane_marked,Unmark,Mark},m,select-pane -m|" \
|
||||
"#{?window_zoomed_flag,Unzoom,Zoom},z,resize-pane -Z"
|
||||
|
||||
/* Entry in format job tree. */
|
||||
struct format_job {
|
||||
struct client *client;
|
||||
@ -768,6 +811,11 @@ format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
format_add(ft, "client_menu", "%s", DEFAULT_CLIENT_MENU);
|
||||
format_add(ft, "session_menu", "%s", DEFAULT_SESSION_MENU);
|
||||
format_add(ft, "window_menu", "%s", DEFAULT_WINDOW_MENU);
|
||||
format_add(ft, "pane_menu", "%s", DEFAULT_PANE_MENU);
|
||||
|
||||
if (item != NULL) {
|
||||
if (item->cmd != NULL)
|
||||
format_add(ft, "command", "%s", item->cmd->entry->name);
|
||||
|
@ -271,6 +271,7 @@ key_bindings_init(void)
|
||||
"bind -r C-Down resize-pane -D",
|
||||
"bind -r C-Left resize-pane -L",
|
||||
"bind -r C-Right resize-pane -R",
|
||||
|
||||
"bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
|
||||
"bind -n MouseDrag1Border resize-pane -M",
|
||||
"bind -n MouseDown1Status select-window -t=",
|
||||
@ -279,6 +280,10 @@ key_bindings_init(void)
|
||||
"bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'",
|
||||
"bind -n MouseDown3Pane if-shell -Ft= '#{mouse_any_flag}' 'select-pane -t=; send-keys -M' 'select-pane -mt='",
|
||||
"bind -n WheelUpPane if-shell -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= \"#{pane_in_mode}\" \"send-keys -M\" \"copy-mode -et=\"'",
|
||||
"bind -n MouseDown3StatusRight display-menu -t= -xM -yS -F -M \"#{client_menu}\" -T \"#[align=centre]#{client_name}\"",
|
||||
"bind -n MouseDown3StatusLeft display-menu -t= -xM -yS -F -M \"#{session_menu}\" -T \"#[align=centre]#{session_name}\"",
|
||||
"bind -n MouseDown3Status display-menu -t= -xW -yS -F -M \"#{window_menu}\" -T \"#[align=centre]#{window_index}:#{window_name}\"",
|
||||
"bind -n M-MouseDown3Pane display-menu -t= -xM -yM -F -M \"#{pane_menu}\" -T \"#[align=centre]#{pane_index} (#{pane_id})\"",
|
||||
|
||||
"bind -Tcopy-mode C-Space send -X begin-selection",
|
||||
"bind -Tcopy-mode C-a send -X start-of-line",
|
||||
|
342
menu.c
Normal file
342
menu.c
Normal file
@ -0,0 +1,342 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct menu_data {
|
||||
struct cmdq_item *item;
|
||||
int flags;
|
||||
|
||||
struct cmd_find_state fs;
|
||||
struct screen s;
|
||||
|
||||
u_int px;
|
||||
u_int py;
|
||||
|
||||
struct menu *menu;
|
||||
int choice;
|
||||
|
||||
menu_choice_cb cb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void
|
||||
menu_add_item(struct menu *menu, struct menu_item *item, struct client *c,
|
||||
struct cmd_find_state *fs)
|
||||
{
|
||||
struct menu_item *new_item;
|
||||
const char *key;
|
||||
char *name;
|
||||
u_int width;
|
||||
|
||||
menu->items = xreallocarray(menu->items, menu->count + 1,
|
||||
sizeof *menu->items);
|
||||
new_item = &menu->items[menu->count++];
|
||||
memset(new_item, 0, sizeof *new_item);
|
||||
|
||||
if (item == NULL || *item->name == '\0') /* horizontal line */
|
||||
return;
|
||||
name = format_single(NULL, item->name, c, fs->s, fs->wl, fs->wp);
|
||||
if (*name == '\0') { /* no item if empty after format expanded */
|
||||
menu->count--;
|
||||
return;
|
||||
}
|
||||
if (item->key != KEYC_UNKNOWN) {
|
||||
key = key_string_lookup_key(item->key);
|
||||
xasprintf(&new_item->name, "%s #[align=right](%s)", name, key);
|
||||
} else
|
||||
xasprintf(&new_item->name, "%s", name);
|
||||
free(name);
|
||||
|
||||
if (item->command != NULL)
|
||||
new_item->command = xstrdup(item->command);
|
||||
else
|
||||
new_item->command = NULL;
|
||||
new_item->key = item->key;
|
||||
|
||||
width = format_width(new_item->name);
|
||||
if (width > menu->width)
|
||||
menu->width = width;
|
||||
}
|
||||
|
||||
static void
|
||||
menu_parse_item(struct menu *menu, const char *s, struct client *c,
|
||||
struct cmd_find_state *fs)
|
||||
{
|
||||
char *copy, *first;
|
||||
const char *second, *third;
|
||||
struct menu_item item;
|
||||
|
||||
first = copy = xstrdup(s);
|
||||
if ((second = format_skip(first, ",")) != NULL) {
|
||||
*(char *)second++ = '\0';
|
||||
if ((third = format_skip(second, ",")) != NULL) {
|
||||
*(char *)third++ = '\0';
|
||||
|
||||
item.name = first;
|
||||
item.command = (char *)third;
|
||||
item.key = key_string_lookup_string(second);
|
||||
menu_add_item(menu, &item, c, fs);
|
||||
}
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
|
||||
struct menu *
|
||||
menu_create_from_items(struct menu_item *items, u_int count, struct client *c,
|
||||
struct cmd_find_state *fs, const char *title)
|
||||
{
|
||||
struct menu *menu;
|
||||
u_int i;
|
||||
|
||||
menu = xcalloc(1, sizeof *menu);
|
||||
menu->title = xstrdup(title);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
menu_add_item(menu, &items[i], c, fs);
|
||||
|
||||
return (menu);
|
||||
}
|
||||
|
||||
struct menu *
|
||||
menu_create_from_string(const char *s, struct client *c,
|
||||
struct cmd_find_state *fs, const char *title)
|
||||
{
|
||||
struct menu *menu;
|
||||
char *copy, *string, *next;
|
||||
|
||||
if (*s == '\0')
|
||||
return (NULL);
|
||||
|
||||
menu = xcalloc(1, sizeof *menu);
|
||||
menu->title = xstrdup(title);
|
||||
|
||||
copy = string = xstrdup(s);
|
||||
do {
|
||||
next = (char *)format_skip(string, "|");
|
||||
log_debug("XXX %s -- %s", next, string);
|
||||
if (next != NULL)
|
||||
*next++ = '\0';
|
||||
if (*string == '\0')
|
||||
menu_add_item(menu, NULL, c, fs);
|
||||
else
|
||||
menu_parse_item(menu, string, c, fs);
|
||||
string = next;
|
||||
} while (next != NULL);
|
||||
free(copy);
|
||||
|
||||
return (menu);
|
||||
}
|
||||
|
||||
void
|
||||
menu_free(struct menu *menu)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < menu->count; i++) {
|
||||
free(menu->items[i].name);
|
||||
free(menu->items[i].command);
|
||||
}
|
||||
free(menu->items);
|
||||
|
||||
free(menu->title);
|
||||
free(menu);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
|
||||
{
|
||||
struct menu_data *md = c->overlay_data;
|
||||
struct tty *tty = &c->tty;
|
||||
struct screen *s = &md->s;
|
||||
struct menu *menu = md->menu;
|
||||
struct screen_write_ctx ctx;
|
||||
u_int i, px, py;
|
||||
|
||||
screen_write_start(&ctx, NULL, s);
|
||||
screen_write_clearscreen(&ctx, 8);
|
||||
screen_write_menu(&ctx, menu, md->choice);
|
||||
screen_write_stop(&ctx);
|
||||
|
||||
px = md->px;
|
||||
py = md->py;
|
||||
|
||||
for (i = 0; i < screen_size_y(&md->s); i++)
|
||||
tty_draw_line(tty, NULL, s, 0, i, menu->width + 4, px, py + i);
|
||||
|
||||
if (~md->flags & MENU_NOMOUSE)
|
||||
tty_update_mode(tty, MODE_MOUSE_ALL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_free_cb(struct client *c)
|
||||
{
|
||||
struct menu_data *md = c->overlay_data;
|
||||
|
||||
if (md->item != NULL)
|
||||
md->item->flags &= ~CMDQ_WAITING;
|
||||
|
||||
screen_free(&md->s);
|
||||
menu_free(md->menu);
|
||||
free(md);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
menu_error_cb(struct cmdq_item *item, void *data)
|
||||
{
|
||||
char *error = data;
|
||||
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static int
|
||||
menu_key_cb(struct client *c, struct key_event *event)
|
||||
{
|
||||
struct menu_data *md = c->overlay_data;
|
||||
struct menu *menu = md->menu;
|
||||
struct mouse_event *m = &event->m;
|
||||
u_int i;
|
||||
int count = menu->count, old = md->choice;
|
||||
const struct menu_item *item;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmdq_item *new_item;
|
||||
char *cause;
|
||||
|
||||
if (KEYC_IS_MOUSE(event->key)) {
|
||||
if (md->flags & MENU_NOMOUSE)
|
||||
return (0);
|
||||
if (m->x < md->px ||
|
||||
m->x > md->px + 4 + menu->width ||
|
||||
m->y < md->py + 1 ||
|
||||
m->y > md->py + 1 + count - 1) {
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
return (1);
|
||||
if (md->choice != -1) {
|
||||
md->choice = -1;
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
md->choice = m->y - (md->py + 1);
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
goto chosen;
|
||||
if (md->choice != old)
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
return (0);
|
||||
}
|
||||
switch (event->key) {
|
||||
case KEYC_UP:
|
||||
do {
|
||||
if (md->choice == -1 || md->choice == 0)
|
||||
md->choice = count - 1;
|
||||
else
|
||||
md->choice--;
|
||||
} while (menu->items[md->choice].name == NULL);
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
return (0);
|
||||
case KEYC_DOWN:
|
||||
do {
|
||||
if (md->choice == -1 || md->choice == count - 1)
|
||||
md->choice = 0;
|
||||
else
|
||||
md->choice++;
|
||||
} while (menu->items[md->choice].name == NULL);
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
return (0);
|
||||
case '\r':
|
||||
goto chosen;
|
||||
case '\033': /* Escape */
|
||||
case '\003': /* C-c */
|
||||
case '\007': /* C-g */
|
||||
case 'q':
|
||||
return (1);
|
||||
}
|
||||
for (i = 0; i < (u_int)count; i++) {
|
||||
if (event->key == menu->items[i].key) {
|
||||
md->choice = i;
|
||||
goto chosen;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
|
||||
chosen:
|
||||
if (md->choice == -1)
|
||||
return (1);
|
||||
item = &menu->items[md->choice];
|
||||
if (item->name == NULL)
|
||||
return (1);
|
||||
if (md->cb != NULL) {
|
||||
md->cb(md->menu, md->choice, item->key, md->data);
|
||||
return (1);
|
||||
}
|
||||
cmdlist = cmd_string_parse(item->command, NULL, 0, &cause);
|
||||
if (cmdlist == NULL && cause != NULL)
|
||||
new_item = cmdq_get_callback(menu_error_cb, cause);
|
||||
else if (cmdlist == NULL)
|
||||
new_item = NULL;
|
||||
else {
|
||||
new_item = cmdq_get_command(cmdlist, &md->fs, NULL, 0);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
if (new_item != NULL) {
|
||||
if (md->item != NULL)
|
||||
cmdq_insert_after(md->item, new_item);
|
||||
else
|
||||
cmdq_append(c, new_item);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct menu_data *md;
|
||||
|
||||
if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
|
||||
return (-1);
|
||||
|
||||
md = xcalloc(1, sizeof *md);
|
||||
md->item = item;
|
||||
md->flags = flags;
|
||||
|
||||
cmd_find_copy_state(&md->fs, fs);
|
||||
screen_init(&md->s, menu->width + 4, menu->count + 2, 0);
|
||||
|
||||
md->px = px;
|
||||
md->py = py;
|
||||
|
||||
md->menu = menu;
|
||||
md->choice = -1;
|
||||
|
||||
md->cb = cb;
|
||||
md->data = data;
|
||||
|
||||
server_client_set_overlay(c, 0, menu_draw_cb, menu_key_cb, menu_free_cb,
|
||||
md);
|
||||
return (0);
|
||||
}
|
92
tmux.1
92
tmux.1
@ -3914,12 +3914,13 @@ The following variables are available, where appropriate:
|
||||
.It Li "buffer_sample" Ta "" Ta "Sample of start of buffer"
|
||||
.It Li "buffer_size" Ta "" Ta "Size of the specified buffer in bytes"
|
||||
.It Li "client_activity" Ta "" Ta "Time client last had activity"
|
||||
.It Li "client_created" Ta "" Ta "Time client created"
|
||||
.It Li "client_control_mode" Ta "" Ta "1 if client is in control mode"
|
||||
.It Li "client_created" Ta "" Ta "Time client created"
|
||||
.It Li "client_discarded" Ta "" Ta "Bytes discarded when client behind"
|
||||
.It Li "client_height" Ta "" Ta "Height of client"
|
||||
.It Li "client_key_table" Ta "" Ta "Current key table"
|
||||
.It Li "client_last_session" Ta "" Ta "Name of the client's last session"
|
||||
.It Li "client_menu" Ta "" Ta "The default client menu"
|
||||
.It Li "client_name" Ta "" Ta "Name of client"
|
||||
.It Li "client_pid" Ta "" Ta "PID of client process"
|
||||
.It Li "client_prefix" Ta "" Ta "1 if prefix key has been pressed"
|
||||
@ -3932,11 +3933,11 @@ The following variables are available, where appropriate:
|
||||
.It Li "client_width" Ta "" Ta "Width of client"
|
||||
.It Li "client_written" Ta "" Ta "Bytes written to client"
|
||||
.It Li "command" Ta "" Ta "Name of command in use, if any"
|
||||
.It Li "command_list_name" Ta "" Ta "Command name if listing commands"
|
||||
.It Li "command_list_alias" Ta "" Ta "Command alias if listing commands"
|
||||
.It Li "command_list_name" Ta "" Ta "Command name if listing commands"
|
||||
.It Li "command_list_usage" Ta "" Ta "Command usage if listing commands"
|
||||
.It Li "cursor_flag" Ta "" Ta "Pane cursor flag"
|
||||
.It Li "cursor_character" Ta "" Ta "Character at cursor in pane"
|
||||
.It Li "cursor_flag" Ta "" Ta "Pane cursor flag"
|
||||
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane"
|
||||
.It Li "cursor_y" Ta "" Ta "Cursor Y position in pane"
|
||||
.It Li "history_bytes" Ta "" Ta "Number of bytes in window history"
|
||||
@ -3954,10 +3955,10 @@ The following variables are available, where appropriate:
|
||||
.It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag"
|
||||
.It Li "keypad_flag" Ta "" Ta "Pane keypad flag"
|
||||
.It Li "line" Ta "" Ta "Line number in the list"
|
||||
.It Li "mouse_all_flag" Ta "" Ta "Pane mouse all flag"
|
||||
.It Li "mouse_any_flag" Ta "" Ta "Pane mouse any flag"
|
||||
.It Li "mouse_button_flag" Ta "" Ta "Pane mouse button flag"
|
||||
.It Li "mouse_standard_flag" Ta "" Ta "Pane mouse standard flag"
|
||||
.It Li "mouse_all_flag" Ta "" Ta "Pane mouse all flag"
|
||||
.It Li "pane_active" Ta "" Ta "1 if active pane"
|
||||
.It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window"
|
||||
.It Li "pane_at_left" Ta "" Ta "1 if pane is at the left of window"
|
||||
@ -3972,11 +3973,12 @@ The following variables are available, where appropriate:
|
||||
.It Li "pane_height" Ta "" Ta "Height of pane"
|
||||
.It Li "pane_id" Ta "#D" Ta "Unique pane ID"
|
||||
.It Li "pane_in_mode" Ta "" Ta "If pane is in a mode"
|
||||
.It Li "pane_input_off" Ta "" Ta "If input to pane is disabled"
|
||||
.It Li "pane_index" Ta "#P" Ta "Index of pane"
|
||||
.It Li "pane_input_off" Ta "" Ta "If input to pane is disabled"
|
||||
.It Li "pane_left" Ta "" Ta "Left of pane"
|
||||
.It Li "pane_marked" Ta " Ta "1 if this is the marked pane"
|
||||
.It Li "pane_marked_set" Ta " Ta "1 if a market pane is set"
|
||||
.It Li "pane_menu" Ta "" Ta "The default pane menu"
|
||||
.It Li "pane_mode" Ta "" Ta "Name of pane mode, if any."
|
||||
.It Li "pane_pid" Ta "" Ta "PID of first process in pane"
|
||||
.It Li "pane_pipe" Ta "" Ta "1 if pane is being piped"
|
||||
@ -3991,31 +3993,32 @@ The following variables are available, where appropriate:
|
||||
.It Li "pane_width" Ta "" Ta "Width of pane"
|
||||
.It Li "pid" Ta "" Ta "Server PID"
|
||||
.It Li "rectangle_toggle" Ta "" Ta "1 if rectangle selection is activated"
|
||||
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
|
||||
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
|
||||
.It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane"
|
||||
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
|
||||
.It Li "selection_present" Ta "" Ta "1 if selection started in copy mode"
|
||||
.It Li "session_activity" Ta "" Ta "Time of session last activity"
|
||||
.It Li "session_alerts" Ta "" Ta "List of window indexes with alerts"
|
||||
.It Li "session_attached" Ta "" Ta "Number of clients session is attached to"
|
||||
.It Li "session_activity" Ta "" Ta "Time of session last activity"
|
||||
.It Li "session_created" Ta "" Ta "Time session created"
|
||||
.It Li "session_format" Ta "" Ta "1 if format is for a session (not assuming the current)"
|
||||
.It Li "session_last_attached" Ta "" Ta "Time session last attached"
|
||||
.It Li "session_group" Ta "" Ta "Name of session group"
|
||||
.It Li "session_group_size" Ta "" Ta "Size of session group"
|
||||
.It Li "session_group_list" Ta "" Ta "List of sessions in group"
|
||||
.It Li "session_group_size" Ta "" Ta "Size of session group"
|
||||
.It Li "session_grouped" Ta "" Ta "1 if session in a group"
|
||||
.It Li "session_id" Ta "" Ta "Unique session ID"
|
||||
.It Li "session_last_attached" Ta "" Ta "Time session last attached"
|
||||
.It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached"
|
||||
.It Li "session_menu" Ta "" Ta "The default session menu"
|
||||
.It Li "session_name" Ta "#S" Ta "Name of session"
|
||||
.It Li "session_stack" Ta "" Ta "Window indexes in most recent order"
|
||||
.It Li "session_windows" Ta "" Ta "Number of windows in session"
|
||||
.It Li "socket_path" Ta "" Ta "Server socket path"
|
||||
.It Li "start_time" Ta "" Ta "Server start time"
|
||||
.It Li "version" Ta "" Ta "Server version"
|
||||
.It Li "window_active" Ta "" Ta "1 if window active"
|
||||
.It Li "window_activity" Ta "" Ta "Time of window last activity"
|
||||
.It Li "window_activity_flag" Ta "" Ta "1 if window has activity"
|
||||
.It Li "window_active" Ta "" Ta "1 if window active"
|
||||
.It Li "window_bell_flag" Ta "" Ta "1 if window has bell"
|
||||
.It Li "window_bigger" Ta "" Ta "1 if window is larger than client"
|
||||
.It Li "window_end_flag" Ta "" Ta "1 if window has the highest index"
|
||||
@ -4027,6 +4030,7 @@ The following variables are available, where appropriate:
|
||||
.It Li "window_last_flag" Ta "" Ta "1 if window is the last used"
|
||||
.It Li "window_layout" Ta "" Ta "Window layout description, ignoring zoomed window panes"
|
||||
.It Li "window_linked" Ta "" Ta "1 if window is linked across sessions"
|
||||
.It Li "window_menu" Ta "" Ta "The default window menu"
|
||||
.It Li "window_name" Ta "#W" Ta "Name of window"
|
||||
.It Li "window_offset_x" Ta "" Ta "X offset into window if larger than client"
|
||||
.It Li "window_offset_y" Ta "" Ta "Y offset into window if larger than client"
|
||||
@ -4443,6 +4447,74 @@ option.
|
||||
.Pp
|
||||
This command works only from inside
|
||||
.Nm .
|
||||
.It Xo Ic display-menu
|
||||
.Op Fl F
|
||||
.Op Fl c Ar target-client
|
||||
.Op Fl M Ar menu
|
||||
.Op Fl t Ar target-pane
|
||||
.Op Fl T Ar title
|
||||
.Op Fl x Ar position
|
||||
.Op Fl y Ar position
|
||||
.Xc
|
||||
.D1 (alias: Ic menu)
|
||||
Display a menu on
|
||||
.Ar target-client .
|
||||
.Ar target-pane
|
||||
gives the target for any commands run from the menu.
|
||||
.Pp
|
||||
A menu is passed to
|
||||
.Fl M
|
||||
as a list of menu items separated by
|
||||
.Ql | .
|
||||
Each menu item consists of three comma-separated parts:
|
||||
.Bl -enum -width Ds
|
||||
.It name
|
||||
The menu item name.
|
||||
This is a format and may include embedded styles, see the
|
||||
.Sx FORMATS
|
||||
and
|
||||
.Sx STYLES
|
||||
sections.
|
||||
.It key
|
||||
The menu item shortcut key.
|
||||
If this is empty the menu item has no key shortcut.
|
||||
.It command
|
||||
The command run when the menu item is chosen.
|
||||
.El
|
||||
.Pp
|
||||
An empty menu item is a separator line.
|
||||
.Pp
|
||||
.Fl T
|
||||
is a format for the menu title (see
|
||||
.Sx FORMATS ) .
|
||||
.Pp
|
||||
.Fl x
|
||||
and
|
||||
.Fl y
|
||||
give the position of the menu.
|
||||
Both may be a row or column number, or one of the following special values:
|
||||
.Bl -column "XXXXX" "XXXX" -offset indent
|
||||
.It Sy "Value" Ta Sy "Flag" Ta Sy "Meaning"
|
||||
.It Li "R" Ta Fl x Ta "The right side of the terminal"
|
||||
.It Li "P" Ta "Both" Ta "The bottom left of the pane"
|
||||
.It Li "M" Ta "Both" Ta "The mouse position"
|
||||
.It Li "W" Ta Fl x Ta "The window position on the status line"
|
||||
.It Li "S" Ta Fl y Ta "The line above or below the status line"
|
||||
.El
|
||||
.Pp
|
||||
Each menu consists of items followed by a key shortcut shown in brackets.
|
||||
If the menu is too large to fit on the terminal, it is not displayed.
|
||||
Pressing the key shortcut chooses the corresponding item.
|
||||
If the mouse is enabled and the menu is opened from a mouse key binding, releasing
|
||||
the mouse button with an item selected will choose that item.
|
||||
The following keys are also available:
|
||||
.Bl -column "Key" "Function" -offset indent
|
||||
.It Sy "Key" Ta Sy "Function"
|
||||
.It Li "Enter" Ta "Choose selected item"
|
||||
.It Li "Up" Ta "Select previous item"
|
||||
.It Li "Down" Ta "Select next item"
|
||||
.It Li "q" Ta "Exit menu"
|
||||
.El
|
||||
.It Xo Ic display-message
|
||||
.Op Fl aIpv
|
||||
.Op Fl c Ar target-client
|
||||
|
24
tmux.h
24
tmux.h
@ -750,20 +750,20 @@ struct screen_redraw_ctx {
|
||||
#define screen_hsize(s) ((s)->grid->hsize)
|
||||
#define screen_hlimit(s) ((s)->grid->hlimit)
|
||||
|
||||
/* Menu item. */
|
||||
struct menu_item {
|
||||
char *name;
|
||||
char *command;
|
||||
key_code key;
|
||||
};
|
||||
|
||||
/* Menu. */
|
||||
struct menu_item {
|
||||
char *name;
|
||||
char *command;
|
||||
key_code key;
|
||||
};
|
||||
struct menu {
|
||||
char *title;
|
||||
struct menu_item *items;
|
||||
u_int count;
|
||||
u_int width;
|
||||
};
|
||||
typedef void (*menu_choice_cb)(struct menu *, u_int, key_code, void *);
|
||||
#define MENU_NOMOUSE 0x1
|
||||
|
||||
/*
|
||||
* Window mode. Windows can be in several modes and this is used to call the
|
||||
@ -2554,6 +2554,16 @@ void printflike(1, 2) log_debug(const char *, ...);
|
||||
__dead void printflike(1, 2) fatal(const char *, ...);
|
||||
__dead void printflike(1, 2) fatalx(const char *, ...);
|
||||
|
||||
/* menu.c */
|
||||
struct menu *menu_create_from_items(struct menu_item *, u_int,
|
||||
struct client *, struct cmd_find_state *, const char *);
|
||||
struct menu *menu_create_from_string(const char *, struct client *,
|
||||
struct cmd_find_state *, const char *);
|
||||
void menu_free(struct menu *);
|
||||
int menu_display(struct menu *, int, struct cmdq_item *, u_int,
|
||||
u_int, struct client *, struct cmd_find_state *,
|
||||
menu_choice_cb, void *);
|
||||
|
||||
/* style.c */
|
||||
int style_parse(struct style *,const struct grid_cell *,
|
||||
const char *);
|
||||
|
Loading…
Reference in New Issue
Block a user