Merge branch 'ps/reftable-drop-generic'
[git/gitster.git] / editor.c
blob6b9ce81d5fc0fdc44dbf75ac4eedf2f218300caa
1 #define USE_THE_REPOSITORY_VARIABLE
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"
17 #ifndef DEFAULT_EDITOR
18 #define DEFAULT_EDITOR "vi"
19 #endif
21 int is_terminal_dumb(void)
23 const char *terminal = getenv("TERM");
24 return !terminal || !strcmp(terminal, "dumb");
27 const char *git_editor(void)
29 const char *editor = getenv("GIT_EDITOR");
30 int terminal_is_dumb = is_terminal_dumb();
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");
39 if (!editor && terminal_is_dumb)
40 return NULL;
42 if (!editor)
43 editor = DEFAULT_EDITOR;
45 return editor;
48 const char *git_sequence_editor(void)
50 const char *editor = getenv("GIT_SEQUENCE_EDITOR");
52 if (!editor)
53 git_config_get_string_tmp("sequence.editor", &editor);
54 if (!editor)
55 editor = git_editor();
57 return editor;
60 static int launch_specified_editor(const char *editor, const char *path,
61 struct strbuf *buffer, const char *const *env)
63 if (!editor)
64 return error("Terminal is dumb, but EDITOR unset");
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);
72 if (print_waiting_for_editor) {
74 * A dumb terminal cannot erase the line later on. Add a
75 * newline to separate the hint from subsequent output.
77 * Make sure that our message is separated with a whitespace
78 * from further cruft that may be written by the editor.
80 const char term = is_terminal_dumb() ? '\n' : ' ';
82 fprintf(stderr,
83 _("hint: Waiting for your editor to close the file...%c"),
84 term);
85 fflush(stderr);
88 strbuf_realpath(&realpath, path, 1);
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);
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())
111 * Erase the entire line to avoid wasting the
112 * vertical space.
114 term_clear_line();
115 if (ret)
116 return error("there was a problem with the editor '%s'",
117 editor);
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;
127 int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)
129 return launch_specified_editor(git_editor(), path, buffer, env);
132 int launch_sequence_editor(const char *path, struct strbuf *buffer,
133 const char *const *env)
135 return launch_specified_editor(git_sequence_editor(), path, buffer, env);
138 int strbuf_edit_interactively(struct repository *r,
139 struct strbuf *buffer, const char *path,
140 const char *const *env)
142 struct strbuf sb = STRBUF_INIT;
143 int fd, res = 0;
145 if (!is_absolute_path(path)) {
146 strbuf_repo_git_path(&sb, r, "%s", path);
147 path = sb.buf;
150 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
151 if (fd < 0)
152 res = error_errno(_("could not open '%s' for writing"), path);
153 else if (write_in_full(fd, buffer->buf, buffer->len) < 0) {
154 res = error_errno(_("could not write to '%s'"), path);
155 close(fd);
156 } else if (close(fd) < 0)
157 res = error_errno(_("could not close '%s'"), path);
158 else {
159 strbuf_reset(buffer);
160 if (launch_editor(path, buffer, env) < 0)
161 res = error_errno(_("could not edit '%s'"), path);
162 unlink(path);
165 strbuf_release(&sb);
166 return res;