Add 'e' key in buffer mode to open the buffer in an editor.

This commit is contained in:
nicm 2020-05-16 15:24:28 +00:00
parent a3cbc014c3
commit 78595457f9
11 changed files with 177 additions and 4 deletions

View File

@ -313,7 +313,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
else if (args_has(args, 'E'))
flags |= POPUP_CLOSEEXIT;
if (popup_display(flags, item, px, py, w, h, nlines, lines, shellcmd,
cmd, cwd, tc, target) != 0)
cmd, cwd, tc, target, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@ -738,7 +738,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
/*
* Draw the screens. How they are arranged depends on where the list
* appearsq.
* appears.
*/
switch (list_align) {
case STYLE_ALIGN_DEFAULT:

7
job.c
View File

@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <paths.h>
@ -285,6 +286,12 @@ job_check_died(pid_t pid, int status)
}
if (job == NULL)
return;
if (WIFSTOPPED(status)) {
if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
return;
killpg(job->pid, SIGCONT);
return;
}
log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid);
job->status = status;

View File

@ -210,6 +210,12 @@ const struct options_table_entry options_table[] = {
.default_str = "screen"
},
{ .name = "editor",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = _PATH_VI
},
{ .name = "escape-time",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,

View File

@ -297,6 +297,15 @@ paste_set(char *data, size_t size, const char *name, char **cause)
return (0);
}
/* Set paste data without otherwise changing it. */
void
paste_replace(struct paste_buffer *pb, char *data, size_t size)
{
free(pb->data);
pb->data = data;
pb->size = size;
}
/* Convert start of buffer into a nice string. */
char *
paste_make_sample(struct paste_buffer *pb)

View File

@ -40,6 +40,8 @@ struct popup_data {
struct job *job;
struct input_ctx *ictx;
int status;
popup_close_cb cb;
void *arg;
u_int px;
u_int py;
@ -150,6 +152,9 @@ popup_free_cb(struct client *c)
struct cmdq_item *item = pd->item;
u_int i;
if (pd->cb != NULL)
pd->cb(pd->status, pd->arg);
if (item != NULL) {
if (pd->ictx != NULL &&
cmdq_get_client(item) != NULL &&
@ -403,7 +408,7 @@ int
popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
u_int sy, u_int nlines, const char **lines, const char *shellcmd,
const char *cmd, const char *cwd, struct client *c,
struct cmd_find_state *fs)
struct cmd_find_state *fs, popup_close_cb cb, void *arg)
{
struct popup_data *pd;
u_int i;
@ -422,6 +427,8 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
pd->c = c;
pd->c->references++;
pd->cb = cb;
pd->arg = arg;
pd->status = 128 + SIGHUP;
if (fs != NULL)

View File

@ -481,4 +481,5 @@ server_child_stopped(pid_t pid, int status)
}
}
}
job_check_died(pid, status);
}

5
tmux.1
View File

@ -3113,6 +3113,10 @@ Set the time in milliseconds for which
waits after an escape is input to determine if it is part of a function or meta
key sequences.
The default is 500 milliseconds.
.It Ic editor Ar shell-command
Set the command used when
.Nm
runs an editor.
.It Xo Ic exit-empty
.Op Ic on | off
.Xc
@ -5339,6 +5343,7 @@ The following keys may be used in buffer mode:
.It Li "P" Ta "Paste tagged buffers"
.It Li "d" Ta "Delete selected buffer"
.It Li "D" Ta "Delete tagged buffers"
.It Li "e" Ta "Open the buffer in an editor"
.It Li "f" Ta "Enter a format to filter items"
.It Li "O" Ta "Change sort field"
.It Li "r" Ta "Reverse sort order"

1
tmux.c
View File

@ -443,6 +443,7 @@ main(int argc, char **argv)
/* Override keys to vi if VISUAL or EDITOR are set. */
if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
options_set_string(global_options, "editor", 0, "%s", s);
if (strrchr(s, '/') != NULL)
s = strrchr(s, '/') + 1;
if (strstr(s, "vi") != NULL)

5
tmux.h
View File

