mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Add 'e' key in buffer mode to open the buffer in an editor.
This commit is contained in:
		| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								job.c
									
									
									
									
									
								
							| @@ -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; | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
							
								
								
									
										9
									
								
								paste.c
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								paste.c
									
									
									
									
									
								
							| @@ -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) | ||||
|   | ||||
							
								
								
									
										9
									
								
								popup.c
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								popup.c
									
									
									
									
									
								
							| @@ -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) | ||||
|   | ||||
							
								
								
									
										1
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								server.c
									
									
									
									
									
								
							| @@ -481,4 +481,5 @@ server_child_stopped(pid_t pid, int status) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	job_check_died(pid, status); | ||||
| } | ||||
|   | ||||
							
								
								
									
										5
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								tmux.1
									
									
									
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								tmux.c
									
									
									
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -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 *, | ||||
|   | ||||
							
								
								
									
										134
									
								
								window-buffer.c
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								window-buffer.c
									
									
									
									
									
								
							| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 nicm
					nicm