]> git.ipfire.org Git - thirdparty/git.git/blame_incremental - editor.c
The fifth batch
[thirdparty/git.git] / editor.c
... / ...
CommitLineData
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 git_config_get_string_tmp("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}