Git fork
at reftables-rust 165 lines 4.1 kB view raw
1#define USE_THE_REPOSITORY_VARIABLE 2 3#include "git-compat-util.h" 4#include "abspath.h" 5#include "advice.h" 6#include "config.h" 7#include "editor.h" 8#include "environment.h" 9#include "gettext.h" 10#include "pager.h" 11#include "path.h" 12#include "strbuf.h" 13#include "strvec.h" 14#include "run-command.h" 15#include "sigchain.h" 16 17#ifndef DEFAULT_EDITOR 18#define DEFAULT_EDITOR "vi" 19#endif 20 21int is_terminal_dumb(void) 22{ 23 const char *terminal = getenv("TERM"); 24 return !terminal || !strcmp(terminal, "dumb"); 25} 26 27const char *git_editor(void) 28{ 29 const char *editor = getenv("GIT_EDITOR"); 30 int terminal_is_dumb = is_terminal_dumb(); 31 32 if (!editor && editor_program) 33 editor = editor_program; 34 if (!editor && !terminal_is_dumb) 35 editor = getenv("VISUAL"); 36 if (!editor) 37 editor = getenv("EDITOR"); 38 39 if (!editor && terminal_is_dumb) 40 return NULL; 41 42 if (!editor) 43 editor = DEFAULT_EDITOR; 44 45 return editor; 46} 47 48const char *git_sequence_editor(void) 49{ 50 const char *editor = getenv("GIT_SEQUENCE_EDITOR"); 51 52 if (!editor) 53 repo_config_get_string_tmp(the_repository, "sequence.editor", &editor); 54 if (!editor) 55 editor = git_editor(); 56 57 return editor; 58} 59 60static int launch_specified_editor(const char *editor, const char *path, 61 struct strbuf *buffer, const char *const *env) 62{ 63 if (!editor) 64 return error("Terminal is dumb, but EDITOR unset"); 65 66 if (strcmp(editor, ":")) { 67 struct strbuf realpath = STRBUF_INIT; 68 struct child_process p = CHILD_PROCESS_INIT; 69 int ret, sig; 70 int print_waiting_for_editor = advice_enabled(ADVICE_WAITING_FOR_EDITOR) && isatty(2); 71 72 if (print_waiting_for_editor) { 73 /* 74 * A dumb terminal cannot erase the line later on. Add a 75 * newline to separate the hint from subsequent output. 76 * 77 * Make sure that our message is separated with a whitespace 78 * from further cruft that may be written by the editor. 79 */ 80 const char term = is_terminal_dumb() ? '\n' : ' '; 81 82 fprintf(stderr, 83 _("hint: Waiting for your editor to close the file...%c"), 84 term); 85 fflush(stderr); 86 } 87 88 strbuf_realpath(&realpath, path, 1); 89 90 strvec_pushl(&p.args, editor, realpath.buf, NULL); 91 if (env) 92 strvec_pushv(&p.env, (const char **)env); 93 p.use_shell = 1; 94 p.trace2_child_class = "editor"; 95 if (start_command(&p) < 0) { 96 strbuf_release(&realpath); 97 return error("unable to start editor '%s'", editor); 98 } 99 100 sigchain_push(SIGINT, SIG_IGN); 101 sigchain_push(SIGQUIT, SIG_IGN); 102 ret = finish_command(&p); 103 strbuf_release(&realpath); 104 sig = ret - 128; 105 sigchain_pop(SIGINT); 106 sigchain_pop(SIGQUIT); 107 if (sig == SIGINT || sig == SIGQUIT) 108 raise(sig); 109 if (print_waiting_for_editor && !is_terminal_dumb()) 110 /* 111 * Erase the entire line to avoid wasting the 112 * vertical space. 113 */ 114 term_clear_line(); 115 if (ret) 116 return error("there was a problem with the editor '%s'", 117 editor); 118 } 119 120 if (!buffer) 121 return 0; 122 if (strbuf_read_file(buffer, path, 0) < 0) 123 return error_errno("could not read file '%s'", path); 124 return 0; 125} 126 127int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) 128{ 129 return launch_specified_editor(git_editor(), path, buffer, env); 130} 131 132int launch_sequence_editor(const char *path, struct strbuf *buffer, 133 const char *const *env) 134{ 135 return launch_specified_editor(git_sequence_editor(), path, buffer, env); 136} 137 138int strbuf_edit_interactively(struct repository *r, 139 struct strbuf *buffer, const char *path, 140 const char *const *env) 141{ 142 struct strbuf sb = STRBUF_INIT; 143 int fd, res = 0; 144 145 if (!is_absolute_path(path)) 146 path = repo_git_path_append(r, &sb, "%s", path); 147 148 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); 149 if (fd < 0) 150 res = error_errno(_("could not open '%s' for writing"), path); 151 else if (write_in_full(fd, buffer->buf, buffer->len) < 0) { 152 res = error_errno(_("could not write to '%s'"), path); 153 close(fd); 154 } else if (close(fd) < 0) 155 res = error_errno(_("could not close '%s'"), path); 156 else { 157 strbuf_reset(buffer); 158 if (launch_editor(path, buffer, env) < 0) 159 res = error_errno(_("could not edit '%s'"), path); 160 unlink(path); 161 } 162 163 strbuf_release(&sb); 164 return res; 165}