mirror of
https://github.com/tmux/tmux.git
synced 2026-07-04 09:34:45 +00:00
Major rework of prompts. The basic prompt mechanics (draw, editing, etc)
are now wrapped up in prompt*.c and do not depend on a client. These functions are used to provide the original client prompt but also to allow panes to have their own prompts, which works much much better for floating panes. The mode prompts for both the tree modes and copy mode are switched over to be per pane. There are some visible changes (some of these may be changed if they don't seem to be working well): - Prompts in modes now appear in the bottom line, covering whatever content was there. - command-prompt has a -P flag to open a pane prompt. - Because they cover the content, the default style for prompts in modes now does not fill the entire line; the main command prompt stays the same. - The old completion menu has gone, and completions are now shown after the text. Builtin aliases are no longer completed. - Clicking the mouse on the prompt now moves the cursor or selects a completion.
This commit is contained in:
2
Makefile
2
Makefile
@@ -102,6 +102,8 @@ SRCS= alerts.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
procname.c \
|
||||
prompt.c \
|
||||
prompt-history.c \
|
||||
regsub.c \
|
||||
resize.c \
|
||||
screen-redraw.c \
|
||||
|
||||
2
cfg.c
2
cfg.c
@@ -57,7 +57,7 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
|
||||
if (cfg_item != NULL)
|
||||
cmdq_continue(cfg_item);
|
||||
|
||||
status_prompt_load_history();
|
||||
prompt_load_history();
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ const struct cmd_entry cmd_command_prompt_entry = {
|
||||
.name = "command-prompt",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "1CbeFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||
.usage = "[-1CbeFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||
.args = { "1CbeFiklI:NPp:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||
.usage = "[-1CbeFiklNP] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||
" [-T prompt-type] [template]",
|
||||
|
||||
.flags = CMD_CLIENT_TFLAG,
|
||||
@@ -62,6 +62,8 @@ struct cmd_command_prompt_cdata {
|
||||
int flags;
|
||||
enum prompt_type prompt_type;
|
||||
|
||||
struct window_pane *wp;
|
||||
|
||||
struct cmd_command_prompt_prompt *prompts;
|
||||
u_int count;
|
||||
u_int current;
|
||||
@@ -87,10 +89,15 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_command_prompt_cdata *cdata;
|
||||
char *tmp, *prompts, *prompt, *next_prompt;
|
||||
char *inputs = NULL, *next_input;
|
||||
struct window_pane *wp = target->wp;
|
||||
u_int count = args_count(args);
|
||||
int wait = !args_has(args, 'b'), space = 1;
|
||||
int pane = args_has(args, 'P');
|
||||
|
||||
if (tc->prompt_string != NULL)
|
||||
if (pane) {
|
||||
if (wp == NULL || window_pane_has_prompt(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
} else if (tc->prompt != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (args_has(args, 'i'))
|
||||
wait = 0;
|
||||
@@ -98,6 +105,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
if (wait)
|
||||
cdata->item = item;
|
||||
if (pane)
|
||||
cdata->wp = wp;
|
||||
cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait,
|
||||
args_has(args, 'F'));
|
||||
|
||||
@@ -146,7 +155,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
if ((type = args_get(args, 'T')) != NULL) {
|
||||
cdata->prompt_type = status_prompt_type(type);
|
||||
cdata->prompt_type = prompt_type(type);
|
||||
if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "unknown type: %s", type);
|
||||
cmd_command_prompt_free(cdata);
|
||||
@@ -167,9 +176,18 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cdata->flags |= PROMPT_BSPACE_EXIT;
|
||||
if (args_has(args, 'C'))
|
||||
cdata->flags |= PROMPT_NOFREEZE;
|
||||
status_prompt_set(tc, target, cdata->prompts[0].prompt,
|
||||
cdata->prompts[0].input, cmd_command_prompt_callback,
|
||||
cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type);
|
||||
if (pane) {
|
||||
cdata->flags |= PROMPT_ISPANE;
|
||||
window_pane_set_prompt(wp, tc, target, cdata->prompts[0].prompt,
|
||||
cdata->prompts[0].input, cmd_command_prompt_callback,
|
||||
cmd_command_prompt_free, cdata, cdata->flags,
|
||||
cdata->prompt_type);
|
||||
} else {
|
||||
status_prompt_set(tc, target, cdata->prompts[0].prompt,
|
||||
cdata->prompts[0].input, cmd_command_prompt_callback,
|
||||
cmd_command_prompt_free, cdata, cdata->flags,
|
||||
cdata->prompt_type);
|
||||
}
|
||||
|
||||
if (!wait)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -197,7 +215,12 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
||||
cmd_append_argv(&cdata->argc, &cdata->argv, s);
|
||||
if (++cdata->current != cdata->count) {
|
||||
prompt = &cdata->prompts[cdata->current];
|
||||
status_prompt_update(c, prompt->prompt, prompt->input);
|
||||
if (cdata->wp != NULL) {
|
||||
window_pane_update_prompt(cdata->wp,
|
||||
prompt->prompt, prompt->input);
|
||||
} else
|
||||
status_prompt_update(c, prompt->prompt,
|
||||
prompt->input);
|
||||
return (PROMPT_CONTINUE);
|
||||
}
|
||||
}
|
||||
@@ -225,12 +248,19 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
||||
}
|
||||
cmd_free_argv(argc, argv);
|
||||
|
||||
if (c->prompt_inputcb != cmd_command_prompt_callback)
|
||||
/*
|
||||
* An incremental prompt fires its callback on every edit but must stay
|
||||
* open for further typing; only an explicit close (handled above) ends
|
||||
* it.
|
||||
*/
|
||||
if (cdata->flags & PROMPT_INCREMENTAL)
|
||||
return (PROMPT_CONTINUE);
|
||||
|
||||
out:
|
||||
if (item != NULL)
|
||||
if (item != NULL) {
|
||||
cdata->item = NULL;
|
||||
cmdq_continue(item);
|
||||
}
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
@@ -240,6 +270,11 @@ cmd_command_prompt_free(void *data)
|
||||
struct cmd_command_prompt_cdata *cdata = data;
|
||||
u_int i;
|
||||
|
||||
if (cdata->item != NULL) {
|
||||
cmdq_continue(cdata->item);
|
||||
cdata->item = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < cdata->count; i++) {
|
||||
free(cdata->prompts[i].prompt);
|
||||
free(cdata->prompts[i].input);
|
||||
|
||||
@@ -279,7 +279,7 @@ cmd_display_panes_draw(struct client *c, __unused void *data)
|
||||
tty_window_offset(&c->tty, &ctx.ox, &ctx.oy, &ctx.sx, &ctx.sy);
|
||||
if (options_get_number(s->options, "status-position") == 0) {
|
||||
lines = status_line_size(c);
|
||||
if (c->message_string != NULL || c->prompt_string != NULL)
|
||||
if (c->message_string != NULL || c->prompt != NULL)
|
||||
lines = (lines == 0 ? 1 : lines);
|
||||
ctx.statuslines = lines;
|
||||
ctx.statustop = 1;
|
||||
|
||||
@@ -55,56 +55,44 @@ cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
const char *typestr = args_get(args, 'T');
|
||||
enum prompt_type type;
|
||||
u_int tidx, hidx;
|
||||
u_int t, h;
|
||||
const char *v;
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
|
||||
if (typestr == NULL) {
|
||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
||||
for (hidx = 0; hidx < status_prompt_hsize[tidx];
|
||||
hidx++)
|
||||
free(status_prompt_hlist[tidx][hidx]);
|
||||
free(status_prompt_hlist[tidx]);
|
||||
status_prompt_hlist[tidx] = NULL;
|
||||
status_prompt_hsize[tidx] = 0;
|
||||
}
|
||||
for (t = 0; t < PROMPT_NTYPES; t++)
|
||||
prompt_history_clear(t);
|
||||
} else {
|
||||
type = status_prompt_type(typestr);
|
||||
type = prompt_type(typestr);
|
||||
if (type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "invalid type: %s", typestr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++)
|
||||
free(status_prompt_hlist[type][hidx]);
|
||||
free(status_prompt_hlist[type]);
|
||||
status_prompt_hlist[type] = NULL;
|
||||
status_prompt_hsize[type] = 0;
|
||||
prompt_history_clear(type);
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (typestr == NULL) {
|
||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
||||
cmdq_print(item, "History for %s:\n",
|
||||
status_prompt_type_string(tidx));
|
||||
for (hidx = 0; hidx < status_prompt_hsize[tidx];
|
||||
hidx++) {
|
||||
cmdq_print(item, "%d: %s", hidx + 1,
|
||||
status_prompt_hlist[tidx][hidx]);
|
||||
for (t = 0; t < PROMPT_NTYPES; t++) {
|
||||
typestr = prompt_type_string(t);
|
||||
cmdq_print(item, "History for %s:\n", typestr);
|
||||
for (h = 0; h < prompt_history_size(t); h++) {
|
||||
v = prompt_history_get(t, h);
|
||||
cmdq_print(item, "%d: %s", h + 1, v);
|
||||
}
|
||||
cmdq_print(item, "%s", "");
|
||||
}
|
||||
} else {
|
||||
type = status_prompt_type(typestr);
|
||||
type = prompt_type(typestr);
|
||||
if (type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "invalid type: %s", typestr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
cmdq_print(item, "History for %s:\n",
|
||||
status_prompt_type_string(type));
|
||||
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++) {
|
||||
cmdq_print(item, "%d: %s", hidx + 1,
|
||||
status_prompt_hlist[type][hidx]);
|
||||
cmdq_print(item, "History for %s:\n", prompt_type_string(type));
|
||||
for (h = 0; h < prompt_history_size(type); h++) {
|
||||
v = prompt_history_get(type, h);
|
||||
cmdq_print(item, "%d: %s", h + 1, v);
|
||||
}
|
||||
cmdq_print(item, "%s", "");
|
||||
}
|
||||
|
||||
@@ -514,8 +514,8 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode M-l { send -X cursor-centre-horizontal }",
|
||||
"bind -Tcopy-mode C-n { send -X cursor-down }",
|
||||
"bind -Tcopy-mode C-p { send -X cursor-up }",
|
||||
"bind -Tcopy-mode C-r { command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental -- '%%' } }",
|
||||
"bind -Tcopy-mode C-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental -- '%%' } }",
|
||||
"bind -Tcopy-mode C-r { command-prompt -P -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental -- '%%' } }",
|
||||
"bind -Tcopy-mode C-s { command-prompt -P -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental -- '%%' } }",
|
||||
"bind -Tcopy-mode C-v { send -X page-down }",
|
||||
"bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }",
|
||||
"bind -Tcopy-mode Escape { send -X cancel }",
|
||||
@@ -523,18 +523,18 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode Space { send -X page-down }",
|
||||
"bind -Tcopy-mode , { send -X jump-reverse }",
|
||||
"bind -Tcopy-mode \\; { send -X jump-again }",
|
||||
"bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode F { command-prompt -P -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode N { send -X search-reverse }",
|
||||
"bind -Tcopy-mode P { send -X toggle-position }",
|
||||
"bind -Tcopy-mode R { send -X rectangle-toggle }",
|
||||
"bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode T { command-prompt -P -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode X { send -X set-mark }",
|
||||
"bind -Tcopy-mode f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||
"bind -Tcopy-mode f { command-prompt -P -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode g { command-prompt -P -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||
"bind -Tcopy-mode n { send -X search-again }",
|
||||
"bind -Tcopy-mode q { send -X cancel }",
|
||||
"bind -Tcopy-mode r { send -X refresh-toggle }",
|
||||
"bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode t { command-prompt -P -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode Home { send -X start-of-line }",
|
||||
"bind -Tcopy-mode End { send -X end-of-line }",
|
||||
"bind -Tcopy-mode MouseDown1Pane select-pane",
|
||||
@@ -550,15 +550,15 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode Down { send -X cursor-down }",
|
||||
"bind -Tcopy-mode Left { send -X cursor-left }",
|
||||
"bind -Tcopy-mode Right { send -X cursor-right }",
|
||||
"bind -Tcopy-mode M-1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-3 { command-prompt -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-5 { command-prompt -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-1 { command-prompt -P -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-2 { command-prompt -P -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-3 { command-prompt -P -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-4 { command-prompt -P -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-5 { command-prompt -P -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-6 { command-prompt -P -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-7 { command-prompt -P -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-8 { command-prompt -P -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-9 { command-prompt -P -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-< { send -X history-top }",
|
||||
"bind -Tcopy-mode M-> { send -X history-bottom }",
|
||||
"bind -Tcopy-mode M-R { send -X top-line }",
|
||||
@@ -599,25 +599,25 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi Space { send -X begin-selection }",
|
||||
"bind -Tcopy-mode-vi '$' { send -X end-of-line }",
|
||||
"bind -Tcopy-mode-vi , { send -X jump-reverse }",
|
||||
"bind -Tcopy-mode-vi / { command-prompt -T search -p'(search down)' { send -X search-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi / { command-prompt -P -T search -p'(search down)' { send -X search-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi 0 { send -X start-of-line }",
|
||||
"bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 3 { command-prompt -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 5 { command-prompt -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi 1 { command-prompt -P -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 2 { command-prompt -P -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 3 { command-prompt -P -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 4 { command-prompt -P -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 5 { command-prompt -P -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 6 { command-prompt -P -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 7 { command-prompt -P -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 8 { command-prompt -P -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 9 { command-prompt -P -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi : { command-prompt -P -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi \\; { send -X jump-again }",
|
||||
"bind -Tcopy-mode-vi ? { command-prompt -T search -p'(search up)' { send -X search-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi ? { command-prompt -P -T search -p'(search up)' { send -X search-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi A { send -X append-selection-and-cancel }",
|
||||
"bind -Tcopy-mode-vi B { send -X previous-space }",
|
||||
"bind -Tcopy-mode-vi D { send -X copy-pipe-end-of-line-and-cancel }",
|
||||
"bind -Tcopy-mode-vi E { send -X next-space-end }",
|
||||
"bind -Tcopy-mode-vi F { command-prompt -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi F { command-prompt -P -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi G { send -X history-bottom }",
|
||||
"bind -Tcopy-mode-vi H { send -X top-line }",
|
||||
"bind -Tcopy-mode-vi J { send -X scroll-down }",
|
||||
@@ -626,14 +626,14 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi M { send -X middle-line }",
|
||||
"bind -Tcopy-mode-vi N { send -X search-reverse }",
|
||||
"bind -Tcopy-mode-vi P { send -X toggle-position }",
|
||||
"bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi T { command-prompt -P -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi V { send -X select-line }",
|
||||
"bind -Tcopy-mode-vi W { send -X next-space }",
|
||||
"bind -Tcopy-mode-vi X { send -X set-mark }",
|
||||
"bind -Tcopy-mode-vi ^ { send -X back-to-indentation }",
|
||||
"bind -Tcopy-mode-vi b { send -X previous-word }",
|
||||
"bind -Tcopy-mode-vi e { send -X next-word-end }",
|
||||
"bind -Tcopy-mode-vi f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi f { command-prompt -P -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi g { send -X history-top }",
|
||||
"bind -Tcopy-mode-vi h { send -X cursor-left }",
|
||||
"bind -Tcopy-mode-vi j { send -X cursor-down }",
|
||||
@@ -644,7 +644,7 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi o { send -X other-end }",
|
||||
"bind -Tcopy-mode-vi q { send -X cancel }",
|
||||
"bind -Tcopy-mode-vi r { send -X refresh-toggle }",
|
||||
"bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi t { command-prompt -P -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi v { send -X rectangle-toggle }",
|
||||
"bind -Tcopy-mode-vi w { send -X next-word }",
|
||||
"bind -Tcopy-mode-vi '{' { send -X previous-paragraph }",
|
||||
|
||||
261
mode-tree.c
261
mode-tree.c
@@ -37,6 +37,7 @@ enum mode_tree_preview {
|
||||
};
|
||||
|
||||
struct mode_tree_item;
|
||||
struct mode_tree_prompt;
|
||||
TAILQ_HEAD(mode_tree_list, mode_tree_item);
|
||||
|
||||
struct mode_tree_data {
|
||||
@@ -51,11 +52,11 @@ struct mode_tree_data {
|
||||
struct sort_criteria sort_crit;
|
||||
const char *view_name;
|
||||
|
||||
mode_tree_build_cb buildcb;
|
||||
mode_tree_draw_cb drawcb;
|
||||
mode_tree_search_cb searchcb;
|
||||
mode_tree_menu_cb menucb;
|
||||
mode_tree_height_cb heightcb;
|
||||
mode_tree_build_cb buildcb;
|
||||
mode_tree_draw_cb drawcb;
|
||||
mode_tree_search_cb searchcb;
|
||||
mode_tree_menu_cb menucb;
|
||||
mode_tree_height_cb heightcb;
|
||||
mode_tree_key_cb keycb;
|
||||
mode_tree_swap_cb swapcb;
|
||||
mode_tree_sort_cb sortcb;
|
||||
@@ -77,6 +78,10 @@ struct mode_tree_data {
|
||||
u_int current;
|
||||
|
||||
struct screen screen;
|
||||
struct prompt *prompt;
|
||||
struct mode_tree_prompt *prompt_data;
|
||||
u_int prompt_cx;
|
||||
int prompt_top;
|
||||
|
||||
int preview;
|
||||
char *search;
|
||||
@@ -124,9 +129,25 @@ struct mode_tree_menu {
|
||||
u_int line;
|
||||
};
|
||||
|
||||
static void mode_tree_free_items(struct mode_tree_list *);
|
||||
static void mode_tree_draw_help(struct mode_tree_data *,
|
||||
struct screen_write_ctx *);
|
||||
/*
|
||||
* Wrapper around a prompt owned by a mode tree. The mode tree holds a reference
|
||||
* while the prompt is alive; the wrapper callbacks forward to the caller's
|
||||
* callbacks and drop that reference when the prompt is freed.
|
||||
*/
|
||||
struct mode_tree_prompt {
|
||||
struct mode_tree_data *mtd;
|
||||
struct client *c;
|
||||
mode_tree_prompt_input_cb inputcb;
|
||||
prompt_free_cb freecb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void mode_tree_free_items(struct mode_tree_list *);
|
||||
static void mode_tree_draw_help(struct mode_tree_data *,
|
||||
struct screen_write_ctx *);
|
||||
static void mode_tree_draw_prompt(struct mode_tree_data *,
|
||||
struct screen_write_ctx *);
|
||||
static enum cmd_retval mode_tree_prompt_accept(struct cmdq_item *, void *);
|
||||
|
||||
static const struct menu_item mode_tree_menu_items[] = {
|
||||
{ "Scroll Left", '<', NULL },
|
||||
@@ -650,6 +671,7 @@ mode_tree_free(struct mode_tree_data *mtd)
|
||||
if (mtd->zoomed == 0)
|
||||
server_unzoom_window(wp->window);
|
||||
|
||||
mode_tree_clear_prompt(mtd);
|
||||
mode_tree_free_items(&mtd->children);
|
||||
mode_tree_clear_lines(mtd);
|
||||
screen_free(&mtd->screen);
|
||||
@@ -942,10 +964,148 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
||||
done:
|
||||
if (mtd->help)
|
||||
mode_tree_draw_help(mtd, &ctx);
|
||||
screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0);
|
||||
if (mtd->prompt != NULL)
|
||||
mode_tree_draw_prompt(mtd, &ctx);
|
||||
else {
|
||||
s->mode &= ~MODE_CURSOR;
|
||||
screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0);
|
||||
}
|
||||
screen_write_stop(&ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_tree_draw_prompt(struct mode_tree_data *mtd, struct screen_write_ctx *ctx)
|
||||
{
|
||||
struct screen *s = &mtd->screen;
|
||||
struct prompt_draw_data pdd;
|
||||
u_int sx = screen_size_x(s), sy = screen_size_y(s);
|
||||
u_int py;
|
||||
|
||||
if (sx == 0 || sy == 0)
|
||||
return;
|
||||
|
||||
if (mtd->prompt_top)
|
||||
py = 0;
|
||||
else
|
||||
py = sy - 1;
|
||||
|
||||
pdd.ctx = ctx;
|
||||
pdd.cursor_x = &mtd->prompt_cx;
|
||||
pdd.area_x = 0;
|
||||
pdd.area_width = sx;
|
||||
pdd.prompt_line = py;
|
||||
|
||||
s->mode |= MODE_CURSOR;
|
||||
prompt_draw(mtd->prompt, &pdd);
|
||||
screen_write_cursormove(ctx, mtd->prompt_cx, py, 0);
|
||||
}
|
||||
|
||||
void
|
||||
mode_tree_clear_prompt(struct mode_tree_data *mtd)
|
||||
{
|
||||
struct prompt *prompt = mtd->prompt;
|
||||
|
||||
if (mtd->prompt != NULL) {
|
||||
mtd->prompt = NULL;
|
||||
prompt_free(prompt);
|
||||
mtd->screen.mode &= ~MODE_CURSOR;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mode_tree_has_prompt(struct mode_tree_data *mtd)
|
||||
{
|
||||
return (mtd->prompt != NULL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
mode_tree_prompt_accept(struct cmdq_item *item, void *data)
|
||||
{
|
||||
struct mode_tree_data *mtd = data;
|
||||
struct client *c = cmdq_get_client(item);
|
||||
key_code key = 'y';
|
||||
|
||||
if (mtd->prompt != NULL && c != NULL)
|
||||
mode_tree_key(mtd, c, &key, NULL, NULL, NULL);
|
||||
|
||||
mode_tree_remove_ref(mtd);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum prompt_result
|
||||
mode_tree_prompt_input_callback(void *data, const char *s,
|
||||
enum prompt_key_result key)
|
||||
{
|
||||
struct mode_tree_prompt *mtp = data;
|
||||
|
||||
if (mtp->inputcb != NULL)
|
||||
return (mtp->inputcb(mtp->c, mtp->data, s, key));
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_tree_prompt_free_callback(void *data)
|
||||
{
|
||||
struct mode_tree_prompt *mtp = data;
|
||||
|
||||
if (mtp->mtd->prompt_data == mtp)
|
||||
mtp->mtd->prompt_data = NULL;
|
||||
if (mtp->freecb != NULL)
|
||||
mtp->freecb(mtp->data);
|
||||
mode_tree_remove_ref(mtp->mtd);
|
||||
free(mtp);
|
||||
}
|
||||
|
||||
void
|
||||
mode_tree_set_prompt(struct mode_tree_data *mtd, struct client *c,
|
||||
const char *prompt, const char *input, enum prompt_type type, int flags,
|
||||
mode_tree_prompt_input_cb inputcb, prompt_free_cb freecb, void *data)
|
||||
{
|
||||
struct session *s;
|
||||
struct options *oo;
|
||||
struct prompt_create_data pd;
|
||||
struct mode_tree_prompt *mtp;
|
||||
|
||||
if (c != NULL && c->session != NULL) {
|
||||
s = c->session;
|
||||
oo = s->options;
|
||||
} else {
|
||||
s = NULL;
|
||||
oo = global_s_options;
|
||||
}
|
||||
|
||||
mode_tree_clear_prompt(mtd);
|
||||
|
||||
mtp = xcalloc(1, sizeof *mtp);
|
||||
mtp->mtd = mtd;
|
||||
mtp->inputcb = inputcb;
|
||||
mtp->freecb = freecb;
|
||||
mtp->data = data;
|
||||
|
||||
mtd->references++;
|
||||
mtd->prompt_top = options_get_number(oo, "status-position") == 0;
|
||||
|
||||
memset(&pd, 0, sizeof pd);
|
||||
prompt_set_options(&pd, s);
|
||||
pd.prompt = prompt;
|
||||
pd.input = input;
|
||||
pd.type = type;
|
||||
pd.flags = flags|PROMPT_ISMODE;
|
||||
pd.inputcb = mode_tree_prompt_input_callback;
|
||||
pd.freecb = mode_tree_prompt_free_callback;
|
||||
pd.data = mtp;
|
||||
mtd->prompt = prompt_create(&pd);
|
||||
mtd->prompt_data = mtp;
|
||||
|
||||
mode_tree_draw(mtd);
|
||||
mtd->wp->flags |= PANE_REDRAW;
|
||||
|
||||
if ((flags & PROMPT_SINGLE) && (flags & PROMPT_ACCEPT) && c != NULL) {
|
||||
mtd->references++;
|
||||
cmdq_append(c, cmdq_get_callback(mode_tree_prompt_accept, mtd));
|
||||
}
|
||||
}
|
||||
|
||||
static struct mode_tree_item *
|
||||
mode_tree_search_backward(struct mode_tree_data *mtd)
|
||||
{
|
||||
@@ -1089,12 +1249,6 @@ mode_tree_search_callback(__unused struct client *c, void *data, const char *s,
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_tree_search_free(void *data)
|
||||
{
|
||||
mode_tree_remove_ref(data);
|
||||
}
|
||||
|
||||
static enum prompt_result
|
||||
mode_tree_filter_callback(__unused struct client *c, void *data, const char *s,
|
||||
enum prompt_key_result key)
|
||||
@@ -1120,12 +1274,6 @@ mode_tree_filter_callback(__unused struct client *c, void *data, const char *s,
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_tree_filter_free(void *data)
|
||||
{
|
||||
mode_tree_remove_ref(data);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_tree_clear_filter(struct mode_tree_data *mtd)
|
||||
{
|
||||
@@ -1225,7 +1373,7 @@ mode_tree_draw_help(struct mode_tree_data *mtd, struct screen_write_ctx *ctx)
|
||||
struct grid_cell gc;
|
||||
const char **line, **lines = NULL, *item = "item";
|
||||
u_int sx = screen_size_x(s), sy = screen_size_y(s);
|
||||
u_int x, y, w, h = 0, box_w, box_h;
|
||||
u_int x, y, w, h = 0, box_w, box_h;
|
||||
|
||||
if (mtd->helpcb == NULL)
|
||||
w = MODE_TREE_HELP_DEFAULT_WIDTH;
|
||||
@@ -1275,14 +1423,66 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
{
|
||||
struct mode_tree_line *line;
|
||||
struct mode_tree_item *current, *parent, *mti;
|
||||
u_int i, x, y;
|
||||
u_int i, x, y, py, sx;
|
||||
int choice, preview;
|
||||
enum prompt_key_result result;
|
||||
int redraw;
|
||||
struct prompt *prompt;
|
||||
struct mode_tree_prompt *mtp;
|
||||
|
||||
if (mtd->line_size == 0) {
|
||||
*key = KEYC_NONE;
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (mtd->prompt != NULL) {
|
||||
redraw = 0;
|
||||
prompt = mtd->prompt;
|
||||
|
||||
mtp = mtd->prompt_data;
|
||||
if (mtp != NULL)
|
||||
mtp->c = c;
|
||||
if (KEYC_IS_MOUSE(*key)) {
|
||||
if (m == NULL ||
|
||||
MOUSE_BUTTONS(m->b) != MOUSE_BUTTON_1 ||
|
||||
MOUSE_DRAG(m->b) || MOUSE_RELEASE(m->b) ||
|
||||
cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0)
|
||||
result = PROMPT_KEY_NOT_HANDLED;
|
||||
else {
|
||||
sx = screen_size_x(&mtd->screen);
|
||||
if (mtd->prompt_top)
|
||||
py = 0;
|
||||
else
|
||||
py = screen_size_y(&mtd->screen) - 1;
|
||||
if (y == py) {
|
||||
result = prompt_mouse(prompt, x, 0, sx,
|
||||
&redraw);
|
||||
} else
|
||||
result = PROMPT_KEY_NOT_HANDLED;
|
||||
}
|
||||
} else
|
||||
result = prompt_key(prompt, *key, &redraw);
|
||||
if (mtd->prompt_data == mtp && mtp != NULL)
|
||||
mtp->c = NULL;
|
||||
|
||||
/*
|
||||
* Only an explicit close or the prompt marking itself closed
|
||||
* ends it; cursor movement and editing keep it open.
|
||||
*/
|
||||
if (mtd->prompt == prompt &&
|
||||
(result == PROMPT_KEY_CLOSE || prompt_closed(prompt)))
|
||||
mode_tree_clear_prompt(mtd);
|
||||
|
||||
if (redraw || mtd->prompt != prompt) {
|
||||
mode_tree_draw(mtd);
|
||||
mtd->wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
if (result != PROMPT_KEY_NOT_HANDLED) {
|
||||
*key = KEYC_NONE;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (mtd->help) {
|
||||
if (KEYC_IS_MOUSE(*key)) {
|
||||
*key = KEYC_NONE;
|
||||
@@ -1489,11 +1689,10 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
case '?':
|
||||
case '/':
|
||||
case 's'|KEYC_CTRL:
|
||||
mtd->references++;
|
||||
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
|
||||
status_prompt_set(c, NULL, "(search) ", "",
|
||||
mode_tree_search_callback, mode_tree_search_free, mtd,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
|
||||
mode_tree_set_prompt(mtd, c, "(search) ", "",
|
||||
PROMPT_TYPE_SEARCH, PROMPT_NOFORMAT,
|
||||
mode_tree_search_callback, NULL, mtd);
|
||||
break;
|
||||
case 'n':
|
||||
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
|
||||
@@ -1504,12 +1703,12 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
mode_tree_search_set(mtd);
|
||||
break;
|
||||
case 'f':
|
||||
mtd->references++;
|
||||
status_prompt_set(c, NULL, "(filter) ", mtd->filter,
|
||||
mode_tree_filter_callback, mode_tree_filter_free, mtd,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
|
||||
mode_tree_set_prompt(mtd, c, "(filter) ", mtd->filter,
|
||||
PROMPT_TYPE_SEARCH, PROMPT_NOFORMAT,
|
||||
mode_tree_filter_callback, NULL, mtd);
|
||||
break;
|
||||
case 'c':
|
||||
mode_tree_clear_prompt(mtd);
|
||||
mode_tree_clear_filter(mtd);
|
||||
break;
|
||||
case 'v':
|
||||
|
||||
@@ -764,7 +764,9 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "message-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.default_str = "bg=yellow,fg=black,fill=yellow",
|
||||
.default_str = "bg=yellow,fg=black,"
|
||||
"#{?#{m/r:(^|#,)IS(PANE|MODE)($|#,),#{prompt_flags}},,"
|
||||
"fill=yellow}",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of messages and the command prompt. "
|
||||
|
||||
264
prompt-history.c
Normal file
264
prompt-history.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
static char *prompt_find_history_file(void);
|
||||
static void prompt_add_typed_history(char *);
|
||||
|
||||
/* Prompt history. */
|
||||
static char **prompt_hlist[PROMPT_NTYPES];
|
||||
static u_int prompt_hsize[PROMPT_NTYPES];
|
||||
|
||||
/* Find the history file to load/save from/to. */
|
||||
static char *
|
||||
prompt_find_history_file(void)
|
||||
{
|
||||
const char *home, *history_file;
|
||||
char *path;
|
||||
|
||||
history_file = options_get_string(global_options, "history-file");
|
||||
if (*history_file == '\0')
|
||||
return (NULL);
|
||||
if (*history_file == '/')
|
||||
return (xstrdup(history_file));
|
||||
|
||||
if (history_file[0] != '~' || history_file[1] != '/')
|
||||
return (NULL);
|
||||
if ((home = find_home()) == NULL)
|
||||
return (NULL);
|
||||
xasprintf(&path, "%s%s", home, history_file + 1);
|
||||
return (path);
|
||||
}
|
||||
|
||||
/* Add loaded history item to the appropriate list. */
|
||||
static void
|
||||
prompt_add_typed_history(char *line)
|
||||
{
|
||||
char *typestr;
|
||||
enum prompt_type type = PROMPT_TYPE_INVALID;
|
||||
|
||||
typestr = strsep(&line, ":");
|
||||
if (line != NULL)
|
||||
type = prompt_type(typestr);
|
||||
if (type == PROMPT_TYPE_INVALID) {
|
||||
/*
|
||||
* Invalid types are not expected, but this provides backward
|
||||
* compatibility with old history files.
|
||||
*/
|
||||
if (line != NULL)
|
||||
*(--line) = ':';
|
||||
prompt_add_history(typestr, PROMPT_TYPE_COMMAND);
|
||||
} else
|
||||
prompt_add_history(line, type);
|
||||
}
|
||||
|
||||
/* Load prompt history from file. */
|
||||
void
|
||||
prompt_load_history(void)
|
||||
{
|
||||
FILE *f;
|
||||
char *history_file, *line, *tmp;
|
||||
size_t length;
|
||||
|
||||
if ((history_file = prompt_find_history_file()) == NULL)
|
||||
return;
|
||||
log_debug("loading history from %s", history_file);
|
||||
|
||||
f = fopen(history_file, "r");
|
||||
if (f == NULL) {
|
||||
log_debug("%s: %s", history_file, strerror(errno));
|
||||
free(history_file);
|
||||
return;
|
||||
}
|
||||
free(history_file);
|
||||
|
||||
for (;;) {
|
||||
if ((line = fgetln(f, &length)) == NULL)
|
||||
break;
|
||||
|
||||
if (length > 0) {
|
||||
if (line[length - 1] == '\n') {
|
||||
line[length - 1] = '\0';
|
||||
prompt_add_typed_history(line);
|
||||
} else {
|
||||
tmp = xmalloc(length + 1);
|
||||
memcpy(tmp, line, length);
|
||||
tmp[length] = '\0';
|
||||
prompt_add_typed_history(tmp);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* Save prompt history to file. */
|
||||
void
|
||||
prompt_save_history(void)
|
||||
{
|
||||
FILE *f;
|
||||
u_int i, type;
|
||||
char *history_file;
|
||||
|
||||
if ((history_file = prompt_find_history_file()) == NULL)
|
||||
return;
|
||||
log_debug("saving history to %s", history_file);
|
||||
|
||||
f = fopen(history_file, "w");
|
||||
if (f == NULL) {
|
||||
log_debug("%s: %s", history_file, strerror(errno));
|
||||
free(history_file);
|
||||
return;
|
||||
}
|
||||
free(history_file);
|
||||
|
||||
for (type = 0; type < PROMPT_NTYPES; type++) {
|
||||
for (i = 0; i < prompt_hsize[type]; i++) {
|
||||
fputs(prompt_type_string(type), f);
|
||||
fputc(':', f);
|
||||
fputs(prompt_hlist[type][i], f);
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
/* Get previous line from the history. */
|
||||
const char *
|
||||
prompt_up_history(u_int *idx, u_int type)
|
||||
{
|
||||
/*
|
||||
* History runs from 0 to size - 1. Index is from 0 to size. Zero is
|
||||
* empty.
|
||||
*/
|
||||
|
||||
if (type >= PROMPT_NTYPES)
|
||||
return (NULL);
|
||||
if (prompt_hsize[type] == 0 || idx[type] == prompt_hsize[type])
|
||||
return (NULL);
|
||||
idx[type]++;
|
||||
return (prompt_hlist[type][prompt_hsize[type] - idx[type]]);
|
||||
}
|
||||
|
||||
/* Get next line from the history. */
|
||||
const char *
|
||||
prompt_down_history(u_int *idx, u_int type)
|
||||
{
|
||||
if (type >= PROMPT_NTYPES)
|
||||
return ("");
|
||||
if (prompt_hsize[type] == 0 || idx[type] == 0)
|
||||
return ("");
|
||||
idx[type]--;
|
||||
if (idx[type] == 0)
|
||||
return ("");
|
||||
return (prompt_hlist[type][prompt_hsize[type] - idx[type]]);
|
||||
}
|
||||
|
||||
/* Add line to the history. */
|
||||
void
|
||||
prompt_add_history(const char *line, u_int type)
|
||||
{
|
||||
u_int i, oldsize, newsize, freecount, hlimit, new = 1;
|
||||
size_t movesize;
|
||||
|
||||
if (type >= PROMPT_NTYPES)
|
||||
return;
|
||||
|
||||
oldsize = prompt_hsize[type];
|
||||
if (oldsize > 0 &&
|
||||
strcmp(prompt_hlist[type][oldsize - 1], line) == 0)
|
||||
new = 0;
|
||||
|
||||
hlimit = options_get_number(global_options, "prompt-history-limit");
|
||||
if (hlimit > oldsize) {
|
||||
if (new == 0)
|
||||
return;
|
||||
newsize = oldsize + new;
|
||||
} else {
|
||||
newsize = hlimit;
|
||||
freecount = oldsize + new - newsize;
|
||||
if (freecount > oldsize)
|
||||
freecount = oldsize;
|
||||
if (freecount == 0)
|
||||
return;
|
||||
for (i = 0; i < freecount; i++)
|
||||
free(prompt_hlist[type][i]);
|
||||
movesize = (oldsize - freecount) *
|
||||
sizeof *prompt_hlist[type];
|
||||
if (movesize > 0) {
|
||||
memmove(&prompt_hlist[type][0],
|
||||
&prompt_hlist[type][freecount], movesize);
|
||||
}
|
||||
}
|
||||
|
||||
if (newsize == 0) {
|
||||
free(prompt_hlist[type]);
|
||||
prompt_hlist[type] = NULL;
|
||||
} else if (newsize != oldsize) {
|
||||
prompt_hlist[type] =
|
||||
xreallocarray(prompt_hlist[type], newsize,
|
||||
sizeof *prompt_hlist[type]);
|
||||
}
|
||||
|
||||
if (new == 1 && newsize > 0)
|
||||
prompt_hlist[type][newsize - 1] = xstrdup(line);
|
||||
prompt_hsize[type] = newsize;
|
||||
}
|
||||
|
||||
/* Get history size. */
|
||||
u_int
|
||||
prompt_history_size(enum prompt_type type)
|
||||
{
|
||||
if (type >= PROMPT_NTYPES)
|
||||
return (0);
|
||||
return (prompt_hsize[type]);
|
||||
}
|
||||
|
||||
/* Get history entry. */
|
||||
const char *
|
||||
prompt_history_get(enum prompt_type type, u_int idx)
|
||||
{
|
||||
if (type >= PROMPT_NTYPES)
|
||||
return (NULL);
|
||||
if (idx >= prompt_hsize[type])
|
||||
return (NULL);
|
||||
return (prompt_hlist[type][idx]);
|
||||
}
|
||||
|
||||
/* Clear prompt history. */
|
||||
void
|
||||
prompt_history_clear(enum prompt_type type)
|
||||
{
|
||||
u_int idx;
|
||||
|
||||
if (type >= PROMPT_NTYPES)
|
||||
return;
|
||||
for (idx = 0; idx < prompt_hsize[type]; idx++)
|
||||
free(prompt_hlist[type][idx]);
|
||||
free(prompt_hlist[type]);
|
||||
prompt_hlist[type] = NULL;
|
||||
prompt_hsize[type] = 0;
|
||||
}
|
||||
@@ -1505,6 +1505,62 @@ redraw_set_draw_context(struct redraw_draw_ctx *dctx,
|
||||
dctx->flags |= REDRAW_ISOLATES;
|
||||
}
|
||||
|
||||
/* Draw a pane's prompt over its content. */
|
||||
static void
|
||||
redraw_draw_pane_prompt(struct redraw_draw_ctx *dctx, struct window_pane *wp)
|
||||
{
|
||||
struct redraw_scene *scene = dctx->scene;
|
||||
struct client *c = scene->c;
|
||||
struct tty *tty = &c->tty;
|
||||
struct screen screen;
|
||||
struct screen_write_ctx ctx;
|
||||
struct prompt_draw_data pdd;
|
||||
int ox = scene->ox, oy = scene->oy;
|
||||
int sx = scene->sx, sy = scene->sy;
|
||||
int line, cy, px, offset, width, wy;
|
||||
|
||||
if (wp->prompt == NULL || wp->sx == 0 || wp->sy == 0)
|
||||
return;
|
||||
|
||||
if (~dctx->flags & REDRAW_STATUS_TOP)
|
||||
wy = wp->yoff + (int)wp->sy - 1;
|
||||
else
|
||||
wy = wp->yoff;
|
||||
if (wy < oy || wy >= oy + sy)
|
||||
return;
|
||||
line = wy - oy;
|
||||
if (dctx->flags & REDRAW_STATUS_TOP)
|
||||
cy = dctx->status_lines + line;
|
||||
else
|
||||
cy = line;
|
||||
|
||||
if (wp->xoff + (int)wp->sx <= ox || wp->xoff >= ox + sx)
|
||||
return;
|
||||
if (wp->xoff < ox) {
|
||||
offset = ox - wp->xoff;
|
||||
px = 0;
|
||||
} else {
|
||||
offset = 0;
|
||||
px = wp->xoff - ox;
|
||||
}
|
||||
width = wp->sx - offset;
|
||||
if (px + width > sx)
|
||||
width = sx - px;
|
||||
|
||||
screen_init(&screen, wp->sx, 1, 0);
|
||||
screen_write_start(&ctx, &screen);
|
||||
pdd.ctx = &ctx;
|
||||
pdd.cursor_x = &wp->prompt_cx;
|
||||
pdd.area_x = 0;
|
||||
pdd.area_width = wp->sx;
|
||||
pdd.prompt_line = 0;
|
||||
prompt_draw(wp->prompt, &pdd);
|
||||
screen_write_stop(&ctx);
|
||||
|
||||
tty_draw_line(tty, &screen, 0, offset, width, px, cy, NULL);
|
||||
screen_free(&screen);
|
||||
}
|
||||
|
||||
/* Draw scene to client. */
|
||||
static void
|
||||
redraw_draw(struct client *c, struct window_pane *wp, int flags)
|
||||
@@ -1526,7 +1582,7 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags)
|
||||
if (flags & REDRAW_STATUS) {
|
||||
if (c->message_string != NULL)
|
||||
redraw = status_message_redraw(c);
|
||||
else if (c->prompt_string != NULL)
|
||||
else if (c->prompt != NULL)
|
||||
redraw = status_prompt_redraw(c);
|
||||
else
|
||||
redraw = status_redraw(c);
|
||||
@@ -1600,9 +1656,20 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags)
|
||||
else
|
||||
redraw_draw_lines(&dctx, flags);
|
||||
|
||||
if (flags & REDRAW_PANE) {
|
||||
if (wp != NULL)
|
||||
redraw_draw_pane_prompt(&dctx, wp);
|
||||
else {
|
||||
TAILQ_FOREACH(loop, &scene->w->panes, entry) {
|
||||
if (window_pane_is_visible(loop))
|
||||
redraw_draw_pane_prompt(&dctx, loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & REDRAW_STATUS) {
|
||||
lines = dctx.status_lines;
|
||||
if (c->message_string != NULL || c->prompt_string != NULL)
|
||||
if (c->message_string != NULL || c->prompt != NULL)
|
||||
lines = (lines == 0 ? 1 : lines);
|
||||
if (dctx.flags & REDRAW_STATUS_TOP)
|
||||
y = 0;
|
||||
|
||||
131
server-client.c
131
server-client.c
@@ -489,10 +489,7 @@ server_client_lost(struct client *c)
|
||||
free(c->message_string);
|
||||
if (event_initialized(&c->message_timer))
|
||||
evtimer_del(&c->message_timer);
|
||||
|
||||
free(c->prompt_saved);
|
||||
free(c->prompt_string);
|
||||
free(c->prompt_buffer);
|
||||
prompt_free(c->prompt);
|
||||
|
||||
format_lost_client(c);
|
||||
environ_free(c->environ);
|
||||
@@ -1464,6 +1461,7 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct cmdq_item *item;
|
||||
struct window_pane *wp;
|
||||
|
||||
/* Check the client is good to accept input. */
|
||||
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
|
||||
@@ -1493,6 +1491,7 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
return (0);
|
||||
status_message_clear(c);
|
||||
}
|
||||
|
||||
if (c->overlay_key != NULL) {
|
||||
switch (c->overlay_key(c, c->overlay_data, event)) {
|
||||
case 0:
|
||||
@@ -1502,9 +1501,10 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
server_client_clear_overlay(c);
|
||||
if (c->prompt_string != NULL) {
|
||||
switch (status_prompt_key(c, event->key)) {
|
||||
if (c->prompt != NULL) {
|
||||
switch (status_prompt_key(c, event->key, &event->m)) {
|
||||
case PROMPT_KEY_HANDLED:
|
||||
case PROMPT_KEY_CLOSE:
|
||||
return (0);
|
||||
@@ -1513,6 +1513,29 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wp = s->curw->window->active;
|
||||
if (wp == NULL || !window_pane_has_prompt(wp)) {
|
||||
TAILQ_FOREACH(wp, &s->curw->window->panes, entry) {
|
||||
if (window_pane_has_prompt(wp) &&
|
||||
window_pane_is_visible(wp))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (wp != NULL &&
|
||||
window_pane_has_prompt(wp) &&
|
||||
window_pane_is_visible(wp)) {
|
||||
switch (window_pane_prompt_key(wp, c, event->key, &event->m)) {
|
||||
case PROMPT_KEY_HANDLED:
|
||||
case PROMPT_KEY_CLOSE:
|
||||
case PROMPT_KEY_MOVE:
|
||||
return (0);
|
||||
case PROMPT_KEY_NOT_HANDLED:
|
||||
if (KEYC_IS_MOUSE(event->key))
|
||||
return (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1784,6 +1807,42 @@ out:
|
||||
bufferevent_enable(wp->event, EV_READ);
|
||||
}
|
||||
|
||||
/* Move cursor for pane prompt. */
|
||||
static int
|
||||
server_client_prompt_cursor(struct client *c, struct window_pane *wp, int *mode,
|
||||
u_int *cx, u_int *cy)
|
||||
{
|
||||
struct tty *tty = &c->tty;
|
||||
struct visible_ranges *r;
|
||||
u_int ox, oy, sx, sy;
|
||||
int px, py;
|
||||
|
||||
if (!window_pane_has_prompt(wp))
|
||||
return (0);
|
||||
*mode &= ~MODE_CURSOR;
|
||||
|
||||
tty_window_offset(tty, &ox, &oy, &sx, &sy);
|
||||
if (status_at_line(c) == 0)
|
||||
py = wp->yoff;
|
||||
else
|
||||
py = wp->yoff + wp->sy - 1;
|
||||
px = wp->xoff + wp->prompt_cx;
|
||||
if (px < (int)ox || px > (int)(ox + sx) ||
|
||||
py < (int)oy || py > (int)(oy + sy))
|
||||
return (1);
|
||||
|
||||
*cx = px - ox;
|
||||
*cy = py - oy;
|
||||
|
||||
r = window_visible_ranges(wp, *cx, *cy, 1, NULL);
|
||||
if (window_position_is_visible(r, *cx)) {
|
||||
if (status_at_line(c) == 0)
|
||||
*cy += status_line_size(c);
|
||||
*mode |= MODE_CURSOR;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update cursor position and mode settings. The scroll region and attributes
|
||||
* are cleared when idle (waiting for an event) as this is the most likely time
|
||||
@@ -1802,7 +1861,7 @@ server_client_reset_state(struct client *c)
|
||||
struct screen *s = NULL;
|
||||
struct options *oo = c->session->options;
|
||||
int mode = 0, cursor, flags, pane_mode = 0;
|
||||
u_int cx = 0, cy = 0, ox, oy, sx, sy, n;
|
||||
u_int cx = 0, cy = 0, ox, oy, sx, sy, prompt = 0;
|
||||
struct visible_ranges *r;
|
||||
|
||||
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
|
||||
@@ -1816,7 +1875,7 @@ server_client_reset_state(struct client *c)
|
||||
if (c->overlay_draw != NULL) {
|
||||
if (c->overlay_mode != NULL)
|
||||
s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
|
||||
} else if (wp != NULL && c->prompt_string == NULL)
|
||||
} else if (wp != NULL && c->prompt == NULL)
|
||||
s = wp->screen;
|
||||
else
|
||||
s = c->status.active;
|
||||
@@ -1832,42 +1891,36 @@ server_client_reset_state(struct client *c)
|
||||
tty_margin_off(tty);
|
||||
|
||||
/* Move cursor to pane cursor and offset. */
|
||||
if (c->prompt_string != NULL) {
|
||||
n = options_get_number(oo, "status-position");
|
||||
if (n == 0)
|
||||
cy = status_prompt_line_at(c);
|
||||
else {
|
||||
n = status_line_size(c) - status_prompt_line_at(c);
|
||||
if (n <= tty->sy)
|
||||
cy = tty->sy - n;
|
||||
else
|
||||
cy = tty->sy - 1;
|
||||
}
|
||||
cx = c->prompt_cursor;
|
||||
if (c->prompt != NULL) {
|
||||
prompt = 1;
|
||||
status_prompt_cursor(c, &cx, &cy);
|
||||
} else if (wp != NULL && c->overlay_draw == NULL) {
|
||||
cursor = 0;
|
||||
pane_mode = wp->base.mode;
|
||||
prompt = server_client_prompt_cursor(c, wp, &mode, &cx, &cy);
|
||||
if (!prompt) {
|
||||
cursor = 0;
|
||||
pane_mode = wp->base.mode;
|
||||
|
||||
tty_window_offset(tty, &ox, &oy, &sx, &sy);
|
||||
if (wp->xoff + (int)s->cx >= (int)ox &&
|
||||
wp->xoff + (int)s->cx <= (int)ox + (int)sx &&
|
||||
wp->yoff + (int)s->cy >= (int)oy &&
|
||||
wp->yoff + (int)s->cy <= (int)oy + (int)sy) {
|
||||
cursor = 1;
|
||||
tty_window_offset(tty, &ox, &oy, &sx, &sy);
|
||||
if (wp->xoff + (int)s->cx >= (int)ox &&
|
||||
wp->xoff + (int)s->cx <= (int)ox + (int)sx &&
|
||||
wp->yoff + (int)s->cy >= (int)oy &&
|
||||
wp->yoff + (int)s->cy <= (int)oy + (int)sy) {
|
||||
cursor = 1;
|
||||
|
||||
cx = wp->xoff + (int)s->cx - (int)ox;
|
||||
cy = wp->yoff + (int)s->cy - (int)oy;
|
||||
cx = wp->xoff + (int)s->cx - (int)ox;
|
||||
cy = wp->yoff + (int)s->cy - (int)oy;
|
||||
|
||||
r = window_visible_ranges(wp, cx, cy, 1, NULL);
|
||||
if (!window_position_is_visible(r, cx))
|
||||
cursor = 0;
|
||||
r = window_visible_ranges(wp, cx, cy, 1, NULL);
|
||||
if (!window_position_is_visible(r, cx))
|
||||
cursor = 0;
|
||||
|
||||
if (status_at_line(c) == 0)
|
||||
cy += status_line_size(c);
|
||||
if (status_at_line(c) == 0)
|
||||
cy += status_line_size(c);
|
||||
}
|
||||
|
||||
if ((pane_mode & MODE_SYNC) || !cursor)
|
||||
mode &= ~MODE_CURSOR;
|
||||
}
|
||||
|
||||
if ((pane_mode & MODE_SYNC) || !cursor)
|
||||
mode &= ~MODE_CURSOR;
|
||||
} else if (c->overlay_mode == NULL || s == NULL)
|
||||
mode &= ~MODE_CURSOR;
|
||||
if (~pane_mode & MODE_SYNC) {
|
||||
@@ -1895,7 +1948,7 @@ server_client_reset_state(struct client *c)
|
||||
}
|
||||
|
||||
/* Clear bracketed paste mode if at the prompt. */
|
||||
if (c->overlay_draw == NULL && c->prompt_string != NULL)
|
||||
if (c->overlay_draw == NULL && prompt)
|
||||
mode &= ~MODE_BRACKETPASTE;
|
||||
|
||||
/* Set the terminal mode and reset attributes. */
|
||||
|
||||
2
server.c
2
server.c
@@ -248,7 +248,7 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
|
||||
proc_loop(server_proc, server_loop);
|
||||
|
||||
job_kill_all();
|
||||
status_prompt_save_history();
|
||||
prompt_save_history();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
4
tmux.1
4
tmux.1
@@ -7359,7 +7359,7 @@ See
|
||||
for possible values for
|
||||
.Ar prompt\-type .
|
||||
.It Xo Ic command\-prompt
|
||||
.Op Fl 1bCeFiklN
|
||||
.Op Fl 1bCeFiklNP
|
||||
.Op Fl I Ar inputs
|
||||
.Op Fl p Ar prompts
|
||||
.Op Fl t Ar target\-client
|
||||
@@ -7439,6 +7439,8 @@ user exits the command prompt.
|
||||
makes
|
||||
.Em BSpace
|
||||
cancel an empty prompt.
|
||||
.Fl P
|
||||
opens a prompt inside a pane instead of on the status line.
|
||||
.Pp
|
||||
.Fl T
|
||||
tells
|
||||
|
||||
157
tmux.h
157
tmux.h
@@ -62,6 +62,8 @@ struct mouse_event;
|
||||
struct options;
|
||||
struct options_array_item;
|
||||
struct options_entry;
|
||||
struct prompt;
|
||||
struct window_pane_prompt;
|
||||
struct redraw_scene;
|
||||
struct redraw_span;
|
||||
struct screen_write_citem;
|
||||
@@ -1296,6 +1298,10 @@ struct window_pane {
|
||||
char *searchstr;
|
||||
int searchregex;
|
||||
|
||||
struct prompt *prompt;
|
||||
struct window_pane_prompt *prompt_data;
|
||||
u_int prompt_cx;
|
||||
|
||||
int border_gc_set;
|
||||
struct grid_cell border_gc;
|
||||
int active_border_gc_set;
|
||||
@@ -1936,20 +1942,12 @@ struct status_line {
|
||||
struct screen *active;
|
||||
int references;
|
||||
|
||||
u_int prompt_cx;
|
||||
|
||||
struct grid_cell style;
|
||||
struct style_line_entry entries[STATUS_LINES_LIMIT];
|
||||
};
|
||||
|
||||
/* Prompt type. */
|
||||
#define PROMPT_NTYPES 4
|
||||
enum prompt_type {
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_TYPE_SEARCH,
|
||||
PROMPT_TYPE_TARGET,
|
||||
PROMPT_TYPE_WINDOW_TARGET,
|
||||
PROMPT_TYPE_INVALID = 0xff
|
||||
};
|
||||
|
||||
/* File in client. */
|
||||
typedef void (*client_file_cb) (struct client *, const char *, int, int,
|
||||
struct evbuffer *, void *);
|
||||
@@ -1990,6 +1988,14 @@ RB_HEAD(client_windows, client_window);
|
||||
/* Maximum time to be pasting. */
|
||||
#define CLIENT_PASTE_TIME_LIMIT 5
|
||||
|
||||
/* Prompt type. */
|
||||
#define PROMPT_NTYPES 2
|
||||
enum prompt_type {
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_TYPE_SEARCH,
|
||||
PROMPT_TYPE_INVALID = 0xff
|
||||
};
|
||||
|
||||
/* Prompt result. */
|
||||
enum prompt_result {
|
||||
PROMPT_CONTINUE,
|
||||
@@ -2005,11 +2011,63 @@ enum prompt_key_result {
|
||||
};
|
||||
|
||||
/* Prompt callbacks. */
|
||||
typedef enum prompt_result (*prompt_input_cb)(struct client *, void *,
|
||||
typedef enum prompt_result (*prompt_input_cb)(void *, const char *,
|
||||
enum prompt_key_result);
|
||||
typedef enum prompt_result (*status_prompt_input_cb)(struct client *, void *,
|
||||
const char *, enum prompt_key_result);
|
||||
typedef enum prompt_result (*mode_tree_prompt_input_cb)(struct client *, void *,
|
||||
const char *, enum prompt_key_result);
|
||||
typedef void (*prompt_free_cb)(void *);
|
||||
|
||||
/* Overlay callbacks. */
|
||||
/* Prompt flags. */
|
||||
#define PROMPT_SINGLE 0x1
|
||||
#define PROMPT_NUMERIC 0x2
|
||||
#define PROMPT_INCREMENTAL 0x4
|
||||
#define PROMPT_NOFORMAT 0x8
|
||||
#define PROMPT_KEY 0x10
|
||||
#define PROMPT_ACCEPT 0x20
|
||||
#define PROMPT_QUOTENEXT 0x40
|
||||
#define PROMPT_BSPACE_EXIT 0x80
|
||||
#define PROMPT_NOFREEZE 0x100
|
||||
#define PROMPT_COMMANDMODE 0x200
|
||||
#define PROMPT_ISPANE 0x400
|
||||
#define PROMPT_ISMODE 0x800
|
||||
|
||||
/* Prompt create data. */
|
||||
struct prompt_create_data {
|
||||
struct cmd_find_state *fs;
|
||||
const char *prompt;
|
||||
const char *input;
|
||||
enum prompt_type type;
|
||||
int flags;
|
||||
|
||||
struct grid_cell style;
|
||||
struct grid_cell command_style;
|
||||
enum screen_cursor_style cstyle;
|
||||
enum screen_cursor_style command_cstyle;
|
||||
int ccolour;
|
||||
int cmode;
|
||||
int command_cmode;
|
||||
const char *message_format;
|
||||
int keys;
|
||||
const char *word_separators;
|
||||
|
||||
prompt_input_cb inputcb;
|
||||
prompt_free_cb freecb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* Prompt draw data. */
|
||||
struct prompt_draw_data {
|
||||
struct screen_write_ctx *ctx;
|
||||
u_int *cursor_x;
|
||||
|
||||
u_int area_x;
|
||||
u_int area_width;
|
||||
u_int prompt_line;
|
||||
};
|
||||
|
||||
/* Overlay callbacks */
|
||||
typedef struct visible_ranges *(*overlay_check_cb)(struct client *, void *,
|
||||
u_int, u_int, u_int);
|
||||
typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *,
|
||||
@@ -2154,29 +2212,7 @@ struct client {
|
||||
char *message_string;
|
||||
struct event message_timer;
|
||||
|
||||
char *prompt_string;
|
||||
struct utf8_data *prompt_buffer;
|
||||
struct cmd_find_state prompt_state;
|
||||
char *prompt_last;
|
||||
size_t prompt_index;
|
||||
prompt_input_cb prompt_inputcb;
|
||||
prompt_free_cb prompt_freecb;
|
||||
void *prompt_data;
|
||||
u_int prompt_hindex[PROMPT_NTYPES];
|
||||
struct utf8_data *prompt_saved;
|
||||
#define PROMPT_SINGLE 0x1
|
||||
#define PROMPT_NUMERIC 0x2
|
||||
#define PROMPT_INCREMENTAL 0x4
|
||||
#define PROMPT_NOFORMAT 0x8
|
||||
#define PROMPT_KEY 0x10
|
||||
#define PROMPT_ACCEPT 0x20
|
||||
#define PROMPT_QUOTENEXT 0x40
|
||||
#define PROMPT_BSPACE_EXIT 0x80
|
||||
#define PROMPT_NOFREEZE 0x100
|
||||
#define PROMPT_COMMANDMODE 0x200
|
||||
int prompt_flags;
|
||||
enum prompt_type prompt_type;
|
||||
int prompt_cursor;
|
||||
struct prompt *prompt;
|
||||
|
||||
struct session *session;
|
||||
struct session *last_session;
|
||||
@@ -3100,8 +3136,6 @@ void server_check_unattached(void);
|
||||
void server_unzoom_window(struct window *);
|
||||
|
||||
/* status.c */
|
||||
extern char **status_prompt_hlist[];
|
||||
extern u_int status_prompt_hsize[];
|
||||
void status_timer_start(struct client *);
|
||||
void status_timer_start_all(void);
|
||||
void status_update_cache(struct session *);
|
||||
@@ -3117,16 +3151,38 @@ void printflike(6, 7) status_message_set(struct client *, int, int, int, int,
|
||||
void status_message_clear(struct client *);
|
||||
int status_message_redraw(struct client *);
|
||||
void status_prompt_set(struct client *, struct cmd_find_state *,
|
||||
const char *, const char *, prompt_input_cb, prompt_free_cb,
|
||||
const char *, const char *, status_prompt_input_cb, prompt_free_cb,
|
||||
void *, int, enum prompt_type);
|
||||
void status_prompt_clear(struct client *);
|
||||
int status_prompt_redraw(struct client *);
|
||||
enum prompt_key_result status_prompt_key(struct client *, key_code);
|
||||
void status_prompt_cursor(struct client *, u_int *, u_int *);
|
||||
enum prompt_key_result status_prompt_key(struct client *, key_code,
|
||||
struct mouse_event *);
|
||||
void status_prompt_update(struct client *, const char *, const char *);
|
||||
void status_prompt_load_history(void);
|
||||
void status_prompt_save_history(void);
|
||||
const char *status_prompt_type_string(u_int);
|
||||
enum prompt_type status_prompt_type(const char *type);
|
||||
|
||||
/* prompt.c */
|
||||
void prompt_set_options(struct prompt_create_data *, struct session *);
|
||||
struct prompt *prompt_create(const struct prompt_create_data *);
|
||||
void prompt_free(struct prompt *);
|
||||
void prompt_incremental_start(struct prompt *);
|
||||
void prompt_draw(struct prompt *, struct prompt_draw_data *);
|
||||
enum prompt_key_result prompt_key(struct prompt *, key_code, int *);
|
||||
enum prompt_key_result prompt_mouse(struct prompt *, u_int, u_int, u_int,
|
||||
int *);
|
||||
void prompt_update(struct prompt *, const char *, const char *);
|
||||
int prompt_closed(struct prompt *);
|
||||
enum prompt_type prompt_type(const char *);
|
||||
const char *prompt_type_string(enum prompt_type);
|
||||
|
||||
/* prompt-history.c */
|
||||
const char *prompt_up_history(u_int *, u_int);
|
||||
const char *prompt_down_history(u_int *, u_int);
|
||||
void prompt_add_history(const char *, u_int);
|
||||
u_int prompt_history_size(enum prompt_type);
|
||||
const char *prompt_history_get(enum prompt_type, u_int);
|
||||
void prompt_history_clear(enum prompt_type);
|
||||
void prompt_load_history(void);
|
||||
void prompt_save_history(void);
|
||||
|
||||
/* resize.c */
|
||||
void resize_window(struct window *, u_int, u_int, int, int);
|
||||
@@ -3452,6 +3508,16 @@ int window_pane_key(struct window_pane *, struct client *,
|
||||
struct mouse_event *);
|
||||
void window_pane_paste(struct window_pane *, key_code, char *,
|
||||
size_t);
|
||||
void window_pane_set_prompt(struct window_pane *, struct client *,
|
||||
struct cmd_find_state *, const char *, const char *,
|
||||
status_prompt_input_cb, prompt_free_cb, void *, int,
|
||||
enum prompt_type);
|
||||
void window_pane_clear_prompt(struct window_pane *);
|
||||
int window_pane_has_prompt(struct window_pane *);
|
||||
void window_pane_update_prompt(struct window_pane *, const char *,
|
||||
const char *);
|
||||
enum prompt_key_result window_pane_prompt_key(struct window_pane *,
|
||||
struct client *, key_code, struct mouse_event *);
|
||||
int window_pane_is_visible(struct window_pane *);
|
||||
int window_pane_exited(struct window_pane *);
|
||||
u_int window_pane_search(struct window_pane *, const char *, int,
|
||||
@@ -3612,6 +3678,11 @@ void mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *);
|
||||
void mode_tree_draw(struct mode_tree_data *);
|
||||
int mode_tree_key(struct mode_tree_data *, struct client *, key_code *,
|
||||
struct mouse_event *, u_int *, u_int *);
|
||||
void mode_tree_set_prompt(struct mode_tree_data *, struct client *,
|
||||
const char *, const char *, enum prompt_type, int,
|
||||
mode_tree_prompt_input_cb, prompt_free_cb, void *);
|
||||
void mode_tree_clear_prompt(struct mode_tree_data *);
|
||||
int mode_tree_has_prompt(struct mode_tree_data *);
|
||||
void mode_tree_run_command(struct client *, struct cmd_find_state *,
|
||||
const char *, const char *);
|
||||
|
||||
|
||||
@@ -1145,10 +1145,10 @@ window_customize_set_option(struct client *c,
|
||||
new_item->idx = idx;
|
||||
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, value,
|
||||
mode_tree_set_prompt(data->data, c, prompt, value,
|
||||
PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
|
||||
window_customize_set_option_callback,
|
||||
window_customize_free_item_callback, new_item,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
|
||||
window_customize_free_item_callback, new_item);
|
||||
|
||||
free(prompt);
|
||||
free(value);
|
||||
@@ -1283,10 +1283,10 @@ window_customize_set_key(struct client *c,
|
||||
new_item->key = key;
|
||||
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, value,
|
||||
mode_tree_set_prompt(data->data, c, prompt, value,
|
||||
PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
|
||||
window_customize_set_command_callback,
|
||||
window_customize_free_item_callback, new_item,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
|
||||
window_customize_free_item_callback, new_item);
|
||||
free(prompt);
|
||||
free(value);
|
||||
} else if (strcmp(s, "Note") == 0) {
|
||||
@@ -1299,11 +1299,11 @@ window_customize_set_key(struct client *c,
|
||||
new_item->key = key;
|
||||
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt,
|
||||
mode_tree_set_prompt(data->data, c, prompt,
|
||||
(bd->note == NULL ? "" : bd->note),
|
||||
PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
|
||||
window_customize_set_note_callback,
|
||||
window_customize_free_item_callback, new_item,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
|
||||
window_customize_free_item_callback, new_item);
|
||||
free(prompt);
|
||||
}
|
||||
}
|
||||
@@ -1477,11 +1477,11 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
|
||||
xasprintf(&prompt, "Reset %s to default? ", item->name);
|
||||
data->references++;
|
||||
data->change = WINDOW_CUSTOMIZE_RESET;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
window_customize_change_current_callback,
|
||||
window_customize_free_callback, data,
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
window_customize_change_current_callback,
|
||||
window_customize_free_callback, data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'D':
|
||||
@@ -1491,11 +1491,11 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
|
||||
xasprintf(&prompt, "Reset %u tagged to default? ", tagged);
|
||||
data->references++;
|
||||
data->change = WINDOW_CUSTOMIZE_RESET;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
window_customize_change_tagged_callback,
|
||||
window_customize_free_callback, data,
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
window_customize_change_tagged_callback,
|
||||
window_customize_free_callback, data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'u':
|
||||
@@ -1508,11 +1508,11 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
|
||||
xasprintf(&prompt, "Unset %s? ", item->name);
|
||||
data->references++;
|
||||
data->change = WINDOW_CUSTOMIZE_UNSET;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
window_customize_change_current_callback,
|
||||
window_customize_free_callback, data,
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
window_customize_change_current_callback,
|
||||
window_customize_free_callback, data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'U':
|
||||
@@ -1522,11 +1522,11 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
|
||||
xasprintf(&prompt, "Unset %u tagged? ", tagged);
|
||||
data->references++;
|
||||
data->change = WINDOW_CUSTOMIZE_UNSET;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
window_customize_change_tagged_callback,
|
||||
window_customize_free_callback, data,
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
window_customize_change_tagged_callback,
|
||||
window_customize_free_callback, data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'H':
|
||||
|
||||
@@ -1317,10 +1317,11 @@ again:
|
||||
if (prompt == NULL)
|
||||
break;
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
window_tree_kill_current_callback, window_tree_command_free,
|
||||
data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'X':
|
||||
@@ -1329,10 +1330,11 @@ again:
|
||||
break;
|
||||
xasprintf(&prompt, "Kill %u tagged? ", tagged);
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
window_tree_kill_tagged_callback, window_tree_command_free,
|
||||
data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
data);
|
||||
free(prompt);
|
||||
break;
|
||||
case ':':
|
||||
@@ -1342,9 +1344,10 @@ again:
|
||||
else
|
||||
xasprintf(&prompt, "(current) ");
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
|
||||
window_tree_command_callback, window_tree_command_free,
|
||||
data, PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
|
||||
data);
|
||||
free(prompt);
|
||||
break;
|
||||
case '\r':
|
||||
|
||||
170
window.c
170
window.c
@@ -80,6 +80,14 @@ RB_GENERATE(windows, window, entry, window_cmp);
|
||||
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
|
||||
RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
|
||||
|
||||
struct window_pane_prompt {
|
||||
u_int wp_id;
|
||||
struct client *c;
|
||||
status_prompt_input_cb inputcb;
|
||||
prompt_free_cb freecb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
int
|
||||
window_cmp(struct window *w1, struct window *w2)
|
||||
{
|
||||
@@ -1148,6 +1156,8 @@ window_pane_destroy(struct window_pane *wp)
|
||||
window_pane_wait_finish(wp);
|
||||
spawn_editor_finish(wp);
|
||||
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
window_pane_free_modes(wp);
|
||||
free(wp->searchstr);
|
||||
|
||||
@@ -1360,6 +1370,7 @@ window_pane_reset_mode(struct window_pane *wp)
|
||||
server_kill_pane(wp);
|
||||
}
|
||||
|
||||
/* Reset all modes. */
|
||||
void
|
||||
window_pane_reset_mode_all(struct window_pane *wp)
|
||||
{
|
||||
@@ -1367,6 +1378,165 @@ window_pane_reset_mode_all(struct window_pane *wp)
|
||||
window_pane_reset_mode(wp);
|
||||
}
|
||||
|
||||
/* Prompt input callback. */
|
||||
static enum prompt_result
|
||||
window_pane_prompt_input_callback(void *data, const char *s,
|
||||
enum prompt_key_result key)
|
||||
{
|
||||
struct window_pane_prompt *wpp = data;
|
||||
|
||||
if (wpp->inputcb != NULL)
|
||||
return (wpp->inputcb(wpp->c, wpp->data, s, key));
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
/* Prompt free callback. */
|
||||
static void
|
||||
window_pane_prompt_free_callback(void *data)
|
||||
{
|
||||
struct window_pane_prompt *wpp = data;
|
||||
struct window_pane *wp;
|
||||
|
||||
wp = window_pane_find_by_id(wpp->wp_id);
|
||||
if (wp != NULL && wp->prompt_data == wpp)
|
||||
wp->prompt_data = NULL;
|
||||
if (wpp->freecb != NULL)
|
||||
wpp->freecb(wpp->data);
|
||||
free(wpp);
|
||||
}
|
||||
|
||||
/* Open a prompt owned by a pane, drawn over the pane instead of the status. */
|
||||
void
|
||||
window_pane_set_prompt(struct window_pane *wp, struct client *c,
|
||||
struct cmd_find_state *fs, const char *msg, const char *input,
|
||||
status_prompt_input_cb inputcb, prompt_free_cb freecb, void *data,
|
||||
int flags, enum prompt_type type)
|
||||
{
|
||||
struct session *s = NULL;
|
||||
struct prompt_create_data pd;
|
||||
struct window_pane_prompt *wpp;
|
||||
|
||||
if (c != NULL)
|
||||
s = c->session;
|
||||
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
wpp = xcalloc(1, sizeof *wpp);
|
||||
wpp->wp_id = wp->id;
|
||||
wpp->c = c;
|
||||
wpp->inputcb = inputcb;
|
||||
wpp->freecb = freecb;
|
||||
wpp->data = data;
|
||||
|
||||
memset(&pd, 0, sizeof pd);
|
||||
prompt_set_options(&pd, s);
|
||||
pd.fs = fs;
|
||||
pd.prompt = msg;
|
||||
pd.input = input;
|
||||
pd.type = type;
|
||||
pd.flags = flags;
|
||||
pd.inputcb = window_pane_prompt_input_callback;
|
||||
pd.freecb = window_pane_prompt_free_callback;
|
||||
pd.data = wpp;
|
||||
|
||||
wp->prompt = prompt_create(&pd);
|
||||
wp->prompt_data = wpp;
|
||||
wp->flags |= PANE_REDRAW;
|
||||
|
||||
prompt_incremental_start(wp->prompt);
|
||||
}
|
||||
|
||||
/* Close a pane prompt. */
|
||||
void
|
||||
window_pane_clear_prompt(struct window_pane *wp)
|
||||
{
|
||||
struct prompt *prompt = wp->prompt;
|
||||
|
||||
if (prompt == NULL)
|
||||
return;
|
||||
wp->prompt = NULL;
|
||||
prompt_free(prompt);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
|
||||
/* Does this pane have an open prompt? */
|
||||
int
|
||||
window_pane_has_prompt(struct window_pane *wp)
|
||||
{
|
||||
return (wp->prompt != NULL);
|
||||
}
|
||||
|
||||
/* Replace the message and input of an open pane prompt. */
|
||||
void
|
||||
window_pane_update_prompt(struct window_pane *wp, const char *msg,
|
||||
const char *input)
|
||||
{
|
||||
if (wp->prompt != NULL) {
|
||||
prompt_update(wp->prompt, msg, input);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass a key to a pane prompt. The client is set transiently for the duration
|
||||
* of the key in case the prompt or pane is destroyed by the callback.
|
||||
*/
|
||||
enum prompt_key_result
|
||||
window_pane_prompt_key(struct window_pane *wp, struct client *c, key_code key,
|
||||
struct mouse_event *m)
|
||||
{
|
||||
struct prompt *prompt = wp->prompt;
|
||||
struct window_pane_prompt *wpp = wp->prompt_data;
|
||||
enum prompt_key_result result;
|
||||
u_int wp_id = wp->id, x, y, py;
|
||||
int redraw = 0;
|
||||
|
||||
if (prompt == NULL)
|
||||
return (PROMPT_KEY_NOT_HANDLED);
|
||||
|
||||
if (wpp != NULL)
|
||||
wpp->c = c;
|
||||
if (KEYC_IS_MOUSE(key)) {
|
||||
if (m == NULL ||
|
||||
MOUSE_BUTTONS(m->b) != MOUSE_BUTTON_1 ||
|
||||
MOUSE_DRAG(m->b) ||
|
||||
MOUSE_RELEASE(m->b) ||
|
||||
cmd_mouse_at(wp, m, &x, &y, 0) != 0)
|
||||
result = PROMPT_KEY_NOT_HANDLED;
|
||||
else {
|
||||
if (c != NULL && status_at_line(c) == 0)
|
||||
py = 0;
|
||||
else
|
||||
py = wp->sy - 1;
|
||||
if (y == py) {
|
||||
result = prompt_mouse(prompt, x, 0, wp->sx,
|
||||
&redraw);
|
||||
} else
|
||||
result = PROMPT_KEY_NOT_HANDLED;
|
||||
}
|
||||
} else
|
||||
result = prompt_key(prompt, key, &redraw);
|
||||
|
||||
wp = window_pane_find_by_id(wp_id);
|
||||
if (wp == NULL)
|
||||
return (result);
|
||||
if (wpp != NULL && wp->prompt_data == wpp)
|
||||
wpp->c = NULL;
|
||||
|
||||
/*
|
||||
* Only an explicit close or the prompt marking itself closed ends it;
|
||||
* cursor movement and editing keep it open.
|
||||
*/
|
||||
if (wp->prompt == prompt &&
|
||||
(result == PROMPT_KEY_CLOSE || prompt_closed(prompt)))
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
if (redraw || wp->prompt != prompt)
|
||||
wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_copy_paste(struct window_pane *wp, char *buf, size_t len)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user