@ -1806,6 +1806,7 @@ void paste_free(struct paste_buffer *);
void paste_add(const char *, char *, size_t);
int paste_rename(const char *, const char *, char **);
int paste_set(char *, size_t, const char *, char **);
void paste_replace(struct paste_buffer *, char *, size_t);
char *paste_make_sample(struct paste_buffer *);
/* format.c */
@ -2813,12 +2814,14 @@ int menu_display(struct menu *, int, struct cmdq_item *, u_int,
#define POPUP_WRITEKEYS 0x1
#define POPUP_CLOSEEXIT 0x2
#define POPUP_CLOSEEXITZERO 0x4
typedef void (*popup_close_cb)(int, void *);
u_int popup_width(struct cmdq_item *, u_int, const char **,
struct client *, struct cmd_find_state *);
u_int popup_height(u_int, const char **);
int popup_display(int, struct cmdq_item *, u_int, u_int, u_int,
u_int, u_int, const char **, const char *, const char *,
const char *, struct client *, struct cmd_find_state *);
const char *, struct client *, struct cmd_find_state *,
popup_close_cb, void *);
/* style.c */
int style_parse(struct style *,const struct grid_cell *,

View File

@ -18,9 +18,12 @@
#include <sys/types.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <vis.h>
#include "tmux.h"
@ -95,6 +98,13 @@ struct window_buffer_modedata {
u_int item_size;
};
struct window_buffer_editdata {
u_int wp_id;
char *path;
char *name;
struct paste_buffer *pb;
};
static struct window_buffer_itemdata *
window_buffer_add_item(struct window_buffer_modedata *data)
{
@ -353,6 +363,126 @@ window_buffer_do_paste(void *modedata, void *itemdata, struct client *c,
mode_tree_run_command(c, NULL, data->command, item->name);
}
static void
window_buffer_finish_edit(struct window_buffer_editdata *ed)
{
unlink(ed->path);
free(ed->path);
free(ed->name);
free(ed);
}
static void
window_buffer_edit_close_cb(int status, void *arg)
{
struct window_buffer_editdata *ed = arg;
FILE *f;
off_t len;
char *buf;
size_t oldlen;
const char *oldbuf;
struct paste_buffer *pb;
struct window_pane *wp;
struct window_buffer_modedata *data;
struct window_mode_entry *wme;
if (status != 0) {
window_buffer_finish_edit(ed);
return;
}
pb = paste_get_name(ed->name);
if (pb == NULL || pb != ed->pb) {
window_buffer_finish_edit(ed);
return;
}
f = fopen(ed->path, "r");
if (f != NULL) {
fseeko(f, 0, SEEK_END);
len = ftello(f);
fseeko(f, 0, SEEK_SET);
if (len > 0 &&
(uintmax_t)len <= (uintmax_t)SIZE_MAX &&
(buf = malloc(len)) != NULL &&
fread(buf, len, 1, f) == 1) {
oldbuf = paste_buffer_data(pb, &oldlen);
if (oldlen != '\0' &&
oldbuf[oldlen - 1] != '\n' &&
buf[len - 1] == '\n')
len--;
if (len != 0)
paste_replace(pb, buf, len);
}
fclose(f);
}
wp = window_pane_find_by_id(ed->wp_id);
if (wp != NULL) {
wme = TAILQ_FIRST(&wp->modes);
if (wme->mode == &window_buffer_mode) {
data = wme->data;
mode_tree_build(data->data);
mode_tree_draw(data->data);
}
wp->flags |= PANE_REDRAW;
}
window_buffer_finish_edit(ed);
}
static void
window_buffer_start_edit(struct window_buffer_modedata *data,
struct window_buffer_itemdata *item, struct client *c)
{
struct paste_buffer *pb;
int fd;
FILE *f;
const char *buf;
size_t len;
struct window_buffer_editdata *ed;
char *cmd;
char path[] = _PATH_TMP "tmux.XXXXXXXX";
const char *editor;
u_int px, py, sx, sy;
if ((pb = paste_get_name(item->name)) == NULL)
return;
buf = paste_buffer_data(pb, &len);
editor = options_get_string(global_options, "editor");
if (*editor == '\0')
return;
fd = mkstemp(path);
if (fd == -1)
return;
f = fdopen(fd, "w");
if (fwrite(buf, len, 1, f) != 1) {
fclose(f);
return;
}
fclose(f);
ed = xcalloc(1, sizeof *ed);
ed->wp_id = data->wp->id;
ed->path = xstrdup(path);
ed->name = xstrdup(paste_buffer_name(pb));
ed->pb = pb;
sx = c->tty.sx * 9 / 10;
sy = c->tty.sy * 9 / 10;
px = (c->tty.sx / 2) - (sx / 2);
py = (c->tty.sy / 2) - (sy / 2);
xasprintf(&cmd, "%s %s", editor, path);
if (popup_display(POPUP_WRITEKEYS|POPUP_CLOSEEXIT, NULL, px, py, sx, sy,
0, NULL, cmd, NULL, _PATH_TMP, c, NULL, window_buffer_edit_close_cb,
ed) != 0)
window_buffer_finish_edit(ed);
free(cmd);
}
static void
window_buffer_key(struct window_mode_entry *wme, struct client *c,
__unused struct session *s, __unused struct winlink *wl, key_code key,
@ -366,6 +496,10 @@ window_buffer_key(struct window_mode_entry *wme, struct client *c,
finished = mode_tree_key(mtd, c, &key, m, NULL, NULL);
switch (key) {
case 'e':
item = mode_tree_get_current(mtd);
window_buffer_start_edit(data, item, c);
break;
case 'd':
item = mode_tree_get_current(mtd);
window_buffer_do_delete(data, item, c, key);