diff --git a/CHANGES b/CHANGES index 9f6ccf49..78565e60 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ 18 January 2009 +* find-window command to search window names, titles and visible content (but + not history) for a string. If only one is found, the window is selected + otherwise a choice list is shown. This (as with the other choice commands) + only works from a key. Bound to "f" by default. * Cleaned up command printing code, also enclose arguments with spaces in "s. * Added command sequences. These are entered by separating each argument by a ; argument (spaces on both sides), for example: @@ -951,7 +955,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.217 2009-01-18 14:40:48 nicm Exp $ +$Id: CHANGES,v 1.218 2009-01-18 17:20:52 nicm Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms diff --git a/GNUmakefile b/GNUmakefile index 231efd0d..ad272f0c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# $Id: GNUmakefile,v 1.61 2009-01-18 15:57:28 tcunha Exp $ +# $Id: GNUmakefile,v 1.62 2009-01-18 17:20:52 nicm Exp $ .PHONY: clean @@ -36,11 +36,11 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-save-buffer.c cmd-select-pane.c cmd-split-window.c \ cmd-resize-pane-up.c cmd-resize-pane-down.c cmd-kill-pane.c \ cmd-up-pane.c cmd-down-pane.c cmd-choose-window.c cmd-choose-session.c \ - cmd-suspend-client.c \ + cmd-suspend-client.c cmd-find-window.c \ window-clock.c window-scroll.c window-more.c window-copy.c \ window-choose.c \ options.c options-cmd.c paste.c colour.c utf8.c clock.c \ - tty.c tty-term.c tty-keys.c tty-write.c + tty.c tty-term.c tty-keys.c tty-write.c util.c CC?= gcc INCDIRS+= -I. -I- diff --git a/Makefile b/Makefile index 30df1cdc..c586b2e0 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.101 2009-01-18 15:57:28 tcunha Exp $ +# $Id: Makefile,v 1.102 2009-01-18 17:20:52 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -40,11 +40,11 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-save-buffer.c cmd-select-pane.c cmd-split-window.c \ cmd-resize-pane-up.c cmd-resize-pane-down.c cmd-kill-pane.c \ cmd-up-pane.c cmd-down-pane.c cmd-choose-window.c cmd-choose-session.c \ - cmd-suspend-client.c \ + cmd-suspend-client.c cmd-find-window.c \ window-clock.c window-scroll.c window-more.c window-copy.c \ window-choose.c \ options.c options-cmd.c paste.c colour.c utf8.c clock.c \ - tty.c tty-term.c tty-keys.c tty-write.c + tty.c tty-term.c tty-keys.c tty-write.c util.c CC?= cc INCDIRS+= -I. -I- -I/usr/local/include diff --git a/NOTES b/NOTES index 4980a6c6..13d25545 100644 --- a/NOTES +++ b/NOTES @@ -87,7 +87,7 @@ The CVS HEAD version of tmux often has additional features from the release versions; if interested, testing it is encouraged. It can be obtained by anonymous CVS from SourceForge: - $ cvs -d:pserver:anoncvs@tmux.cvs.sf.net:/cvsroot/tmux co tmux + $ cvs -d:pserver:anoncvs@tmux.cvs.sf.net:/cvsroot/tmux co tmux If running CVS HEAD, please note it is development code and there may be bugs and undocumented features; please read the CHANGES file for information. @@ -99,4 +99,4 @@ welcome. Please email: -- Nicholas Marriott -$Id: NOTES,v 1.41 2009-01-18 15:55:33 tcunha Exp $ +$Id: NOTES,v 1.42 2009-01-18 17:20:52 nicm Exp $ diff --git a/TODO b/TODO index 05cf057f..de1187cd 100644 --- a/TODO +++ b/TODO @@ -79,3 +79,7 @@ - document command sequences - make command sequences more usable: don't require space around ;, handle errors better +- -a and -b flags to next/previous window to jump to next window with activity + or bell +- document find-window + diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 14745c16..9763918a 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -1,4 +1,4 @@ -/* $Id: cmd-choose-session.c,v 1.3 2009-01-18 12:13:21 nicm Exp $ */ +/* $Id: cmd-choose-session.c,v 1.4 2009-01-18 17:20:52 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -61,7 +61,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) return; if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) - return; + goto out; cur = idx = 0; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { @@ -84,6 +84,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) window_choose_ready( wl->window->active, cur, cmd_choose_session_callback, cdata); +out: if (ctx->cmdclient != NULL) server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); } diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 280f4ae0..b071770d 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -1,4 +1,4 @@ -/* $Id: cmd-choose-window.c,v 1.4 2009-01-17 18:47:36 nicm Exp $ */ +/* $Id: cmd-choose-window.c,v 1.5 2009-01-18 17:20:52 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -21,7 +21,7 @@ #include "tmux.h" /* - * Enter choice mode to chosoe a window. + * Enter choice mode to choose a window. */ void cmd_choose_window_exec(struct cmd *, struct cmd_ctx *); @@ -62,7 +62,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) return; if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) - return; + goto out; cur = idx = 0; RB_FOREACH(wm, winlinks, &s->windows) { @@ -73,8 +73,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) idx++; window_choose_add(wl->window->active, - wm->idx, "%3d: %s [%ux%u] (%u panes)", wm->idx, w->name, w->sx, w->sy, - window_count_panes(w)); + wm->idx, "%3d: %s [%ux%u] (%u panes)", wm->idx, w->name, + w->sx, w->sy, window_count_panes(w)); } cdata = xmalloc(sizeof *cdata); @@ -84,6 +84,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) window_choose_ready( wl->window->active, cur, cmd_choose_window_callback, cdata); +out: if (ctx->cmdclient != NULL) server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); } diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index cdcbd424..eca662fe 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -1,4 +1,4 @@ -/* $Id: cmd-command-prompt.c,v 1.10 2009-01-18 14:40:48 nicm Exp $ */ +/* $Id: cmd-command-prompt.c,v 1.11 2009-01-18 17:20:52 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -62,6 +62,9 @@ cmd_command_prompt_init(struct cmd *self, int key) case ',': data->arg = xstrdup("rename-window '%%'"); break; + case 'f': + data->arg = xstrdup("find-window '%%'"); + break; } } diff --git a/cmd-find-window.c b/cmd-find-window.c new file mode 100644 index 00000000..a9c497da --- /dev/null +++ b/cmd-find-window.c @@ -0,0 +1,198 @@ +/* $Id: cmd-find-window.c,v 1.1 2009-01-18 17:20:52 nicm Exp $ */ + +/* + * Copyright (c) 2009 Nicholas Marriott + * + * 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 + +#include + +#include "tmux.h" + +/* + * Find window containing text. + */ + +void cmd_find_window_exec(struct cmd *, struct cmd_ctx *); + +void cmd_find_window_callback(void *, int); +char *cmd_find_window_search(struct window_pane *, const char *); + +const struct cmd_entry cmd_find_window_entry = { + "find-window", NULL, + CMD_TARGET_WINDOW_USAGE, + CMD_ARG1, + cmd_target_init, + cmd_target_parse, + cmd_find_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +struct cmd_find_window_data { + u_int session; +}; + +void +cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_find_window_data *cdata; + struct session *s = ctx->curclient->session; + struct winlink *wl, *wm; + struct window *w; + struct window_pane *wp; + ARRAY_DECL(, u_int) list_idx; + ARRAY_DECL(, char *) list_ctx; + char *sres, *sctx; + u_int i; + + if (ctx->curclient == NULL) + return; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return; + + ARRAY_INIT(&list_idx); + ARRAY_INIT(&list_ctx); + + RB_FOREACH(wm, winlinks, &s->windows) { + i = 0; + TAILQ_FOREACH(wp, &wm->window->panes, entry) { + i++; + + if (strstr(wm->window->name, data->arg) != NULL) + sctx = xstrdup(""); + else { + sres = cmd_find_window_search(wp, data->arg); + if (sres == NULL && + strstr(wp->base.title, data->arg) == NULL) + continue; + + if (sres == NULL) { + xasprintf(&sctx, + "pane %u title: \"%s\"", i - 1, + wp->base.title); + } else { + xasprintf(&sctx, "\"%s\"", sres); + xfree(sres); + } + } + + ARRAY_ADD(&list_idx, wm->idx); + ARRAY_ADD(&list_ctx, sctx); + } + } + + if (ARRAY_LENGTH(&list_idx) == 0) { + ctx->error(ctx, "no windows matching: %s", data->arg); + ARRAY_FREE(&list_idx); + ARRAY_FREE(&list_ctx); + return; + } + + if (ARRAY_LENGTH(&list_idx) == 1) { + if (session_select(s, ARRAY_FIRST(&list_idx)) == 0) + server_redraw_session(s); + recalculate_sizes(); + goto out; + } + + if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) + goto out; + + for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) { + wm = winlink_find_by_index( + &s->windows, ARRAY_ITEM(&list_idx, i)); + w = wm->window; + + sctx = ARRAY_ITEM(&list_ctx, i); + window_choose_add(wl->window->active, + wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name, + w->sx, w->sy, window_count_panes(w), sctx); + xfree(sctx); + } + + cdata = xmalloc(sizeof *cdata); + if (session_index(s, &cdata->session) != 0) + fatalx("session not found"); + + window_choose_ready( + wl->window->active, 0, cmd_find_window_callback, cdata); + +out: + ARRAY_FREE(&list_idx); + ARRAY_FREE(&list_ctx); + + if (ctx->cmdclient != NULL) + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); +} + +void +cmd_find_window_callback(void *data, int idx) +{ + struct cmd_find_window_data *cdata = data; + struct session *s; + + if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) { + s = ARRAY_ITEM(&sessions, cdata->session); + if (s != NULL && session_select(s, idx) == 0) + server_redraw_session(s); + recalculate_sizes(); + } + xfree(cdata); +} + +char * +cmd_find_window_search(struct window_pane *wp, const char *searchstr) +{ + char *buf, *s; + size_t off; + const struct grid_cell *gc; + u_int i, j, k; + u_char data[4]; + + buf = xmalloc(1); + + for (j = 0; j < screen_size_y(&wp->base); j++) { + off = 0; + for (i = 0; i < screen_size_x(&wp->base); i++) { + gc = grid_view_peek_cell(wp->base.grid, i, j); + utf8_split(gc->data, data); + + buf = xrealloc(buf, 1, off + 4); + for (k = 0; k < sizeof data; k++) { + if (data[k] == 0xff) + break; + buf[off++] = data[k]; + } + } + while (off > 0 && buf[off - 1] == ' ') + off--; + buf[off] = '\0'; + + if ((s = strstr(buf, searchstr)) != NULL) { + s = section_string(buf, off, s - buf, 40); + xfree(buf); + return (s); + } + } + + xfree(buf); + return (NULL); +} diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index d79df313..7ffe558d 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -1,4 +1,4 @@ -/* $Id: cmd-list-buffers.c,v 1.5 2009-01-07 19:52:36 nicm Exp $ */ +/* $Id: cmd-list-buffers.c,v 1.6 2009-01-18 17:20:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -78,8 +78,8 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx) tmp[out - 3] = '.'; } - ctx->print(ctx, "%d: " - "%zu bytes: \"%s\"", idx - 1, strlen(pb->data), tmp); + ctx->print(ctx, "%d: %zu bytes: \"%s\"", + idx - 1, strlen(pb->data), tmp); } else ctx->print(ctx, "%d: %zu bytes", idx, strlen(pb->data)); } diff --git a/cmd.c b/cmd.c index ad9eccdf..618a90b1 100644 --- a/cmd.c +++ b/cmd.c @@ -1,4 +1,4 @@ -/* $Id: cmd.c,v 1.81 2009-01-18 14:40:48 nicm Exp $ */ +/* $Id: cmd.c,v 1.82 2009-01-18 17:20:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -36,6 +36,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_delete_buffer_entry, &cmd_detach_client_entry, &cmd_down_pane_entry, + &cmd_find_window_entry, &cmd_has_session_entry, &cmd_kill_pane_entry, &cmd_kill_server_entry, diff --git a/key-bindings.c b/key-bindings.c index a616f04d..13aa54f8 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -1,4 +1,4 @@ -/* $Id: key-bindings.c,v 1.55 2009-01-18 14:40:48 nicm Exp $ */ +/* $Id: key-bindings.c,v 1.56 2009-01-18 17:20:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -100,6 +100,7 @@ key_bindings_init(void) { ']', &cmd_paste_buffer_entry }, { 'c', &cmd_new_window_entry }, { 'd', &cmd_detach_client_entry }, + { 'f', &cmd_command_prompt_entry }, { 'l', &cmd_last_window_entry }, { 'n', &cmd_next_window_entry }, { 'o', &cmd_down_pane_entry }, diff --git a/tmux.h b/tmux.h index b4db069e..9f7c0865 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.238 2009-01-18 14:40:48 nicm Exp $ */ +/* $Id: tmux.h,v 1.239 2009-01-18 17:20:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1102,6 +1102,7 @@ extern const struct cmd_entry cmd_copy_mode_entry; extern const struct cmd_entry cmd_delete_buffer_entry; extern const struct cmd_entry cmd_detach_client_entry; extern const struct cmd_entry cmd_down_pane_entry; +extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_has_session_entry; extern const struct cmd_entry cmd_kill_pane_entry; extern const struct cmd_entry cmd_kill_server_entry; @@ -1488,6 +1489,9 @@ u_int utf8_combine(const u_char *); void utf8_split(u_int, u_char *); int utf8_width(u_int); +/* util.c */ +char *section_string(char *, size_t, size_t, size_t); + /* buffer.c */ struct buffer *buffer_create(size_t); void buffer_destroy(struct buffer *); diff --git a/util.c b/util.c new file mode 100644 index 00000000..97b405e3 --- /dev/null +++ b/util.c @@ -0,0 +1,52 @@ +/* $Id: util.c,v 1.1 2009-01-18 17:20:52 nicm Exp $ */ + +/* + * Copyright (c) 2009 Nicholas Marriott + * + * 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 + +#include "tmux.h" + +/* Return a section of a string around a point. */ +char * +section_string(char *buf, size_t len, size_t sectoff, size_t sectlen) +{ + char *s; + size_t first, last; + + if (len <= sectlen) { + first = 0; + last = len; + } else if (sectoff < sectlen / 2) { + first = 0; + last = sectlen; + } else if (sectoff + sectlen / 2 > len) { + last = len; + first = last - sectlen; + } else { + first = sectoff - sectlen / 2; + last = first + sectlen; + } + + if (last - first > 3 && first != 0) + first += 3; + if (last - first > 3 && last != len) + last -= 3; + + xasprintf(&s, "%s%.*s%s", first == 0 ? "" : "...", + (int) (last - first), buf + first, last == len ? "" : "..."); + return (s); +} diff --git a/window-choose.c b/window-choose.c index d27cafd0..1bc3746b 100644 --- a/window-choose.c +++ b/window-choose.c @@ -1,4 +1,4 @@ -/* $Id: window-choose.c,v 1.2 2009-01-15 19:28:36 nicm Exp $ */ +/* $Id: window-choose.c,v 1.3 2009-01-18 17:20:52 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -149,6 +149,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct screen_write_ctx ctx; + struct window_choose_mode_item *item; int table; u_int items; @@ -161,7 +162,8 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) window_pane_reset_mode(wp); break; case MODEKEY_ENTER: - data->callback(data->data, data->selected); + item = &ARRAY_ITEM(&data->list, data->selected); + data->callback(data->data, item->idx); window_pane_reset_mode(wp); break; case MODEKEY_UP: