]> git.ipfire.org Git - thirdparty/git.git/blame - editor.c
The fifth batch
[thirdparty/git.git] / editor.c
CommitLineData
219de841
PS
1#define USE_THE_REPOSITORY_VARIABLE
2
77f091ed 3#include "git-compat-util.h"
0b027f6c 4#include "abspath.h"
6c6ddf92 5#include "advice.h"
2aed0181 6#include "config.h"
4e120823 7#include "editor.h"
32a8f510 8#include "environment.h"
f394e093 9#include "gettext.h"
ca4eed70 10#include "pager.h"
d1cbe1e6 11#include "path.h"
d82f33e2 12#include "strbuf.h"
c7c4bdec 13#include "strvec.h"
d82f33e2 14#include "run-command.h"
913ef360 15#include "sigchain.h"
d82f33e2 16
8f4b576a
JN
17#ifndef DEFAULT_EDITOR
18#define DEFAULT_EDITOR "vi"
19#endif
20
a64f213d
LS
21int is_terminal_dumb(void)
22{
23 const char *terminal = getenv("TERM");
24 return !terminal || !strcmp(terminal, "dumb");
25}
26
44fcb497 27const char *git_editor(void)
d82f33e2 28{
d33738d7 29 const char *editor = getenv("GIT_EDITOR");
a64f213d 30 int terminal_is_dumb = is_terminal_dumb();
d82f33e2 31
d82f33e2
SB
32 if (!editor && editor_program)
33 editor = editor_program;
d33738d7 34 if (!editor && !terminal_is_dumb)
d82f33e2
SB
35 editor = getenv("VISUAL");
36 if (!editor)
37 editor = getenv("EDITOR");
38
d33738d7 39 if (!editor && terminal_is_dumb)
44fcb497 40 return NULL;
d82f33e2
SB
41
42 if (!editor)
8f4b576a 43 editor = DEFAULT_EDITOR;
d82f33e2 44
44fcb497
JN
45 return editor;
46}
47
2aed0181 48const char *git_sequence_editor(void)
44fcb497 49{
2aed0181
AG
50 const char *editor = getenv("GIT_SEQUENCE_EDITOR");
51
52 if (!editor)
f1de981e 53 git_config_get_string_tmp("sequence.editor", &editor);
2aed0181
AG
54 if (!editor)
55 editor = git_editor();
44fcb497 56
2aed0181
AG
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{
44fcb497
JN
63 if (!editor)
64 return error("Terminal is dumb, but EDITOR unset");
65
d82f33e2 66 if (strcmp(editor, ":")) {
3d7747e3 67 struct strbuf realpath = STRBUF_INIT;
d3180279 68 struct child_process p = CHILD_PROCESS_INIT;
1250857c 69 int ret, sig;
ed9bff08 70 int print_waiting_for_editor = advice_enabled(ADVICE_WAITING_FOR_EDITOR) && isatty(2);
abfb04d0
LS
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 }
d82f33e2 87
3d7747e3 88 strbuf_realpath(&realpath, path, 1);
3d7747e3 89
2b709893 90 strvec_pushl(&p.args, editor, realpath.buf, NULL);
c7c4bdec 91 if (env)
29fda24d 92 strvec_pushv(&p.env, (const char **)env);
f42ca31d 93 p.use_shell = 1;
eee73d1d 94 p.trace2_child_class = "editor";
3d7747e3
AM
95 if (start_command(&p) < 0) {
96 strbuf_release(&realpath);
f42ca31d 97 return error("unable to start editor '%s'", editor);
3d7747e3 98 }
f42ca31d 99
913ef360
PF
100 sigchain_push(SIGINT, SIG_IGN);
101 sigchain_push(SIGQUIT, SIG_IGN);
102 ret = finish_command(&p);
3d7747e3 103 strbuf_release(&realpath);
709ca730 104 sig = ret - 128;
913ef360
PF
105 sigchain_pop(SIGINT);
106 sigchain_pop(SIGQUIT);
1250857c
JK
107 if (sig == SIGINT || sig == SIGQUIT)
108 raise(sig);
abfb04d0
LS
109 if (print_waiting_for_editor && !is_terminal_dumb())
110 /*
cd1096b2
SG
111 * Erase the entire line to avoid wasting the
112 * vertical space.
abfb04d0 113 */
cd1096b2 114 term_clear_line();
48e1ca27
RJ
115 if (ret)
116 return error("there was a problem with the editor '%s'",
117 editor);
d82f33e2
SB
118 }
119
120 if (!buffer)
7198203a 121 return 0;
d82f33e2 122 if (strbuf_read_file(buffer, path, 0) < 0)
9f9a522c 123 return error_errno("could not read file '%s'", path);
7198203a 124 return 0;
d82f33e2 125}
2aed0181
AG
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}
4e120823 137
419dbb29
PS
138int strbuf_edit_interactively(struct repository *r,
139 struct strbuf *buffer, const char *path,
4e120823
EN
140 const char *const *env)
141{
419dbb29 142 struct strbuf sb = STRBUF_INIT;
4e120823
EN
143 int fd, res = 0;
144
bdfc07bf
PS
145 if (!is_absolute_path(path))
146 path = repo_git_path_append(r, &sb, "%s", path);
4e120823
EN
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
419dbb29 163 strbuf_release(&sb);
4e120823
EN
164 return res;
165}