version 1.20, 2009/08/13 22:32:18 |
version 1.21, 2009/08/18 07:08:26 |
|
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
|
|
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
#include "tmux.h" |
#include "tmux.h" |
|
|
void window_copy_free(struct window_pane *); |
void window_copy_free(struct window_pane *); |
void window_copy_resize(struct window_pane *, u_int, u_int); |
void window_copy_resize(struct window_pane *, u_int, u_int); |
void window_copy_key(struct window_pane *, struct client *, int); |
void window_copy_key(struct window_pane *, struct client *, int); |
|
int window_copy_key_input(struct window_pane *, int); |
void window_copy_mouse( |
void window_copy_mouse( |
struct window_pane *, struct client *, u_char, u_char, u_char); |
struct window_pane *, struct client *, u_char, u_char, u_char); |
|
|
|
|
void window_copy_write_lines( |
void window_copy_write_lines( |
struct window_pane *, struct screen_write_ctx *, u_int, u_int); |
struct window_pane *, struct screen_write_ctx *, u_int, u_int); |
|
|
|
void window_copy_scroll_to(struct window_pane *, u_int, u_int); |
|
int window_copy_search_compare( |
|
struct grid *, u_int, u_int, struct grid *, u_int); |
|
int window_copy_search_lr( |
|
struct grid *, struct grid *, u_int *, u_int, u_int, u_int); |
|
int window_copy_search_rl( |
|
struct grid *, struct grid *, u_int *, u_int, u_int, u_int); |
|
void window_copy_search_up(struct window_pane *, const char *); |
|
void window_copy_search_down(struct window_pane *, const char *); |
|
void window_copy_goto_line(struct window_pane *, const char *); |
void window_copy_update_cursor(struct window_pane *, u_int, u_int); |
void window_copy_update_cursor(struct window_pane *, u_int, u_int); |
void window_copy_start_selection(struct window_pane *); |
void window_copy_start_selection(struct window_pane *); |
int window_copy_update_selection(struct window_pane *); |
int window_copy_update_selection(struct window_pane *); |
|
|
NULL, |
NULL, |
}; |
}; |
|
|
|
enum window_copy_input_type { |
|
WINDOW_COPY_OFF, |
|
WINDOW_COPY_SEARCHUP, |
|
WINDOW_COPY_SEARCHDOWN, |
|
WINDOW_COPY_GOTOLINE, |
|
}; |
|
|
struct window_copy_mode_data { |
struct window_copy_mode_data { |
struct screen screen; |
struct screen screen; |
|
|
struct mode_key_data mdata; |
struct mode_key_data mdata; |
|
|
u_int oy; |
u_int oy; |
|
|
u_int selx; |
u_int selx; |
u_int sely; |
u_int sely; |
|
|
u_int cx; |
u_int cx; |
u_int cy; |
u_int cy; |
|
|
|
enum window_copy_input_type inputtype; |
|
const char *inputprompt; |
|
char *inputstr; |
|
|
|
enum window_copy_input_type searchtype; |
|
char *searchstr; |
}; |
}; |
|
|
struct screen * |
struct screen * |
|
|
data->cx = wp->base.cx; |
data->cx = wp->base.cx; |
data->cy = wp->base.cy; |
data->cy = wp->base.cy; |
|
|
|
data->inputtype = WINDOW_COPY_OFF; |
|
data->inputprompt = NULL; |
|
data->inputstr = xstrdup(""); |
|
|
|
data->searchtype = WINDOW_COPY_OFF; |
|
data->searchstr = NULL; |
|
|
s = &data->screen; |
s = &data->screen; |
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); |
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); |
if (options_get_number(&wp->window->options, "mode-mouse")) |
if (options_get_number(&wp->window->options, "mode-mouse")) |
|
|
{ |
{ |
struct window_copy_mode_data *data = wp->modedata; |
struct window_copy_mode_data *data = wp->modedata; |
|
|
|
if (data->searchstr != NULL) |
|
xfree(data->searchstr); |
|
xfree(data->inputstr); |
|
|
screen_free(&data->screen); |
screen_free(&data->screen); |
|
|
xfree(data); |
xfree(data); |
} |
} |
|
|
|
|
struct window_copy_mode_data *data = wp->modedata; |
struct window_copy_mode_data *data = wp->modedata; |
struct screen *s = &data->screen; |
struct screen *s = &data->screen; |
u_int n; |
u_int n; |
|
int keys; |
|
|
|
if (data->inputtype != WINDOW_COPY_OFF) { |
|
if (window_copy_key_input(wp, key) != 0) |
|
goto input_off; |
|
return; |
|
} |
|
|
switch (mode_key_lookup(&data->mdata, key)) { |
switch (mode_key_lookup(&data->mdata, key)) { |
case MODEKEYCOPY_CANCEL: |
case MODEKEYCOPY_CANCEL: |
window_pane_reset_mode(wp); |
window_pane_reset_mode(wp); |
|
|
case MODEKEYCOPY_PREVIOUSWORD: |
case MODEKEYCOPY_PREVIOUSWORD: |
window_copy_cursor_previous_word(wp); |
window_copy_cursor_previous_word(wp); |
break; |
break; |
|
case MODEKEYCOPY_SEARCHUP: |
|
data->inputtype = WINDOW_COPY_SEARCHUP; |
|
data->inputprompt = "Search Up"; |
|
goto input_on; |
|
case MODEKEYCOPY_SEARCHDOWN: |
|
data->inputtype = WINDOW_COPY_SEARCHDOWN; |
|
data->inputprompt = "Search Down"; |
|
goto input_on; |
|
case MODEKEYCOPY_SEARCHAGAIN: |
|
switch (data->searchtype) { |
|
case WINDOW_COPY_OFF: |
|
case WINDOW_COPY_GOTOLINE: |
|
break; |
|
case WINDOW_COPY_SEARCHUP: |
|
window_copy_search_up(wp, data->searchstr); |
|
break; |
|
case WINDOW_COPY_SEARCHDOWN: |
|
window_copy_search_down(wp, data->searchstr); |
|
break; |
|
} |
|
break; |
|
case MODEKEYCOPY_GOTOLINE: |
|
data->inputtype = WINDOW_COPY_GOTOLINE; |
|
data->inputprompt = "Goto Line"; |
|
*data->inputstr = '\0'; |
|
goto input_on; |
default: |
default: |
break; |
break; |
} |
} |
|
|
|
return; |
|
|
|
input_on: |
|
keys = options_get_number(&wp->window->options, "mode-keys"); |
|
if (keys == MODEKEY_EMACS) |
|
mode_key_init(&data->mdata, &mode_key_tree_emacs_edit); |
|
else |
|
mode_key_init(&data->mdata, &mode_key_tree_vi_edit); |
|
|
|
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); |
|
return; |
|
|
|
input_off: |
|
keys = options_get_number(&wp->window->options, "mode-keys"); |
|
if (keys == MODEKEY_EMACS) |
|
mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); |
|
else |
|
mode_key_init(&data->mdata, &mode_key_tree_vi_copy); |
|
|
|
data->inputtype = WINDOW_COPY_OFF; |
|
data->inputprompt = NULL; |
|
|
|
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); |
} |
} |
|
|
|
int |
|
window_copy_key_input(struct window_pane *wp, int key) |
|
{ |
|
struct window_copy_mode_data *data = wp->modedata; |
|
struct screen *s = &data->screen; |
|
size_t inputlen; |
|
|
|
switch (mode_key_lookup(&data->mdata, key)) { |
|
case MODEKEYEDIT_CANCEL: |
|
return (-1); |
|
case MODEKEYEDIT_BACKSPACE: |
|
inputlen = strlen(data->inputstr); |
|
if (inputlen > 0) |
|
data->inputstr[inputlen - 1] = '\0'; |
|
break; |
|
case MODEKEYEDIT_ENTER: |
|
switch (data->inputtype) { |
|
case WINDOW_COPY_OFF: |
|
break; |
|
case WINDOW_COPY_SEARCHUP: |
|
window_copy_search_up(wp, data->inputstr); |
|
data->searchtype = data->inputtype; |
|
data->searchstr = xstrdup(data->inputstr); |
|
break; |
|
case WINDOW_COPY_SEARCHDOWN: |
|
window_copy_search_down(wp, data->inputstr); |
|
data->searchtype = data->inputtype; |
|
data->searchstr = xstrdup(data->inputstr); |
|
break; |
|
case WINDOW_COPY_GOTOLINE: |
|
window_copy_goto_line(wp, data->inputstr); |
|
*data->inputstr = '\0'; |
|
break; |
|
} |
|
return (1); |
|
case MODEKEY_OTHER: |
|
if (key < 32 || key > 126) |
|
break; |
|
inputlen = strlen(data->inputstr) + 2; |
|
|
|
data->inputstr = xrealloc(data->inputstr, 1, inputlen); |
|
data->inputstr[inputlen - 2] = key; |
|
data->inputstr[inputlen - 1] = '\0'; |
|
break; |
|
default: |
|
break; |
|
} |
|
|
|
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); |
|
return (0); |
|
} |
|
|
void |
void |
window_copy_mouse(struct window_pane *wp, |
window_copy_mouse(struct window_pane *wp, |
unused struct client *c, u_char b, u_char x, u_char y) |
unused struct client *c, u_char b, u_char x, u_char y) |
|
|
} |
} |
|
|
void |
void |
|
window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py) |
|
{ |
|
struct window_copy_mode_data *data = wp->modedata; |
|
struct screen *s = &wp->base; |
|
struct grid *gd = s->grid; |
|
u_int offset, gap; |
|
|
|
data->cx = px; |
|
|
|
gap = gd->sy / 4; |
|
if (py < gd->sy) { |
|
offset = 0; |
|
data->cy = py; |
|
} else if (py > gd->hsize + gd->sy - gap) { |
|
offset = gd->hsize; |
|
data->cy = py - gd->hsize; |
|
} else { |
|
offset = py + gap - gd->sy; |
|
data->cy = py - offset; |
|
} |
|
data->oy = gd->hsize - offset; |
|
|
|
window_copy_redraw_screen(wp); |
|
} |
|
|
|
int |
|
window_copy_search_compare( |
|
struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx) |
|
{ |
|
const struct grid_cell *gc, *sgc; |
|
const struct grid_utf8 *gu, *sgu; |
|
|
|
gc = grid_peek_cell(gd, px, py); |
|
sgc = grid_peek_cell(sgd, spx, 0); |
|
|
|
if ((gc->flags & GRID_FLAG_UTF8) != (sgc->flags & GRID_FLAG_UTF8)) |
|
return (0); |
|
|
|
if (gc->flags & GRID_FLAG_UTF8) { |
|
gu = grid_peek_utf8(gd, px, py); |
|
sgu = grid_peek_utf8(sgd, spx, 0); |
|
if (memcmp(gu->data, sgu->data, UTF8_SIZE) == 0) |
|
return (1); |
|
} else { |
|
if (gc->data == sgc->data) |
|
return (1); |
|
} |
|
return (0); |
|
} |
|
|
|
int |
|
window_copy_search_lr(struct grid *gd, |
|
struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last) |
|
{ |
|
u_int ax, bx, px; |
|
|
|
for (ax = first; ax < last; ax++) { |
|
if (ax + sgd->sx >= gd->sx) |
|
break; |
|
for (bx = 0; bx < sgd->sx; bx++) { |
|
px = ax + bx; |
|
if (!window_copy_search_compare(gd, px, py, sgd, bx)) |
|
break; |
|
} |
|
if (bx == sgd->sx) { |
|
*ppx = ax; |
|
return (1); |
|
} |
|
} |
|
return (0); |
|
} |
|
|
|
int |
|
window_copy_search_rl(struct grid *gd, |
|
struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last) |
|
{ |
|
u_int ax, bx, px; |
|
|
|
for (ax = last + 1; ax > first; ax--) { |
|
for (bx = 0; bx < sgd->sx; bx++) { |
|
px = ax - 1 + bx; |
|
if (!window_copy_search_compare(gd, px, py, sgd, bx)) |
|
break; |
|
} |
|
if (bx == sgd->sx) { |
|
*ppx = ax - 1; |
|
return (1); |
|
} |
|
} |
|
return (0); |
|
} |
|
|
|
void |
|
window_copy_search_up(struct window_pane *wp, const char *searchstr) |
|
{ |
|
struct window_copy_mode_data *data = wp->modedata; |
|
struct screen *s = &wp->base, ss; |
|
struct screen_write_ctx ctx; |
|
struct grid *gd = s->grid, *sgd; |
|
struct grid_cell gc; |
|
size_t searchlen; |
|
u_int i, last, fx, fy, px; |
|
int utf8flag, n, wrapped; |
|
|
|
if (*searchstr == '\0') |
|
return; |
|
utf8flag = options_get_number(&wp->window->options, "utf8"); |
|
searchlen = screen_write_strlen(utf8flag, "%s", searchstr); |
|
|
|
screen_init(&ss, searchlen, 1, 0); |
|
screen_write_start(&ctx, NULL, &ss); |
|
memcpy(&gc, &grid_default_cell, sizeof gc); |
|
screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); |
|
screen_write_stop(&ctx); |
|
|
|
fx = data->cx; |
|
fy = gd->hsize - data->oy + data->cy; |
|
|
|
if (fx == 0) { |
|
if (fy == 0) |
|
return; |
|
fx = gd->sx - 1; |
|
fy--; |
|
} else |
|
fx--; |
|
n = wrapped = 0; |
|
|
|
retry: |
|
sgd = ss.grid; |
|
for (i = fy + 1; i > 0; i--) { |
|
last = screen_size_x(s); |
|
if (i == fy + 1) |
|
last = fx; |
|
n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last); |
|
if (n) { |
|
window_copy_scroll_to(wp, px, i - 1); |
|
break; |
|
} |
|
} |
|
if (!n && !wrapped) { |
|
fx = gd->sx - 1; |
|
fy = gd->hsize + gd->sy - 1; |
|
wrapped = 1; |
|
goto retry; |
|
} |
|
|
|
screen_free(&ss); |
|
} |
|
|
|
void |
|
window_copy_search_down(struct window_pane *wp, const char *searchstr) |
|
{ |
|
struct window_copy_mode_data *data = wp->modedata; |
|
struct screen *s = &wp->base, ss; |
|
struct screen_write_ctx ctx; |
|
struct grid *gd = s->grid, *sgd; |
|
struct grid_cell gc; |
|
size_t searchlen; |
|
u_int i, first, fx, fy, px; |
|
int utf8flag, n, wrapped; |
|
|
|
if (*searchstr == '\0') |
|
return; |
|
utf8flag = options_get_number(&wp->window->options, "utf8"); |
|
searchlen = screen_write_strlen(utf8flag, "%s", searchstr); |
|
|
|
screen_init(&ss, searchlen, 1, 0); |
|
screen_write_start(&ctx, NULL, &ss); |
|
memcpy(&gc, &grid_default_cell, sizeof gc); |
|
screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); |
|
screen_write_stop(&ctx); |
|
searchlen = strlen(searchstr); |
|
|
|
fx = data->cx; |
|
fy = gd->hsize - data->oy + data->cy; |
|
|
|
if (fx == gd->sx - 1) { |
|
if (fy == gd->hsize + gd->sy) |
|
return; |
|
fx = 0; |
|
fy++; |
|
} else |
|
fx++; |
|
n = wrapped = 0; |
|
|
|
retry: |
|
sgd = ss.grid; |
|
for (i = fy + 1; i < gd->hsize + gd->sy; i++) { |
|
first = 0; |
|
if (i == fy + 1) |
|
first = fx; |
|
n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx); |
|
if (n) { |
|
window_copy_scroll_to(wp, px, i - 1); |
|
break; |
|
} |
|
} |
|
if (!n && !wrapped) { |
|
fx = 0; |
|
fy = 0; |
|
wrapped = 1; |
|
goto retry; |
|
} |
|
|
|
screen_free(&ss); |
|
} |
|
|
|
void |
|
window_copy_goto_line(struct window_pane *wp, const char *linestr) |
|
{ |
|
struct window_copy_mode_data *data = wp->modedata; |
|
const char *errstr; |
|
u_int lineno; |
|
|
|
lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr); |
|
if (errstr != NULL) |
|
return; |
|
|
|
data->oy = lineno; |
|
window_copy_redraw_screen(wp); |
|
} |
|
|
|
void |
window_copy_write_line( |
window_copy_write_line( |
struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) |
struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) |
{ |
{ |
|
|
struct screen *s = &data->screen; |
struct screen *s = &data->screen; |
struct grid_cell gc; |
struct grid_cell gc; |
char hdr[32]; |
char hdr[32]; |
size_t size; |
size_t last, xoff = 0, size = 0; |
|
|
|
memcpy(&gc, &grid_default_cell, sizeof gc); |
|
gc.fg = options_get_number(&wp->window->options, "mode-fg"); |
|
gc.bg = options_get_number(&wp->window->options, "mode-bg"); |
|
gc.attr |= options_get_number(&wp->window->options, "mode-attr"); |
|
|
|
last = screen_size_y(s) - 1; |
if (py == 0) { |
if (py == 0) { |
memcpy(&gc, &grid_default_cell, sizeof gc); |
|
size = xsnprintf(hdr, sizeof hdr, |
size = xsnprintf(hdr, sizeof hdr, |
"[%u/%u]", data->oy, screen_hsize(&wp->base)); |
"[%u/%u]", data->oy, screen_hsize(&wp->base)); |
gc.fg = options_get_number(&wp->window->options, "mode-fg"); |
|
gc.bg = options_get_number(&wp->window->options, "mode-bg"); |
|
gc.attr |= options_get_number( |
|
&wp->window->options, "mode-attr"); |
|
screen_write_cursormove(ctx, screen_size_x(s) - size, 0); |
screen_write_cursormove(ctx, screen_size_x(s) - size, 0); |
screen_write_puts(ctx, &gc, "%s", hdr); |
screen_write_puts(ctx, &gc, "%s", hdr); |
|
} else if (py == last && data->inputtype != WINDOW_COPY_OFF) { |
|
xoff = size = xsnprintf(hdr, sizeof hdr, |
|
"%s: %s", data->inputprompt, data->inputstr); |
|
screen_write_cursormove(ctx, 0, last); |
|
screen_write_puts(ctx, &gc, "%s", hdr); |
} else |
} else |
size = 0; |
size = 0; |
|
|
screen_write_cursormove(ctx, 0, py); |
screen_write_cursormove(ctx, xoff, py); |
screen_write_copy(ctx, &wp->base, 0, (screen_hsize(&wp->base) - |
screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) - |
data->oy) + py, screen_size_x(s) - size, 1); |
data->oy) + py, screen_size_x(s) - size, 1); |
|
|
if (py == data->cy && data->cx == screen_size_x(s)) { |
if (py == data->cy && data->cx == screen_size_x(s)) { |