mirror of
https://github.com/tmux/tmux.git
synced 2026-07-03 10:12:31 +00:00
Merge branch 'obsd-master'
This commit is contained in:
@@ -184,6 +184,8 @@ dist_tmux_SOURCES = \
|
||||
paste.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
prompt.c \
|
||||
prompt-history.c \
|
||||
regsub.c \
|
||||
resize.c \
|
||||
screen-redraw.c \
|
||||
|
||||
2
cfg.c
2
cfg.c
@@ -56,7 +56,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':
|
||||
|
||||
@@ -763,7 +763,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
@@ -485,10 +485,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);
|
||||
@@ -1460,6 +1457,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))
|
||||
@@ -1489,6 +1487,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:
|
||||
@@ -1498,9 +1497,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);
|
||||
@@ -1509,6 +1509,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1780,6 +1803,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
|
||||
@@ -1798,7 +1857,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))
|
||||
@@ -1812,7 +1871,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;
|
||||
@@ -1828,42 +1887,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) {
|
||||
@@ -1891,7 +1944,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
@@ -254,7 +254,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
@@ -7361,7 +7361,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
|
||||
@@ -7441,6 +7441,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
@@ -63,6 +63,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;
|
||||
@@ -1330,6 +1332,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;
|
||||
@@ -1977,20 +1983,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 *);
|
||||
@@ -2031,6 +2029,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,
|
||||
@@ -2046,11 +2052,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 *,
|
||||
@@ -2195,29 +2253,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;
|
||||
@@ -3145,8 +3181,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 *);
|
||||
@@ -3162,16 +3196,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);
|
||||
@@ -3501,6 +3557,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,
|
||||
@@ -3661,6 +3727,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
@@ -78,6 +78,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)
|
||||
{
|
||||
@@ -1155,6 +1163,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);
|
||||
|
||||
@@ -1371,6 +1381,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)
|
||||
{
|
||||
@@ -1378,6 +1389,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