Blame


1 9f7d7167 2018-04-29 stsp /*
2 5aa81393 2020-01-06 stsp * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
3 9f7d7167 2018-04-29 stsp *
4 9f7d7167 2018-04-29 stsp * Permission to use, copy, modify, and distribute this software for any
5 9f7d7167 2018-04-29 stsp * purpose with or without fee is hereby granted, provided that the above
6 9f7d7167 2018-04-29 stsp * copyright notice and this permission notice appear in all copies.
7 9f7d7167 2018-04-29 stsp *
8 9f7d7167 2018-04-29 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 9f7d7167 2018-04-29 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 9f7d7167 2018-04-29 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 9f7d7167 2018-04-29 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 9f7d7167 2018-04-29 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 9f7d7167 2018-04-29 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 9f7d7167 2018-04-29 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 9f7d7167 2018-04-29 stsp */
16 4fccd2fe 2023-03-08 thomas
17 4fccd2fe 2023-03-08 thomas #include "got_compat.h"
18 9f7d7167 2018-04-29 stsp
19 8b925c6c 2022-07-16 thomas #include <sys/queue.h>
20 ffd1d5e5 2018-06-23 stsp #include <sys/stat.h>
21 25791caa 2018-10-24 stsp #include <sys/ioctl.h>
22 80ddbec8 2018-04-29 stsp
23 0d6c6ee3 2020-05-20 stsp #include <ctype.h>
24 31120ada 2018-04-30 stsp #include <errno.h>
25 d24ddaa6 2022-02-26 thomas #if defined(__FreeBSD__) || defined(__APPLE__)
26 def2f970 2021-09-28 thomas #define _XOPEN_SOURCE_EXTENDED /* for ncurses wide-character functions */
27 def2f970 2021-09-28 thomas #endif
28 9f7d7167 2018-04-29 stsp #include <curses.h>
29 9f7d7167 2018-04-29 stsp #include <panel.h>
30 9f7d7167 2018-04-29 stsp #include <locale.h>
31 61266923 2020-01-14 stsp #include <signal.h>
32 9f7d7167 2018-04-29 stsp #include <stdlib.h>
33 ee85c5e8 2020-02-29 stsp #include <stdarg.h>
34 26ed57b2 2018-05-19 stsp #include <stdio.h>
35 9f7d7167 2018-04-29 stsp #include <getopt.h>
36 9f7d7167 2018-04-29 stsp #include <string.h>
37 9f7d7167 2018-04-29 stsp #include <err.h>
38 80ddbec8 2018-04-29 stsp #include <unistd.h>
39 26ed57b2 2018-05-19 stsp #include <limits.h>
40 61e69b96 2018-05-20 stsp #include <wchar.h>
41 788c352e 2018-06-16 stsp #include <time.h>
42 84451b3e 2018-07-10 stsp #include <pthread.h>
43 5036bf37 2018-09-24 stsp #include <libgen.h>
44 60493ae3 2019-06-20 stsp #include <regex.h>
45 dd038bc6 2021-09-21 thomas.ad
46 53ccebc2 2019-07-30 stsp #include "got_version.h"
47 9f7d7167 2018-04-29 stsp #include "got_error.h"
48 80ddbec8 2018-04-29 stsp #include "got_object.h"
49 80ddbec8 2018-04-29 stsp #include "got_reference.h"
50 80ddbec8 2018-04-29 stsp #include "got_repository.h"
51 80ddbec8 2018-04-29 stsp #include "got_diff.h"
52 511a516b 2018-05-19 stsp #include "got_opentemp.h"
53 00dfcb92 2018-06-11 stsp #include "got_utf8.h"
54 6fb7cd11 2019-08-22 stsp #include "got_cancel.h"
55 6fb7cd11 2019-08-22 stsp #include "got_commit_graph.h"
56 a70480e0 2018-06-23 stsp #include "got_blame.h"
57 c2db6724 2019-01-04 stsp #include "got_privsep.h"
58 1dd54920 2019-05-11 stsp #include "got_path.h"
59 b7165be3 2019-02-05 stsp #include "got_worktree.h"
60 66b04f8f 2023-07-19 thomas #include "got_keyword.h"
61 9f7d7167 2018-04-29 stsp
62 881b2d3e 2018-04-30 stsp #ifndef MIN
63 881b2d3e 2018-04-30 stsp #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
64 881b2d3e 2018-04-30 stsp #endif
65 881b2d3e 2018-04-30 stsp
66 2bd27830 2018-10-22 stsp #ifndef MAX
67 2bd27830 2018-10-22 stsp #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b))
68 2bd27830 2018-10-22 stsp #endif
69 2bd27830 2018-10-22 stsp
70 acf52a76 2021-09-21 thomas.ad #ifndef CTRL
71 a4292ac5 2019-05-12 jcs #define CTRL(x) ((x) & 0x1f)
72 acf52a76 2021-09-21 thomas.ad #endif
73 2bd27830 2018-10-22 stsp
74 9f7d7167 2018-04-29 stsp #ifndef nitems
75 9f7d7167 2018-04-29 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
76 9f7d7167 2018-04-29 stsp #endif
77 9f7d7167 2018-04-29 stsp
78 9f7d7167 2018-04-29 stsp struct tog_cmd {
79 c2301be8 2018-04-30 stsp const char *name;
80 9f7d7167 2018-04-29 stsp const struct got_error *(*cmd_main)(int, char *[]);
81 9f7d7167 2018-04-29 stsp void (*cmd_usage)(void);
82 9f7d7167 2018-04-29 stsp };
83 9f7d7167 2018-04-29 stsp
84 6879ba42 2020-10-01 naddy __dead static void usage(int, int);
85 4ed7e80c 2018-05-20 stsp __dead static void usage_log(void);
86 4ed7e80c 2018-05-20 stsp __dead static void usage_diff(void);
87 4ed7e80c 2018-05-20 stsp __dead static void usage_blame(void);
88 ffd1d5e5 2018-06-23 stsp __dead static void usage_tree(void);
89 6458efa5 2020-11-24 stsp __dead static void usage_ref(void);
90 9f7d7167 2018-04-29 stsp
91 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_log(int, char *[]);
92 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_diff(int, char *[]);
93 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_blame(int, char *[]);
94 ffd1d5e5 2018-06-23 stsp static const struct got_error* cmd_tree(int, char *[]);
95 6458efa5 2020-11-24 stsp static const struct got_error* cmd_ref(int, char *[]);
96 9f7d7167 2018-04-29 stsp
97 641a8ee6 2022-02-16 thomas static const struct tog_cmd tog_commands[] = {
98 5e070240 2019-06-22 stsp { "log", cmd_log, usage_log },
99 5e070240 2019-06-22 stsp { "diff", cmd_diff, usage_diff },
100 5e070240 2019-06-22 stsp { "blame", cmd_blame, usage_blame },
101 5e070240 2019-06-22 stsp { "tree", cmd_tree, usage_tree },
102 6458efa5 2020-11-24 stsp { "ref", cmd_ref, usage_ref },
103 9f7d7167 2018-04-29 stsp };
104 9f7d7167 2018-04-29 stsp
105 d6b05b5b 2018-08-04 stsp enum tog_view_type {
106 d6b05b5b 2018-08-04 stsp TOG_VIEW_DIFF,
107 d6b05b5b 2018-08-04 stsp TOG_VIEW_LOG,
108 ad80ab7b 2018-08-04 stsp TOG_VIEW_BLAME,
109 6458efa5 2020-11-24 stsp TOG_VIEW_TREE,
110 6458efa5 2020-11-24 stsp TOG_VIEW_REF,
111 fc2737d5 2022-09-15 thomas TOG_VIEW_HELP
112 fc2737d5 2022-09-15 thomas };
113 fc2737d5 2022-09-15 thomas
114 fc2737d5 2022-09-15 thomas /* Match _DIFF to _HELP with enum tog_view_type TOG_VIEW_* counterparts. */
115 fc2737d5 2022-09-15 thomas enum tog_keymap_type {
116 fc2737d5 2022-09-15 thomas TOG_KEYMAP_KEYS = -2,
117 fc2737d5 2022-09-15 thomas TOG_KEYMAP_GLOBAL,
118 fc2737d5 2022-09-15 thomas TOG_KEYMAP_DIFF,
119 fc2737d5 2022-09-15 thomas TOG_KEYMAP_LOG,
120 fc2737d5 2022-09-15 thomas TOG_KEYMAP_BLAME,
121 fc2737d5 2022-09-15 thomas TOG_KEYMAP_TREE,
122 fc2737d5 2022-09-15 thomas TOG_KEYMAP_REF,
123 fc2737d5 2022-09-15 thomas TOG_KEYMAP_HELP
124 d6b05b5b 2018-08-04 stsp };
125 c3e9aa98 2019-05-13 jcs
126 a5d43cac 2022-07-01 thomas enum tog_view_mode {
127 a5d43cac 2022-07-01 thomas TOG_VIEW_SPLIT_NONE,
128 a5d43cac 2022-07-01 thomas TOG_VIEW_SPLIT_VERT,
129 a5d43cac 2022-07-01 thomas TOG_VIEW_SPLIT_HRZN
130 a5d43cac 2022-07-01 thomas };
131 a5d43cac 2022-07-01 thomas
132 87a675e0 2023-04-22 thomas #define HSPLIT_SCALE 0.3f /* default horizontal split scale */
133 a5d43cac 2022-07-01 thomas
134 c3e9aa98 2019-05-13 jcs #define TOG_EOF_STRING "(END)"
135 d6b05b5b 2018-08-04 stsp
136 ba4f502b 2018-08-04 stsp struct commit_queue_entry {
137 ba4f502b 2018-08-04 stsp TAILQ_ENTRY(commit_queue_entry) entry;
138 ba4f502b 2018-08-04 stsp struct got_object_id *id;
139 ba4f502b 2018-08-04 stsp struct got_commit_object *commit;
140 1a76625f 2018-10-22 stsp int idx;
141 ba4f502b 2018-08-04 stsp };
142 ba4f502b 2018-08-04 stsp TAILQ_HEAD(commit_queue_head, commit_queue_entry);
143 ba4f502b 2018-08-04 stsp struct commit_queue {
144 ba4f502b 2018-08-04 stsp int ncommits;
145 ba4f502b 2018-08-04 stsp struct commit_queue_head head;
146 6d17833f 2019-11-08 stsp };
147 6d17833f 2019-11-08 stsp
148 f26dddb7 2019-11-08 stsp struct tog_color {
149 dbdddfee 2021-06-23 naddy STAILQ_ENTRY(tog_color) entry;
150 6d17833f 2019-11-08 stsp regex_t regex;
151 6d17833f 2019-11-08 stsp short colorpair;
152 15a087fe 2019-02-21 stsp };
153 dbdddfee 2021-06-23 naddy STAILQ_HEAD(tog_colors, tog_color);
154 11b20872 2019-11-08 stsp
155 d9dff0e5 2020-12-26 stsp static struct got_reflist_head tog_refs = TAILQ_HEAD_INITIALIZER(tog_refs);
156 51a10b52 2020-12-26 stsp static struct got_reflist_object_id_map *tog_refs_idmap;
157 349dfd1e 2023-07-23 thomas static struct {
158 349dfd1e 2023-07-23 thomas struct got_object_id *id;
159 349dfd1e 2023-07-23 thomas int idx;
160 349dfd1e 2023-07-23 thomas char marker;
161 349dfd1e 2023-07-23 thomas } tog_base_commit;
162 8295dece 2023-10-08 thomas static enum got_diff_algorithm tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
163 2183bbf6 2022-01-23 thomas
164 2183bbf6 2022-01-23 thomas static const struct got_error *
165 2183bbf6 2022-01-23 thomas tog_ref_cmp_by_name(void *arg, int *cmp, struct got_reference *re1,
166 2183bbf6 2022-01-23 thomas struct got_reference* re2)
167 2183bbf6 2022-01-23 thomas {
168 2183bbf6 2022-01-23 thomas const char *name1 = got_ref_get_name(re1);
169 2183bbf6 2022-01-23 thomas const char *name2 = got_ref_get_name(re2);
170 2183bbf6 2022-01-23 thomas int isbackup1, isbackup2;
171 2183bbf6 2022-01-23 thomas
172 2183bbf6 2022-01-23 thomas /* Sort backup refs towards the bottom of the list. */
173 2183bbf6 2022-01-23 thomas isbackup1 = strncmp(name1, "refs/got/backup/", 16) == 0;
174 2183bbf6 2022-01-23 thomas isbackup2 = strncmp(name2, "refs/got/backup/", 16) == 0;
175 2183bbf6 2022-01-23 thomas if (!isbackup1 && isbackup2) {
176 2183bbf6 2022-01-23 thomas *cmp = -1;
177 2183bbf6 2022-01-23 thomas return NULL;
178 2183bbf6 2022-01-23 thomas } else if (isbackup1 && !isbackup2) {
179 2183bbf6 2022-01-23 thomas *cmp = 1;
180 2183bbf6 2022-01-23 thomas return NULL;
181 2183bbf6 2022-01-23 thomas }
182 2183bbf6 2022-01-23 thomas
183 2183bbf6 2022-01-23 thomas *cmp = got_path_cmp(name1, name2, strlen(name1), strlen(name2));
184 2183bbf6 2022-01-23 thomas return NULL;
185 2183bbf6 2022-01-23 thomas }
186 51a10b52 2020-12-26 stsp
187 11b20872 2019-11-08 stsp static const struct got_error *
188 3bfadbd4 2021-11-20 thomas tog_load_refs(struct got_repository *repo, int sort_by_date)
189 51a10b52 2020-12-26 stsp {
190 51a10b52 2020-12-26 stsp const struct got_error *err;
191 51a10b52 2020-12-26 stsp
192 3bfadbd4 2021-11-20 thomas err = got_ref_list(&tog_refs, repo, NULL, sort_by_date ?
193 2183bbf6 2022-01-23 thomas got_ref_cmp_by_commit_timestamp_descending : tog_ref_cmp_by_name,
194 3bfadbd4 2021-11-20 thomas repo);
195 51a10b52 2020-12-26 stsp if (err)
196 51a10b52 2020-12-26 stsp return err;
197 51a10b52 2020-12-26 stsp
198 51a10b52 2020-12-26 stsp return got_reflist_object_id_map_create(&tog_refs_idmap, &tog_refs,
199 51a10b52 2020-12-26 stsp repo);
200 51a10b52 2020-12-26 stsp }
201 51a10b52 2020-12-26 stsp
202 51a10b52 2020-12-26 stsp static void
203 51a10b52 2020-12-26 stsp tog_free_refs(void)
204 51a10b52 2020-12-26 stsp {
205 51a10b52 2020-12-26 stsp if (tog_refs_idmap) {
206 f193b038 2020-12-26 stsp got_reflist_object_id_map_free(tog_refs_idmap);
207 51a10b52 2020-12-26 stsp tog_refs_idmap = NULL;
208 51a10b52 2020-12-26 stsp }
209 51a10b52 2020-12-26 stsp got_ref_list_free(&tog_refs);
210 51a10b52 2020-12-26 stsp }
211 51a10b52 2020-12-26 stsp
212 51a10b52 2020-12-26 stsp static const struct got_error *
213 11b20872 2019-11-08 stsp add_color(struct tog_colors *colors, const char *pattern,
214 11b20872 2019-11-08 stsp int idx, short color)
215 11b20872 2019-11-08 stsp {
216 11b20872 2019-11-08 stsp const struct got_error *err = NULL;
217 11b20872 2019-11-08 stsp struct tog_color *tc;
218 11b20872 2019-11-08 stsp int regerr = 0;
219 11b20872 2019-11-08 stsp
220 11b20872 2019-11-08 stsp if (idx < 1 || idx > COLOR_PAIRS - 1)
221 11b20872 2019-11-08 stsp return NULL;
222 11b20872 2019-11-08 stsp
223 11b20872 2019-11-08 stsp init_pair(idx, color, -1);
224 11b20872 2019-11-08 stsp
225 11b20872 2019-11-08 stsp tc = calloc(1, sizeof(*tc));
226 11b20872 2019-11-08 stsp if (tc == NULL)
227 11b20872 2019-11-08 stsp return got_error_from_errno("calloc");
228 11b20872 2019-11-08 stsp regerr = regcomp(&tc->regex, pattern,
229 11b20872 2019-11-08 stsp REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
230 11b20872 2019-11-08 stsp if (regerr) {
231 11b20872 2019-11-08 stsp static char regerr_msg[512];
232 11b20872 2019-11-08 stsp static char err_msg[512];
233 11b20872 2019-11-08 stsp regerror(regerr, &tc->regex, regerr_msg,
234 11b20872 2019-11-08 stsp sizeof(regerr_msg));
235 11b20872 2019-11-08 stsp snprintf(err_msg, sizeof(err_msg), "regcomp: %s",
236 11b20872 2019-11-08 stsp regerr_msg);
237 11b20872 2019-11-08 stsp err = got_error_msg(GOT_ERR_REGEX, err_msg);
238 11b20872 2019-11-08 stsp free(tc);
239 11b20872 2019-11-08 stsp return err;
240 11b20872 2019-11-08 stsp }
241 11b20872 2019-11-08 stsp tc->colorpair = idx;
242 dbdddfee 2021-06-23 naddy STAILQ_INSERT_HEAD(colors, tc, entry);
243 11b20872 2019-11-08 stsp return NULL;
244 11b20872 2019-11-08 stsp }
245 11b20872 2019-11-08 stsp
246 11b20872 2019-11-08 stsp static void
247 11b20872 2019-11-08 stsp free_colors(struct tog_colors *colors)
248 11b20872 2019-11-08 stsp {
249 11b20872 2019-11-08 stsp struct tog_color *tc;
250 11b20872 2019-11-08 stsp
251 dbdddfee 2021-06-23 naddy while (!STAILQ_EMPTY(colors)) {
252 dbdddfee 2021-06-23 naddy tc = STAILQ_FIRST(colors);
253 dbdddfee 2021-06-23 naddy STAILQ_REMOVE_HEAD(colors, entry);
254 11b20872 2019-11-08 stsp regfree(&tc->regex);
255 11b20872 2019-11-08 stsp free(tc);
256 11b20872 2019-11-08 stsp }
257 11b20872 2019-11-08 stsp }
258 11b20872 2019-11-08 stsp
259 ef20f542 2022-06-26 thomas static struct tog_color *
260 11b20872 2019-11-08 stsp get_color(struct tog_colors *colors, int colorpair)
261 11b20872 2019-11-08 stsp {
262 11b20872 2019-11-08 stsp struct tog_color *tc = NULL;
263 11b20872 2019-11-08 stsp
264 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(tc, colors, entry) {
265 11b20872 2019-11-08 stsp if (tc->colorpair == colorpair)
266 11b20872 2019-11-08 stsp return tc;
267 11b20872 2019-11-08 stsp }
268 11b20872 2019-11-08 stsp
269 11b20872 2019-11-08 stsp return NULL;
270 11b20872 2019-11-08 stsp }
271 11b20872 2019-11-08 stsp
272 11b20872 2019-11-08 stsp static int
273 11b20872 2019-11-08 stsp default_color_value(const char *envvar)
274 11b20872 2019-11-08 stsp {
275 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_DIFF_MINUS") == 0)
276 11b20872 2019-11-08 stsp return COLOR_MAGENTA;
277 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_DIFF_PLUS") == 0)
278 11b20872 2019-11-08 stsp return COLOR_CYAN;
279 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_DIFF_CHUNK_HEADER") == 0)
280 11b20872 2019-11-08 stsp return COLOR_YELLOW;
281 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_DIFF_META") == 0)
282 11b20872 2019-11-08 stsp return COLOR_GREEN;
283 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_TREE_SUBMODULE") == 0)
284 11b20872 2019-11-08 stsp return COLOR_MAGENTA;
285 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_TREE_SYMLINK") == 0)
286 91b8c405 2020-01-25 stsp return COLOR_MAGENTA;
287 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_TREE_DIRECTORY") == 0)
288 91b8c405 2020-01-25 stsp return COLOR_CYAN;
289 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_TREE_EXECUTABLE") == 0)
290 11b20872 2019-11-08 stsp return COLOR_GREEN;
291 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_COMMIT") == 0)
292 11b20872 2019-11-08 stsp return COLOR_GREEN;
293 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_AUTHOR") == 0)
294 11b20872 2019-11-08 stsp return COLOR_CYAN;
295 11b20872 2019-11-08 stsp if (strcmp(envvar, "TOG_COLOR_DATE") == 0)
296 11b20872 2019-11-08 stsp return COLOR_YELLOW;
297 6458efa5 2020-11-24 stsp if (strcmp(envvar, "TOG_COLOR_REFS_HEADS") == 0)
298 6458efa5 2020-11-24 stsp return COLOR_GREEN;
299 6458efa5 2020-11-24 stsp if (strcmp(envvar, "TOG_COLOR_REFS_TAGS") == 0)
300 6458efa5 2020-11-24 stsp return COLOR_MAGENTA;
301 6458efa5 2020-11-24 stsp if (strcmp(envvar, "TOG_COLOR_REFS_REMOTES") == 0)
302 6458efa5 2020-11-24 stsp return COLOR_YELLOW;
303 2183bbf6 2022-01-23 thomas if (strcmp(envvar, "TOG_COLOR_REFS_BACKUP") == 0)
304 2183bbf6 2022-01-23 thomas return COLOR_CYAN;
305 11b20872 2019-11-08 stsp
306 11b20872 2019-11-08 stsp return -1;
307 11b20872 2019-11-08 stsp }
308 11b20872 2019-11-08 stsp
309 11b20872 2019-11-08 stsp static int
310 11b20872 2019-11-08 stsp get_color_value(const char *envvar)
311 11b20872 2019-11-08 stsp {
312 11b20872 2019-11-08 stsp const char *val = getenv(envvar);
313 11b20872 2019-11-08 stsp
314 11b20872 2019-11-08 stsp if (val == NULL)
315 11b20872 2019-11-08 stsp return default_color_value(envvar);
316 15a087fe 2019-02-21 stsp
317 11b20872 2019-11-08 stsp if (strcasecmp(val, "black") == 0)
318 11b20872 2019-11-08 stsp return COLOR_BLACK;
319 11b20872 2019-11-08 stsp if (strcasecmp(val, "red") == 0)
320 11b20872 2019-11-08 stsp return COLOR_RED;
321 11b20872 2019-11-08 stsp if (strcasecmp(val, "green") == 0)
322 11b20872 2019-11-08 stsp return COLOR_GREEN;
323 11b20872 2019-11-08 stsp if (strcasecmp(val, "yellow") == 0)
324 11b20872 2019-11-08 stsp return COLOR_YELLOW;
325 11b20872 2019-11-08 stsp if (strcasecmp(val, "blue") == 0)
326 11b20872 2019-11-08 stsp return COLOR_BLUE;
327 11b20872 2019-11-08 stsp if (strcasecmp(val, "magenta") == 0)
328 11b20872 2019-11-08 stsp return COLOR_MAGENTA;
329 11b20872 2019-11-08 stsp if (strcasecmp(val, "cyan") == 0)
330 11b20872 2019-11-08 stsp return COLOR_CYAN;
331 11b20872 2019-11-08 stsp if (strcasecmp(val, "white") == 0)
332 11b20872 2019-11-08 stsp return COLOR_WHITE;
333 11b20872 2019-11-08 stsp if (strcasecmp(val, "default") == 0)
334 11b20872 2019-11-08 stsp return -1;
335 11b20872 2019-11-08 stsp
336 11b20872 2019-11-08 stsp return default_color_value(envvar);
337 11b20872 2019-11-08 stsp }
338 11b20872 2019-11-08 stsp
339 15a087fe 2019-02-21 stsp struct tog_diff_view_state {
340 15a087fe 2019-02-21 stsp struct got_object_id *id1, *id2;
341 3dbaef42 2020-11-24 stsp const char *label1, *label2;
342 a0f32f33 2022-06-13 thomas FILE *f, *f1, *f2;
343 19a6a6b5 2022-07-01 thomas int fd1, fd2;
344 82c78e96 2022-08-06 thomas int lineno;
345 15a087fe 2019-02-21 stsp int first_displayed_line;
346 15a087fe 2019-02-21 stsp int last_displayed_line;
347 15a087fe 2019-02-21 stsp int eof;
348 15a087fe 2019-02-21 stsp int diff_context;
349 3dbaef42 2020-11-24 stsp int ignore_whitespace;
350 64453f7e 2020-11-21 stsp int force_text_diff;
351 15a087fe 2019-02-21 stsp struct got_repository *repo;
352 82c78e96 2022-08-06 thomas struct got_diff_line *lines;
353 fe621944 2020-11-10 stsp size_t nlines;
354 f44b1f58 2020-02-02 tracey int matched_line;
355 f44b1f58 2020-02-02 tracey int selected_line;
356 15a087fe 2019-02-21 stsp
357 4fc71f3b 2022-07-12 thomas /* passed from log or blame view; may be NULL */
358 4fc71f3b 2022-07-12 thomas struct tog_view *parent_view;
359 b01e7d3b 2018-08-04 stsp };
360 b01e7d3b 2018-08-04 stsp
361 1a76625f 2018-10-22 stsp pthread_mutex_t tog_mutex = PTHREAD_MUTEX_INITIALIZER;
362 f2d749db 2022-07-12 thomas static volatile sig_atomic_t tog_thread_error;
363 1a76625f 2018-10-22 stsp
364 1a76625f 2018-10-22 stsp struct tog_log_thread_args {
365 1a76625f 2018-10-22 stsp pthread_cond_t need_commits;
366 7c1452c1 2020-03-26 stsp pthread_cond_t commit_loaded;
367 1a76625f 2018-10-22 stsp int commits_needed;
368 fb280deb 2021-08-30 stsp int load_all;
369 b01e7d3b 2018-08-04 stsp struct got_commit_graph *graph;
370 7e8004ba 2022-09-11 thomas struct commit_queue *real_commits;
371 1a76625f 2018-10-22 stsp const char *in_repo_path;
372 1a76625f 2018-10-22 stsp struct got_object_id *start_id;
373 1a76625f 2018-10-22 stsp struct got_repository *repo;
374 1af5eddf 2022-06-23 thomas int *pack_fds;
375 1a76625f 2018-10-22 stsp int log_complete;
376 92845f09 2023-07-26 thomas pthread_cond_t log_loaded;
377 1a76625f 2018-10-22 stsp sig_atomic_t *quit;
378 1a76625f 2018-10-22 stsp struct commit_queue_entry **first_displayed_entry;
379 1a76625f 2018-10-22 stsp struct commit_queue_entry **selected_entry;
380 13add988 2019-10-15 stsp int *searching;
381 13add988 2019-10-15 stsp int *search_next_done;
382 13add988 2019-10-15 stsp regex_t *regex;
383 7e8004ba 2022-09-11 thomas int *limiting;
384 7e8004ba 2022-09-11 thomas int limit_match;
385 7e8004ba 2022-09-11 thomas regex_t *limit_regex;
386 7e8004ba 2022-09-11 thomas struct commit_queue *limit_commits;
387 92845f09 2023-07-26 thomas struct got_worktree *worktree;
388 92845f09 2023-07-26 thomas int need_commit_marker;
389 1a76625f 2018-10-22 stsp };
390 1a76625f 2018-10-22 stsp
391 1a76625f 2018-10-22 stsp struct tog_log_view_state {
392 7e8004ba 2022-09-11 thomas struct commit_queue *commits;
393 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *first_displayed_entry;
394 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *last_displayed_entry;
395 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *selected_entry;
396 7e8004ba 2022-09-11 thomas struct commit_queue real_commits;
397 b01e7d3b 2018-08-04 stsp int selected;
398 b01e7d3b 2018-08-04 stsp char *in_repo_path;
399 9cd7cbd1 2020-12-07 stsp char *head_ref_name;
400 b672a97a 2020-01-27 stsp int log_branches;
401 b01e7d3b 2018-08-04 stsp struct got_repository *repo;
402 5036bf37 2018-09-24 stsp struct got_object_id *start_id;
403 1a76625f 2018-10-22 stsp sig_atomic_t quit;
404 1a76625f 2018-10-22 stsp pthread_t thread;
405 1a76625f 2018-10-22 stsp struct tog_log_thread_args thread_args;
406 60493ae3 2019-06-20 stsp struct commit_queue_entry *matched_entry;
407 96e2b566 2019-07-08 stsp struct commit_queue_entry *search_entry;
408 11b20872 2019-11-08 stsp struct tog_colors colors;
409 f69c5a46 2022-07-19 thomas int use_committer;
410 7e8004ba 2022-09-11 thomas int limit_view;
411 7e8004ba 2022-09-11 thomas regex_t limit_regex;
412 7e8004ba 2022-09-11 thomas struct commit_queue limit_commits;
413 ba4f502b 2018-08-04 stsp };
414 11b20872 2019-11-08 stsp
415 11b20872 2019-11-08 stsp #define TOG_COLOR_DIFF_MINUS 1
416 11b20872 2019-11-08 stsp #define TOG_COLOR_DIFF_PLUS 2
417 11b20872 2019-11-08 stsp #define TOG_COLOR_DIFF_CHUNK_HEADER 3
418 11b20872 2019-11-08 stsp #define TOG_COLOR_DIFF_META 4
419 11b20872 2019-11-08 stsp #define TOG_COLOR_TREE_SUBMODULE 5
420 11b20872 2019-11-08 stsp #define TOG_COLOR_TREE_SYMLINK 6
421 11b20872 2019-11-08 stsp #define TOG_COLOR_TREE_DIRECTORY 7
422 11b20872 2019-11-08 stsp #define TOG_COLOR_TREE_EXECUTABLE 8
423 11b20872 2019-11-08 stsp #define TOG_COLOR_COMMIT 9
424 11b20872 2019-11-08 stsp #define TOG_COLOR_AUTHOR 10
425 bf30f154 2020-12-07 naddy #define TOG_COLOR_DATE 11
426 6458efa5 2020-11-24 stsp #define TOG_COLOR_REFS_HEADS 12
427 6458efa5 2020-11-24 stsp #define TOG_COLOR_REFS_TAGS 13
428 6458efa5 2020-11-24 stsp #define TOG_COLOR_REFS_REMOTES 14
429 2183bbf6 2022-01-23 thomas #define TOG_COLOR_REFS_BACKUP 15
430 ba4f502b 2018-08-04 stsp
431 e9424729 2018-08-04 stsp struct tog_blame_cb_args {
432 e9424729 2018-08-04 stsp struct tog_blame_line *lines; /* one per line */
433 e9424729 2018-08-04 stsp int nlines;
434 e9424729 2018-08-04 stsp
435 e9424729 2018-08-04 stsp struct tog_view *view;
436 e9424729 2018-08-04 stsp struct got_object_id *commit_id;
437 e9424729 2018-08-04 stsp int *quit;
438 e9424729 2018-08-04 stsp };
439 e9424729 2018-08-04 stsp
440 e9424729 2018-08-04 stsp struct tog_blame_thread_args {
441 e9424729 2018-08-04 stsp const char *path;
442 e9424729 2018-08-04 stsp struct got_repository *repo;
443 e9424729 2018-08-04 stsp struct tog_blame_cb_args *cb_args;
444 e9424729 2018-08-04 stsp int *complete;
445 fc06ba56 2019-08-22 stsp got_cancel_cb cancel_cb;
446 fc06ba56 2019-08-22 stsp void *cancel_arg;
447 1134ebde 2023-04-22 thomas pthread_cond_t blame_complete;
448 e9424729 2018-08-04 stsp };
449 e9424729 2018-08-04 stsp
450 e9424729 2018-08-04 stsp struct tog_blame {
451 e9424729 2018-08-04 stsp FILE *f;
452 be659d10 2020-11-18 stsp off_t filesize;
453 e9424729 2018-08-04 stsp struct tog_blame_line *lines;
454 6fcac457 2018-11-19 stsp int nlines;
455 6c4c42e0 2019-06-24 stsp off_t *line_offsets;
456 e9424729 2018-08-04 stsp pthread_t thread;
457 e9424729 2018-08-04 stsp struct tog_blame_thread_args thread_args;
458 e9424729 2018-08-04 stsp struct tog_blame_cb_args cb_args;
459 e9424729 2018-08-04 stsp const char *path;
460 7cd52833 2022-06-23 thomas int *pack_fds;
461 e9424729 2018-08-04 stsp };
462 e9424729 2018-08-04 stsp
463 7cbe629d 2018-08-04 stsp struct tog_blame_view_state {
464 7cbe629d 2018-08-04 stsp int first_displayed_line;
465 7cbe629d 2018-08-04 stsp int last_displayed_line;
466 7cbe629d 2018-08-04 stsp int selected_line;
467 4fc71f3b 2022-07-12 thomas int last_diffed_line;
468 7cbe629d 2018-08-04 stsp int blame_complete;
469 e5a0f69f 2018-08-18 stsp int eof;
470 e5a0f69f 2018-08-18 stsp int done;
471 7cbe629d 2018-08-04 stsp struct got_object_id_queue blamed_commits;
472 7cbe629d 2018-08-04 stsp struct got_object_qid *blamed_commit;
473 e5a0f69f 2018-08-18 stsp char *path;
474 7cbe629d 2018-08-04 stsp struct got_repository *repo;
475 ad80ab7b 2018-08-04 stsp struct got_object_id *commit_id;
476 2a31b33b 2022-07-23 thomas struct got_object_id *id_to_log;
477 e9424729 2018-08-04 stsp struct tog_blame blame;
478 6c4c42e0 2019-06-24 stsp int matched_line;
479 11b20872 2019-11-08 stsp struct tog_colors colors;
480 ad80ab7b 2018-08-04 stsp };
481 ad80ab7b 2018-08-04 stsp
482 ad80ab7b 2018-08-04 stsp struct tog_parent_tree {
483 ad80ab7b 2018-08-04 stsp TAILQ_ENTRY(tog_parent_tree) entry;
484 ad80ab7b 2018-08-04 stsp struct got_tree_object *tree;
485 ad80ab7b 2018-08-04 stsp struct got_tree_entry *first_displayed_entry;
486 ad80ab7b 2018-08-04 stsp struct got_tree_entry *selected_entry;
487 ad80ab7b 2018-08-04 stsp int selected;
488 ad80ab7b 2018-08-04 stsp };
489 ad80ab7b 2018-08-04 stsp
490 ad80ab7b 2018-08-04 stsp TAILQ_HEAD(tog_parent_trees, tog_parent_tree);
491 ad80ab7b 2018-08-04 stsp
492 ad80ab7b 2018-08-04 stsp struct tog_tree_view_state {
493 ad80ab7b 2018-08-04 stsp char *tree_label;
494 bc573f3b 2021-07-10 stsp struct got_object_id *commit_id;/* commit which this tree belongs to */
495 bc573f3b 2021-07-10 stsp struct got_tree_object *root; /* the commit's root tree entry */
496 bc573f3b 2021-07-10 stsp struct got_tree_object *tree; /* currently displayed (sub-)tree */
497 ad80ab7b 2018-08-04 stsp struct got_tree_entry *first_displayed_entry;
498 ad80ab7b 2018-08-04 stsp struct got_tree_entry *last_displayed_entry;
499 ad80ab7b 2018-08-04 stsp struct got_tree_entry *selected_entry;
500 416a95c5 2019-01-24 stsp int ndisplayed, selected, show_ids;
501 bc573f3b 2021-07-10 stsp struct tog_parent_trees parents; /* parent trees of current sub-tree */
502 9cd7cbd1 2020-12-07 stsp char *head_ref_name;
503 ad80ab7b 2018-08-04 stsp struct got_repository *repo;
504 7c32bd05 2019-06-22 stsp struct got_tree_entry *matched_entry;
505 6458efa5 2020-11-24 stsp struct tog_colors colors;
506 6458efa5 2020-11-24 stsp };
507 6458efa5 2020-11-24 stsp
508 6458efa5 2020-11-24 stsp struct tog_reflist_entry {
509 6458efa5 2020-11-24 stsp TAILQ_ENTRY(tog_reflist_entry) entry;
510 6458efa5 2020-11-24 stsp struct got_reference *ref;
511 6458efa5 2020-11-24 stsp int idx;
512 6458efa5 2020-11-24 stsp };
513 6458efa5 2020-11-24 stsp
514 6458efa5 2020-11-24 stsp TAILQ_HEAD(tog_reflist_head, tog_reflist_entry);
515 6458efa5 2020-11-24 stsp
516 6458efa5 2020-11-24 stsp struct tog_ref_view_state {
517 dae613fa 2020-12-26 stsp struct tog_reflist_head refs;
518 6458efa5 2020-11-24 stsp struct tog_reflist_entry *first_displayed_entry;
519 6458efa5 2020-11-24 stsp struct tog_reflist_entry *last_displayed_entry;
520 6458efa5 2020-11-24 stsp struct tog_reflist_entry *selected_entry;
521 84227eb1 2022-06-23 thomas int nrefs, ndisplayed, selected, show_date, show_ids, sort_by_date;
522 6458efa5 2020-11-24 stsp struct got_repository *repo;
523 6458efa5 2020-11-24 stsp struct tog_reflist_entry *matched_entry;
524 bddb1296 2019-11-08 stsp struct tog_colors colors;
525 fc2737d5 2022-09-15 thomas };
526 fc2737d5 2022-09-15 thomas
527 fc2737d5 2022-09-15 thomas struct tog_help_view_state {
528 fc2737d5 2022-09-15 thomas FILE *f;
529 fc2737d5 2022-09-15 thomas off_t *line_offsets;
530 fc2737d5 2022-09-15 thomas size_t nlines;
531 fc2737d5 2022-09-15 thomas int lineno;
532 fc2737d5 2022-09-15 thomas int first_displayed_line;
533 fc2737d5 2022-09-15 thomas int last_displayed_line;
534 fc2737d5 2022-09-15 thomas int eof;
535 fc2737d5 2022-09-15 thomas int matched_line;
536 fc2737d5 2022-09-15 thomas int selected_line;
537 fc2737d5 2022-09-15 thomas int all;
538 fc2737d5 2022-09-15 thomas enum tog_keymap_type type;
539 fc2737d5 2022-09-15 thomas };
540 fc2737d5 2022-09-15 thomas
541 fc2737d5 2022-09-15 thomas #define GENERATE_HELP \
542 fc2737d5 2022-09-15 thomas KEYMAP_("Global", TOG_KEYMAP_GLOBAL), \
543 fc2737d5 2022-09-15 thomas KEY_("H F1", "Open view-specific help (double tap for all help)"), \
544 fc2737d5 2022-09-15 thomas KEY_("k C-p Up", "Move cursor or page up one line"), \
545 fc2737d5 2022-09-15 thomas KEY_("j C-n Down", "Move cursor or page down one line"), \
546 fc2737d5 2022-09-15 thomas KEY_("C-b b PgUp", "Scroll the view up one page"), \
547 fc2737d5 2022-09-15 thomas KEY_("C-f f PgDn Space", "Scroll the view down one page"), \
548 fc2737d5 2022-09-15 thomas KEY_("C-u u", "Scroll the view up one half page"), \
549 fc2737d5 2022-09-15 thomas KEY_("C-d d", "Scroll the view down one half page"), \
550 aa7a1117 2023-01-09 thomas KEY_("g", "Go to line N (default: first line)"), \
551 aa7a1117 2023-01-09 thomas KEY_("Home =", "Go to the first line"), \
552 aa7a1117 2023-01-09 thomas KEY_("G", "Go to line N (default: last line)"), \
553 aa7a1117 2023-01-09 thomas KEY_("End *", "Go to the last line"), \
554 fc2737d5 2022-09-15 thomas KEY_("l Right", "Scroll the view right"), \
555 fc2737d5 2022-09-15 thomas KEY_("h Left", "Scroll the view left"), \
556 fc2737d5 2022-09-15 thomas KEY_("$", "Scroll view to the rightmost position"), \
557 fc2737d5 2022-09-15 thomas KEY_("0", "Scroll view to the leftmost position"), \
558 fc2737d5 2022-09-15 thomas KEY_("-", "Decrease size of the focussed split"), \
559 fc2737d5 2022-09-15 thomas KEY_("+", "Increase size of the focussed split"), \
560 fc2737d5 2022-09-15 thomas KEY_("Tab", "Switch focus between views"), \
561 fc2737d5 2022-09-15 thomas KEY_("F", "Toggle fullscreen mode"), \
562 c282f787 2023-04-22 thomas KEY_("S", "Switch split-screen layout"), \
563 fc2737d5 2022-09-15 thomas KEY_("/", "Open prompt to enter search term"), \
564 fc2737d5 2022-09-15 thomas KEY_("n", "Find next line/token matching the current search term"), \
565 fc2737d5 2022-09-15 thomas KEY_("N", "Find previous line/token matching the current search term"),\
566 06ff88bb 2022-09-19 thomas KEY_("q", "Quit the focussed view; Quit help screen"), \
567 fc2737d5 2022-09-15 thomas KEY_("Q", "Quit tog"), \
568 fc2737d5 2022-09-15 thomas \
569 d0d3e7a4 2022-09-23 thomas KEYMAP_("Log view", TOG_KEYMAP_LOG), \
570 fc2737d5 2022-09-15 thomas KEY_("< ,", "Move cursor up one commit"), \
571 fc2737d5 2022-09-15 thomas KEY_("> .", "Move cursor down one commit"), \
572 fc2737d5 2022-09-15 thomas KEY_("Enter", "Open diff view of the selected commit"), \
573 fc2737d5 2022-09-15 thomas KEY_("B", "Reload the log view and toggle display of merged commits"), \
574 fc2737d5 2022-09-15 thomas KEY_("R", "Open ref view of all repository references"), \
575 fc2737d5 2022-09-15 thomas KEY_("T", "Display tree view of the repository from the selected" \
576 fc2737d5 2022-09-15 thomas " commit"), \
577 fc2737d5 2022-09-15 thomas KEY_("@", "Toggle between displaying author and committer name"), \
578 fc2737d5 2022-09-15 thomas KEY_("&", "Open prompt to enter term to limit commits displayed"), \
579 fc2737d5 2022-09-15 thomas KEY_("C-g Backspace", "Cancel current search or log operation"), \
580 fc2737d5 2022-09-15 thomas KEY_("C-l", "Reload the log view with new commits in the repository"), \
581 fc2737d5 2022-09-15 thomas \
582 d0d3e7a4 2022-09-23 thomas KEYMAP_("Diff view", TOG_KEYMAP_DIFF), \
583 fc2737d5 2022-09-15 thomas KEY_("K < ,", "Display diff of next line in the file/log entry"), \
584 fc2737d5 2022-09-15 thomas KEY_("J > .", "Display diff of previous line in the file/log entry"), \
585 fc2737d5 2022-09-15 thomas KEY_("A", "Toggle between Myers and Patience diff algorithm"), \
586 fc2737d5 2022-09-15 thomas KEY_("a", "Toggle treatment of file as ASCII irrespective of binary" \
587 fc2737d5 2022-09-15 thomas " data"), \
588 fc2737d5 2022-09-15 thomas KEY_("(", "Go to the previous file in the diff"), \
589 fc2737d5 2022-09-15 thomas KEY_(")", "Go to the next file in the diff"), \
590 fc2737d5 2022-09-15 thomas KEY_("{", "Go to the previous hunk in the diff"), \
591 fc2737d5 2022-09-15 thomas KEY_("}", "Go to the next hunk in the diff"), \
592 fc2737d5 2022-09-15 thomas KEY_("[", "Decrease the number of context lines"), \
593 fc2737d5 2022-09-15 thomas KEY_("]", "Increase the number of context lines"), \
594 fc2737d5 2022-09-15 thomas KEY_("w", "Toggle ignore whitespace-only changes in the diff"), \
595 fc2737d5 2022-09-15 thomas \
596 d0d3e7a4 2022-09-23 thomas KEYMAP_("Blame view", TOG_KEYMAP_BLAME), \
597 fc2737d5 2022-09-15 thomas KEY_("Enter", "Display diff view of the selected line's commit"), \
598 fc2737d5 2022-09-15 thomas KEY_("A", "Toggle diff algorithm between Myers and Patience"), \
599 fc2737d5 2022-09-15 thomas KEY_("L", "Open log view for the currently selected annotated line"), \
600 fc2737d5 2022-09-15 thomas KEY_("C", "Reload view with the previously blamed commit"), \
601 fc2737d5 2022-09-15 thomas KEY_("c", "Reload view with the version of the file found in the" \
602 fc2737d5 2022-09-15 thomas " selected line's commit"), \
603 fc2737d5 2022-09-15 thomas KEY_("p", "Reload view with the version of the file found in the" \
604 fc2737d5 2022-09-15 thomas " selected line's parent commit"), \
605 fc2737d5 2022-09-15 thomas \
606 d0d3e7a4 2022-09-23 thomas KEYMAP_("Tree view", TOG_KEYMAP_TREE), \
607 fc2737d5 2022-09-15 thomas KEY_("Enter", "Enter selected directory or open blame view of the" \
608 fc2737d5 2022-09-15 thomas " selected file"), \
609 fc2737d5 2022-09-15 thomas KEY_("L", "Open log view for the selected entry"), \
610 fc2737d5 2022-09-15 thomas KEY_("R", "Open ref view of all repository references"), \
611 fc2737d5 2022-09-15 thomas KEY_("i", "Show object IDs for all tree entries"), \
612 fc2737d5 2022-09-15 thomas KEY_("Backspace", "Return to the parent directory"), \
613 fc2737d5 2022-09-15 thomas \
614 d0d3e7a4 2022-09-23 thomas KEYMAP_("Ref view", TOG_KEYMAP_REF), \
615 fc2737d5 2022-09-15 thomas KEY_("Enter", "Display log view of the selected reference"), \
616 fc2737d5 2022-09-15 thomas KEY_("T", "Display tree view of the selected reference"), \
617 fc2737d5 2022-09-15 thomas KEY_("i", "Toggle display of IDs for all non-symbolic references"), \
618 fc2737d5 2022-09-15 thomas KEY_("m", "Toggle display of last modified date for each reference"), \
619 fc2737d5 2022-09-15 thomas KEY_("o", "Toggle reference sort order (name -> timestamp)"), \
620 fc2737d5 2022-09-15 thomas KEY_("C-l", "Reload view with all repository references")
621 fc2737d5 2022-09-15 thomas
622 fc2737d5 2022-09-15 thomas struct tog_key_map {
623 fc2737d5 2022-09-15 thomas const char *keys;
624 fc2737d5 2022-09-15 thomas const char *info;
625 fc2737d5 2022-09-15 thomas enum tog_keymap_type type;
626 7cbe629d 2018-08-04 stsp };
627 7cbe629d 2018-08-04 stsp
628 b85a3496 2023-04-14 thomas /* curses io for tog regress */
629 b85a3496 2023-04-14 thomas struct tog_io {
630 b85a3496 2023-04-14 thomas FILE *cin;
631 b85a3496 2023-04-14 thomas FILE *cout;
632 b85a3496 2023-04-14 thomas FILE *f;
633 5b3a801d 2023-04-22 thomas FILE *sdump;
634 1fc091f3 2023-09-05 thomas char *input_str;
635 8e778ade 2023-04-22 thomas int wait_for_ui;
636 557d3365 2023-04-14 thomas } tog_io;
637 557d3365 2023-04-14 thomas static int using_mock_io;
638 b85a3496 2023-04-14 thomas
639 13bc6832 2023-04-22 thomas #define TOG_KEY_SCRDUMP SHRT_MIN
640 b85a3496 2023-04-14 thomas
641 669b5ffa 2018-10-07 stsp /*
642 669b5ffa 2018-10-07 stsp * We implement two types of views: parent views and child views.
643 669b5ffa 2018-10-07 stsp *
644 e78dc838 2020-12-04 stsp * The 'Tab' key switches focus between a parent view and its child view.
645 669b5ffa 2018-10-07 stsp * Child views are shown side-by-side to their parent view, provided
646 669b5ffa 2018-10-07 stsp * there is enough screen estate.
647 669b5ffa 2018-10-07 stsp *
648 669b5ffa 2018-10-07 stsp * When a new view is opened from within a parent view, this new view
649 669b5ffa 2018-10-07 stsp * becomes a child view of the parent view, replacing any existing child.
650 669b5ffa 2018-10-07 stsp *
651 669b5ffa 2018-10-07 stsp * When a new view is opened from within a child view, this new view
652 669b5ffa 2018-10-07 stsp * becomes a parent view which will obscure the views below until the
653 669b5ffa 2018-10-07 stsp * user quits the new parent view by typing 'q'.
654 669b5ffa 2018-10-07 stsp *
655 669b5ffa 2018-10-07 stsp * This list of views contains parent views only.
656 669b5ffa 2018-10-07 stsp * Child views are only pointed to by their parent view.
657 669b5ffa 2018-10-07 stsp */
658 bcbd79e2 2018-08-19 stsp TAILQ_HEAD(tog_view_list_head, tog_view);
659 669b5ffa 2018-10-07 stsp
660 cc3c9aac 2018-08-01 stsp struct tog_view {
661 e5a0f69f 2018-08-18 stsp TAILQ_ENTRY(tog_view) entry;
662 26ed57b2 2018-05-19 stsp WINDOW *window;
663 26ed57b2 2018-05-19 stsp PANEL *panel;
664 a5d43cac 2022-07-01 thomas int nlines, ncols, begin_y, begin_x; /* based on split height/width */
665 53d2bdd3 2022-07-10 thomas int resized_y, resized_x; /* begin_y/x based on user resizing */
666 05171be4 2022-06-23 thomas int maxx, x; /* max column and current start column */
667 f7d12f7e 2018-08-01 stsp int lines, cols; /* copies of LINES and COLS */
668 a5d43cac 2022-07-01 thomas int nscrolled, offset; /* lines scrolled and hsplit line offset */
669 07dd3ed3 2022-08-06 thomas int gline, hiline; /* navigate to and highlight this nG line */
670 07b0611c 2022-06-23 thomas int ch, count; /* current keymap and count prefix */
671 ea0bff04 2022-07-19 thomas int resized; /* set when in a resize event */
672 e78dc838 2020-12-04 stsp int focussed; /* Only set on one parent or child view at a time. */
673 9970f7fc 2020-12-03 stsp int dying;
674 669b5ffa 2018-10-07 stsp struct tog_view *parent;
675 669b5ffa 2018-10-07 stsp struct tog_view *child;
676 5dc9f4bc 2018-08-04 stsp
677 e78dc838 2020-12-04 stsp /*
678 e78dc838 2020-12-04 stsp * This flag is initially set on parent views when a new child view
679 e78dc838 2020-12-04 stsp * is created. It gets toggled when the 'Tab' key switches focus
680 e78dc838 2020-12-04 stsp * between parent and child.
681 e78dc838 2020-12-04 stsp * The flag indicates whether focus should be passed on to our child
682 e78dc838 2020-12-04 stsp * view if this parent view gets picked for focus after another parent
683 e78dc838 2020-12-04 stsp * view was closed. This prevents child views from losing focus in such
684 e78dc838 2020-12-04 stsp * situations.
685 e78dc838 2020-12-04 stsp */
686 e78dc838 2020-12-04 stsp int focus_child;
687 e78dc838 2020-12-04 stsp
688 a5d43cac 2022-07-01 thomas enum tog_view_mode mode;
689 5dc9f4bc 2018-08-04 stsp /* type-specific state */
690 d6b05b5b 2018-08-04 stsp enum tog_view_type type;
691 5dc9f4bc 2018-08-04 stsp union {
692 b01e7d3b 2018-08-04 stsp struct tog_diff_view_state diff;
693 b01e7d3b 2018-08-04 stsp struct tog_log_view_state log;
694 7cbe629d 2018-08-04 stsp struct tog_blame_view_state blame;
695 ad80ab7b 2018-08-04 stsp struct tog_tree_view_state tree;
696 6458efa5 2020-11-24 stsp struct tog_ref_view_state ref;
697 fc2737d5 2022-09-15 thomas struct tog_help_view_state help;
698 5dc9f4bc 2018-08-04 stsp } state;
699 e5a0f69f 2018-08-18 stsp
700 e5a0f69f 2018-08-18 stsp const struct got_error *(*show)(struct tog_view *);
701 e5a0f69f 2018-08-18 stsp const struct got_error *(*input)(struct tog_view **,
702 e78dc838 2020-12-04 stsp struct tog_view *, int);
703 adf4c9e0 2022-07-03 thomas const struct got_error *(*reset)(struct tog_view *);
704 ea0bff04 2022-07-19 thomas const struct got_error *(*resize)(struct tog_view *, int);
705 e5a0f69f 2018-08-18 stsp const struct got_error *(*close)(struct tog_view *);
706 60493ae3 2019-06-20 stsp
707 60493ae3 2019-06-20 stsp const struct got_error *(*search_start)(struct tog_view *);
708 60493ae3 2019-06-20 stsp const struct got_error *(*search_next)(struct tog_view *);
709 2a7d3cd7 2022-09-17 thomas void (*search_setup)(struct tog_view *, FILE **, off_t **, size_t *,
710 2a7d3cd7 2022-09-17 thomas int **, int **, int **, int **);
711 c0c4acc8 2021-01-24 stsp int search_started;
712 60493ae3 2019-06-20 stsp int searching;
713 b1bf1435 2019-06-21 stsp #define TOG_SEARCH_FORWARD 1
714 b1bf1435 2019-06-21 stsp #define TOG_SEARCH_BACKWARD 2
715 60493ae3 2019-06-20 stsp int search_next_done;
716 8f4ed634 2020-03-26 stsp #define TOG_SEARCH_HAVE_MORE 1
717 8f4ed634 2020-03-26 stsp #define TOG_SEARCH_NO_MORE 2
718 f9967bca 2020-03-27 stsp #define TOG_SEARCH_HAVE_NONE 3
719 1803e47f 2019-06-22 stsp regex_t regex;
720 41605754 2020-11-12 stsp regmatch_t regmatch;
721 f2d06bef 2023-01-23 thomas const char *action;
722 cc3c9aac 2018-08-01 stsp };
723 cd0acaa7 2018-05-20 stsp
724 ba4f502b 2018-08-04 stsp static const struct got_error *open_diff_view(struct tog_view *,
725 3dbaef42 2020-11-24 stsp struct got_object_id *, struct got_object_id *,
726 3dbaef42 2020-11-24 stsp const char *, const char *, int, int, int, struct tog_view *,
727 78756c87 2020-11-24 stsp struct got_repository *);
728 5dc9f4bc 2018-08-04 stsp static const struct got_error *show_diff_view(struct tog_view *);
729 e5a0f69f 2018-08-18 stsp static const struct got_error *input_diff_view(struct tog_view **,
730 e78dc838 2020-12-04 stsp struct tog_view *, int);
731 adf4c9e0 2022-07-03 thomas static const struct got_error *reset_diff_view(struct tog_view *);
732 e5a0f69f 2018-08-18 stsp static const struct got_error* close_diff_view(struct tog_view *);
733 f44b1f58 2020-02-02 tracey static const struct got_error *search_start_diff_view(struct tog_view *);
734 2a7d3cd7 2022-09-17 thomas static void search_setup_diff_view(struct tog_view *, FILE **, off_t **,
735 2a7d3cd7 2022-09-17 thomas size_t *, int **, int **, int **, int **);
736 fc2737d5 2022-09-15 thomas static const struct got_error *search_next_view_match(struct tog_view *);
737 e5a0f69f 2018-08-18 stsp
738 ba4f502b 2018-08-04 stsp static const struct got_error *open_log_view(struct tog_view *,
739 78756c87 2020-11-24 stsp struct got_object_id *, struct got_repository *,
740 92845f09 2023-07-26 thomas const char *, const char *, int, struct got_worktree *);
741 ba4f502b 2018-08-04 stsp static const struct got_error * show_log_view(struct tog_view *);
742 e5a0f69f 2018-08-18 stsp static const struct got_error *input_log_view(struct tog_view **,
743 e78dc838 2020-12-04 stsp struct tog_view *, int);
744 ea0bff04 2022-07-19 thomas static const struct got_error *resize_log_view(struct tog_view *, int);
745 e5a0f69f 2018-08-18 stsp static const struct got_error *close_log_view(struct tog_view *);
746 60493ae3 2019-06-20 stsp static const struct got_error *search_start_log_view(struct tog_view *);
747 60493ae3 2019-06-20 stsp static const struct got_error *search_next_log_view(struct tog_view *);
748 e5a0f69f 2018-08-18 stsp
749 e5a0f69f 2018-08-18 stsp static const struct got_error *open_blame_view(struct tog_view *, char *,
750 78756c87 2020-11-24 stsp struct got_object_id *, struct got_repository *);
751 7cbe629d 2018-08-04 stsp static const struct got_error *show_blame_view(struct tog_view *);
752 e5a0f69f 2018-08-18 stsp static const struct got_error *input_blame_view(struct tog_view **,
753 e78dc838 2020-12-04 stsp struct tog_view *, int);
754 adf4c9e0 2022-07-03 thomas static const struct got_error *reset_blame_view(struct tog_view *);
755 e5a0f69f 2018-08-18 stsp static const struct got_error *close_blame_view(struct tog_view *);
756 6c4c42e0 2019-06-24 stsp static const struct got_error *search_start_blame_view(struct tog_view *);
757 2a7d3cd7 2022-09-17 thomas static void search_setup_blame_view(struct tog_view *, FILE **, off_t **,
758 2a7d3cd7 2022-09-17 thomas size_t *, int **, int **, int **, int **);
759 e5a0f69f 2018-08-18 stsp
760 ad80ab7b 2018-08-04 stsp static const struct got_error *open_tree_view(struct tog_view *,
761 bc573f3b 2021-07-10 stsp struct got_object_id *, const char *, struct got_repository *);
762 ad80ab7b 2018-08-04 stsp static const struct got_error *show_tree_view(struct tog_view *);
763 e5a0f69f 2018-08-18 stsp static const struct got_error *input_tree_view(struct tog_view **,
764 e78dc838 2020-12-04 stsp struct tog_view *, int);
765 e5a0f69f 2018-08-18 stsp static const struct got_error *close_tree_view(struct tog_view *);
766 7c32bd05 2019-06-22 stsp static const struct got_error *search_start_tree_view(struct tog_view *);
767 7c32bd05 2019-06-22 stsp static const struct got_error *search_next_tree_view(struct tog_view *);
768 6458efa5 2020-11-24 stsp
769 6458efa5 2020-11-24 stsp static const struct got_error *open_ref_view(struct tog_view *,
770 6458efa5 2020-11-24 stsp struct got_repository *);
771 6458efa5 2020-11-24 stsp static const struct got_error *show_ref_view(struct tog_view *);
772 6458efa5 2020-11-24 stsp static const struct got_error *input_ref_view(struct tog_view **,
773 e78dc838 2020-12-04 stsp struct tog_view *, int);
774 6458efa5 2020-11-24 stsp static const struct got_error *close_ref_view(struct tog_view *);
775 6458efa5 2020-11-24 stsp static const struct got_error *search_start_ref_view(struct tog_view *);
776 6458efa5 2020-11-24 stsp static const struct got_error *search_next_ref_view(struct tog_view *);
777 2a7d3cd7 2022-09-17 thomas
778 2a7d3cd7 2022-09-17 thomas static const struct got_error *open_help_view(struct tog_view *,
779 2a7d3cd7 2022-09-17 thomas struct tog_view *);
780 2a7d3cd7 2022-09-17 thomas static const struct got_error *show_help_view(struct tog_view *);
781 2a7d3cd7 2022-09-17 thomas static const struct got_error *input_help_view(struct tog_view **,
782 2a7d3cd7 2022-09-17 thomas struct tog_view *, int);
783 2a7d3cd7 2022-09-17 thomas static const struct got_error *reset_help_view(struct tog_view *);
784 2a7d3cd7 2022-09-17 thomas static const struct got_error* close_help_view(struct tog_view *);
785 2a7d3cd7 2022-09-17 thomas static const struct got_error *search_start_help_view(struct tog_view *);
786 2a7d3cd7 2022-09-17 thomas static void search_setup_help_view(struct tog_view *, FILE **, off_t **,
787 2a7d3cd7 2022-09-17 thomas size_t *, int **, int **, int **, int **);
788 25791caa 2018-10-24 stsp
789 25791caa 2018-10-24 stsp static volatile sig_atomic_t tog_sigwinch_received;
790 83baff54 2019-08-12 stsp static volatile sig_atomic_t tog_sigpipe_received;
791 61266923 2020-01-14 stsp static volatile sig_atomic_t tog_sigcont_received;
792 296152d1 2022-05-31 thomas static volatile sig_atomic_t tog_sigint_received;
793 296152d1 2022-05-31 thomas static volatile sig_atomic_t tog_sigterm_received;
794 25791caa 2018-10-24 stsp
795 25791caa 2018-10-24 stsp static void
796 25791caa 2018-10-24 stsp tog_sigwinch(int signo)
797 25791caa 2018-10-24 stsp {
798 25791caa 2018-10-24 stsp tog_sigwinch_received = 1;
799 83baff54 2019-08-12 stsp }
800 83baff54 2019-08-12 stsp
801 83baff54 2019-08-12 stsp static void
802 83baff54 2019-08-12 stsp tog_sigpipe(int signo)
803 83baff54 2019-08-12 stsp {
804 83baff54 2019-08-12 stsp tog_sigpipe_received = 1;
805 25791caa 2018-10-24 stsp }
806 26ed57b2 2018-05-19 stsp
807 61266923 2020-01-14 stsp static void
808 61266923 2020-01-14 stsp tog_sigcont(int signo)
809 61266923 2020-01-14 stsp {
810 61266923 2020-01-14 stsp tog_sigcont_received = 1;
811 61266923 2020-01-14 stsp }
812 61266923 2020-01-14 stsp
813 296152d1 2022-05-31 thomas static void
814 296152d1 2022-05-31 thomas tog_sigint(int signo)
815 296152d1 2022-05-31 thomas {
816 296152d1 2022-05-31 thomas tog_sigint_received = 1;
817 296152d1 2022-05-31 thomas }
818 296152d1 2022-05-31 thomas
819 296152d1 2022-05-31 thomas static void
820 296152d1 2022-05-31 thomas tog_sigterm(int signo)
821 296152d1 2022-05-31 thomas {
822 296152d1 2022-05-31 thomas tog_sigterm_received = 1;
823 296152d1 2022-05-31 thomas }
824 296152d1 2022-05-31 thomas
825 296152d1 2022-05-31 thomas static int
826 c31666ae 2022-06-23 thomas tog_fatal_signal_received(void)
827 296152d1 2022-05-31 thomas {
828 296152d1 2022-05-31 thomas return (tog_sigpipe_received ||
829 47cc6e77 2022-10-24 thomas tog_sigint_received || tog_sigterm_received);
830 296152d1 2022-05-31 thomas }
831 296152d1 2022-05-31 thomas
832 e5a0f69f 2018-08-18 stsp static const struct got_error *
833 96a765a8 2018-08-04 stsp view_close(struct tog_view *view)
834 ea5e7bb5 2018-08-01 stsp {
835 f2d749db 2022-07-12 thomas const struct got_error *err = NULL, *child_err = NULL;
836 e5a0f69f 2018-08-18 stsp
837 669b5ffa 2018-10-07 stsp if (view->child) {
838 f2d749db 2022-07-12 thomas child_err = view_close(view->child);
839 669b5ffa 2018-10-07 stsp view->child = NULL;
840 669b5ffa 2018-10-07 stsp }
841 e5a0f69f 2018-08-18 stsp if (view->close)
842 e5a0f69f 2018-08-18 stsp err = view->close(view);
843 ea5e7bb5 2018-08-01 stsp if (view->panel)
844 ea5e7bb5 2018-08-01 stsp del_panel(view->panel);
845 ea5e7bb5 2018-08-01 stsp if (view->window)
846 ea5e7bb5 2018-08-01 stsp delwin(view->window);
847 ea5e7bb5 2018-08-01 stsp free(view);
848 f2d749db 2022-07-12 thomas return err ? err : child_err;
849 ea5e7bb5 2018-08-01 stsp }
850 ea5e7bb5 2018-08-01 stsp
851 ea5e7bb5 2018-08-01 stsp static struct tog_view *
852 b3665f43 2018-08-04 stsp view_open(int nlines, int ncols, int begin_y, int begin_x,
853 0cf4efb1 2018-09-29 stsp enum tog_view_type type)
854 ea5e7bb5 2018-08-01 stsp {
855 ad80ab7b 2018-08-04 stsp struct tog_view *view = calloc(1, sizeof(*view));
856 ea5e7bb5 2018-08-01 stsp
857 ea5e7bb5 2018-08-01 stsp if (view == NULL)
858 ea5e7bb5 2018-08-01 stsp return NULL;
859 ea5e7bb5 2018-08-01 stsp
860 d6b05b5b 2018-08-04 stsp view->type = type;
861 f7d12f7e 2018-08-01 stsp view->lines = LINES;
862 f7d12f7e 2018-08-01 stsp view->cols = COLS;
863 207b9029 2018-08-01 stsp view->nlines = nlines ? nlines : LINES - begin_y;
864 207b9029 2018-08-01 stsp view->ncols = ncols ? ncols : COLS - begin_x;
865 97ddc146 2018-08-01 stsp view->begin_y = begin_y;
866 97ddc146 2018-08-01 stsp view->begin_x = begin_x;
867 842167bf 2018-08-01 stsp view->window = newwin(nlines, ncols, begin_y, begin_x);
868 ea5e7bb5 2018-08-01 stsp if (view->window == NULL) {
869 96a765a8 2018-08-04 stsp view_close(view);
870 ea5e7bb5 2018-08-01 stsp return NULL;
871 ea5e7bb5 2018-08-01 stsp }
872 ea5e7bb5 2018-08-01 stsp view->panel = new_panel(view->window);
873 0cf4efb1 2018-09-29 stsp if (view->panel == NULL ||
874 0cf4efb1 2018-09-29 stsp set_panel_userptr(view->panel, view) != OK) {
875 96a765a8 2018-08-04 stsp view_close(view);
876 ea5e7bb5 2018-08-01 stsp return NULL;
877 ea5e7bb5 2018-08-01 stsp }
878 ea5e7bb5 2018-08-01 stsp
879 ea5e7bb5 2018-08-01 stsp keypad(view->window, TRUE);
880 ea5e7bb5 2018-08-01 stsp return view;
881 cdf1ee82 2018-08-01 stsp }
882 cdf1ee82 2018-08-01 stsp
883 0cf4efb1 2018-09-29 stsp static int
884 0cf4efb1 2018-09-29 stsp view_split_begin_x(int begin_x)
885 0cf4efb1 2018-09-29 stsp {
886 2bd27830 2018-10-22 stsp if (begin_x > 0 || COLS < 120)
887 0cf4efb1 2018-09-29 stsp return 0;
888 2bd27830 2018-10-22 stsp return (COLS - MAX(COLS / 2, 80));
889 5c60c32a 2018-10-18 stsp }
890 5c60c32a 2018-10-18 stsp
891 a5d43cac 2022-07-01 thomas /* XXX Stub till we decide what to do. */
892 a5d43cac 2022-07-01 thomas static int
893 a5d43cac 2022-07-01 thomas view_split_begin_y(int lines)
894 a5d43cac 2022-07-01 thomas {
895 a5d43cac 2022-07-01 thomas return lines * HSPLIT_SCALE;
896 a5d43cac 2022-07-01 thomas }
897 a5d43cac 2022-07-01 thomas
898 5c60c32a 2018-10-18 stsp static const struct got_error *view_resize(struct tog_view *);
899 5c60c32a 2018-10-18 stsp
900 5c60c32a 2018-10-18 stsp static const struct got_error *
901 5c60c32a 2018-10-18 stsp view_splitscreen(struct tog_view *view)
902 5c60c32a 2018-10-18 stsp {
903 5c60c32a 2018-10-18 stsp const struct got_error *err = NULL;
904 5c60c32a 2018-10-18 stsp
905 ea0bff04 2022-07-19 thomas if (!view->resized && view->mode == TOG_VIEW_SPLIT_HRZN) {
906 53d2bdd3 2022-07-10 thomas if (view->resized_y && view->resized_y < view->lines)
907 53d2bdd3 2022-07-10 thomas view->begin_y = view->resized_y;
908 53d2bdd3 2022-07-10 thomas else
909 53d2bdd3 2022-07-10 thomas view->begin_y = view_split_begin_y(view->nlines);
910 a5d43cac 2022-07-01 thomas view->begin_x = 0;
911 ea0bff04 2022-07-19 thomas } else if (!view->resized) {
912 53d2bdd3 2022-07-10 thomas if (view->resized_x && view->resized_x < view->cols - 1 &&
913 53d2bdd3 2022-07-10 thomas view->cols > 119)
914 53d2bdd3 2022-07-10 thomas view->begin_x = view->resized_x;
915 53d2bdd3 2022-07-10 thomas else
916 53d2bdd3 2022-07-10 thomas view->begin_x = view_split_begin_x(0);
917 a5d43cac 2022-07-01 thomas view->begin_y = 0;
918 a5d43cac 2022-07-01 thomas }
919 a5d43cac 2022-07-01 thomas view->nlines = LINES - view->begin_y;
920 5c60c32a 2018-10-18 stsp view->ncols = COLS - view->begin_x;
921 5c60c32a 2018-10-18 stsp view->lines = LINES;
922 5c60c32a 2018-10-18 stsp view->cols = COLS;
923 5c60c32a 2018-10-18 stsp err = view_resize(view);
924 5c60c32a 2018-10-18 stsp if (err)
925 5c60c32a 2018-10-18 stsp return err;
926 5c60c32a 2018-10-18 stsp
927 a5d43cac 2022-07-01 thomas if (view->parent && view->mode == TOG_VIEW_SPLIT_HRZN)
928 a5d43cac 2022-07-01 thomas view->parent->nlines = view->begin_y;
929 a5d43cac 2022-07-01 thomas
930 5c60c32a 2018-10-18 stsp if (mvwin(view->window, view->begin_y, view->begin_x) == ERR)
931 638f9024 2019-05-13 stsp return got_error_from_errno("mvwin");
932 5c60c32a 2018-10-18 stsp
933 5c60c32a 2018-10-18 stsp return NULL;
934 5c60c32a 2018-10-18 stsp }
935 5c60c32a 2018-10-18 stsp
936 5c60c32a 2018-10-18 stsp static const struct got_error *
937 5c60c32a 2018-10-18 stsp view_fullscreen(struct tog_view *view)
938 5c60c32a 2018-10-18 stsp {
939 5c60c32a 2018-10-18 stsp const struct got_error *err = NULL;
940 5c60c32a 2018-10-18 stsp
941 5c60c32a 2018-10-18 stsp view->begin_x = 0;
942 ea0bff04 2022-07-19 thomas view->begin_y = view->resized ? view->begin_y : 0;
943 ea0bff04 2022-07-19 thomas view->nlines = view->resized ? view->nlines : LINES;
944 5c60c32a 2018-10-18 stsp view->ncols = COLS;
945 5c60c32a 2018-10-18 stsp view->lines = LINES;
946 5c60c32a 2018-10-18 stsp view->cols = COLS;
947 5c60c32a 2018-10-18 stsp err = view_resize(view);
948 5c60c32a 2018-10-18 stsp if (err)
949 5c60c32a 2018-10-18 stsp return err;
950 5c60c32a 2018-10-18 stsp
951 5c60c32a 2018-10-18 stsp if (mvwin(view->window, view->begin_y, view->begin_x) == ERR)
952 638f9024 2019-05-13 stsp return got_error_from_errno("mvwin");
953 5c60c32a 2018-10-18 stsp
954 5c60c32a 2018-10-18 stsp return NULL;
955 0cf4efb1 2018-09-29 stsp }
956 0cf4efb1 2018-09-29 stsp
957 5c60c32a 2018-10-18 stsp static int
958 5c60c32a 2018-10-18 stsp view_is_parent_view(struct tog_view *view)
959 5c60c32a 2018-10-18 stsp {
960 5c60c32a 2018-10-18 stsp return view->parent == NULL;
961 5c60c32a 2018-10-18 stsp }
962 5c60c32a 2018-10-18 stsp
963 b65b3ea0 2022-06-23 thomas static int
964 b65b3ea0 2022-06-23 thomas view_is_splitscreen(struct tog_view *view)
965 b65b3ea0 2022-06-23 thomas {
966 a5d43cac 2022-07-01 thomas return view->begin_x > 0 || view->begin_y > 0;
967 e44940c3 2022-07-01 thomas }
968 e44940c3 2022-07-01 thomas
969 e44940c3 2022-07-01 thomas static int
970 e44940c3 2022-07-01 thomas view_is_fullscreen(struct tog_view *view)
971 e44940c3 2022-07-01 thomas {
972 e44940c3 2022-07-01 thomas return view->nlines == LINES && view->ncols == COLS;
973 b65b3ea0 2022-06-23 thomas }
974 b65b3ea0 2022-06-23 thomas
975 444d5325 2022-07-03 thomas static int
976 444d5325 2022-07-03 thomas view_is_hsplit_top(struct tog_view *view)
977 444d5325 2022-07-03 thomas {
978 444d5325 2022-07-03 thomas return view->mode == TOG_VIEW_SPLIT_HRZN && view->child &&
979 444d5325 2022-07-03 thomas view_is_splitscreen(view->child);
980 444d5325 2022-07-03 thomas }
981 444d5325 2022-07-03 thomas
982 a5d43cac 2022-07-01 thomas static void
983 a5d43cac 2022-07-01 thomas view_border(struct tog_view *view)
984 a5d43cac 2022-07-01 thomas {
985 a5d43cac 2022-07-01 thomas PANEL *panel;
986 a5d43cac 2022-07-01 thomas const struct tog_view *view_above;
987 b65b3ea0 2022-06-23 thomas
988 a5d43cac 2022-07-01 thomas if (view->parent)
989 a5d43cac 2022-07-01 thomas return view_border(view->parent);
990 a5d43cac 2022-07-01 thomas
991 a5d43cac 2022-07-01 thomas panel = panel_above(view->panel);
992 a5d43cac 2022-07-01 thomas if (panel == NULL)
993 a5d43cac 2022-07-01 thomas return;
994 a5d43cac 2022-07-01 thomas
995 a5d43cac 2022-07-01 thomas view_above = panel_userptr(panel);
996 a5d43cac 2022-07-01 thomas if (view->mode == TOG_VIEW_SPLIT_HRZN)
997 a5d43cac 2022-07-01 thomas mvwhline(view->window, view_above->begin_y - 1,
998 88e8b64f 2023-04-22 thomas view->begin_x, ACS_HLINE, view->ncols);
999 a5d43cac 2022-07-01 thomas else
1000 a5d43cac 2022-07-01 thomas mvwvline(view->window, view->begin_y, view_above->begin_x - 1,
1001 88e8b64f 2023-04-22 thomas ACS_VLINE, view->nlines);
1002 a5d43cac 2022-07-01 thomas }
1003 a5d43cac 2022-07-01 thomas
1004 53d2bdd3 2022-07-10 thomas static const struct got_error *view_init_hsplit(struct tog_view *, int);
1005 a5d43cac 2022-07-01 thomas static const struct got_error *request_log_commits(struct tog_view *);
1006 a5d43cac 2022-07-01 thomas static const struct got_error *offset_selection_down(struct tog_view *);
1007 a5d43cac 2022-07-01 thomas static void offset_selection_up(struct tog_view *);
1008 53d2bdd3 2022-07-10 thomas static void view_get_split(struct tog_view *, int *, int *);
1009 a5d43cac 2022-07-01 thomas
1010 4d8c2215 2018-08-19 stsp static const struct got_error *
1011 f7d12f7e 2018-08-01 stsp view_resize(struct tog_view *view)
1012 f7d12f7e 2018-08-01 stsp {
1013 a5d43cac 2022-07-01 thomas const struct got_error *err = NULL;
1014 a5d43cac 2022-07-01 thomas int dif, nlines, ncols;
1015 f7d12f7e 2018-08-01 stsp
1016 a5d43cac 2022-07-01 thomas dif = LINES - view->lines; /* line difference */
1017 a5d43cac 2022-07-01 thomas
1018 0cf4efb1 2018-09-29 stsp if (view->lines > LINES)
1019 0cf4efb1 2018-09-29 stsp nlines = view->nlines - (view->lines - LINES);
1020 0cf4efb1 2018-09-29 stsp else
1021 0cf4efb1 2018-09-29 stsp nlines = view->nlines + (LINES - view->lines);
1022 0cf4efb1 2018-09-29 stsp if (view->cols > COLS)
1023 0cf4efb1 2018-09-29 stsp ncols = view->ncols - (view->cols - COLS);
1024 0cf4efb1 2018-09-29 stsp else
1025 0cf4efb1 2018-09-29 stsp ncols = view->ncols + (COLS - view->cols);
1026 6d0fee91 2018-08-01 stsp
1027 4918811f 2022-07-01 thomas if (view->child) {
1028 a5d43cac 2022-07-01 thomas int hs = view->child->begin_y;
1029 a5d43cac 2022-07-01 thomas
1030 e44940c3 2022-07-01 thomas if (!view_is_fullscreen(view))
1031 1827fdb7 2022-07-01 thomas view->child->begin_x = view_split_begin_x(view->begin_x);
1032 a5d43cac 2022-07-01 thomas if (view->mode == TOG_VIEW_SPLIT_HRZN ||
1033 a5d43cac 2022-07-01 thomas view->child->begin_x == 0) {
1034 40236d76 2022-06-23 thomas ncols = COLS;
1035 40236d76 2022-06-23 thomas
1036 5c60c32a 2018-10-18 stsp view_fullscreen(view->child);
1037 5c60c32a 2018-10-18 stsp if (view->child->focussed)
1038 5c60c32a 2018-10-18 stsp show_panel(view->child->panel);
1039 5c60c32a 2018-10-18 stsp else
1040 5c60c32a 2018-10-18 stsp show_panel(view->panel);
1041 5c60c32a 2018-10-18 stsp } else {
1042 40236d76 2022-06-23 thomas ncols = view->child->begin_x;
1043 40236d76 2022-06-23 thomas
1044 5c60c32a 2018-10-18 stsp view_splitscreen(view->child);
1045 5c60c32a 2018-10-18 stsp show_panel(view->child->panel);
1046 a5d43cac 2022-07-01 thomas }
1047 a5d43cac 2022-07-01 thomas /*
1048 a5d43cac 2022-07-01 thomas * XXX This is ugly and needs to be moved into the above
1049 a5d43cac 2022-07-01 thomas * logic but "works" for now and my attempts at moving it
1050 a5d43cac 2022-07-01 thomas * break either 'tab' or 'F' key maps in horizontal splits.
1051 a5d43cac 2022-07-01 thomas */
1052 a5d43cac 2022-07-01 thomas if (hs) {
1053 a5d43cac 2022-07-01 thomas err = view_splitscreen(view->child);
1054 a5d43cac 2022-07-01 thomas if (err)
1055 a5d43cac 2022-07-01 thomas return err;
1056 a5d43cac 2022-07-01 thomas if (dif < 0) { /* top split decreased */
1057 a5d43cac 2022-07-01 thomas err = offset_selection_down(view);
1058 a5d43cac 2022-07-01 thomas if (err)
1059 a5d43cac 2022-07-01 thomas return err;
1060 a5d43cac 2022-07-01 thomas }
1061 a5d43cac 2022-07-01 thomas view_border(view);
1062 a5d43cac 2022-07-01 thomas update_panels();
1063 a5d43cac 2022-07-01 thomas doupdate();
1064 a5d43cac 2022-07-01 thomas show_panel(view->child->panel);
1065 a5d43cac 2022-07-01 thomas nlines = view->nlines;
1066 a5d43cac 2022-07-01 thomas }
1067 40236d76 2022-06-23 thomas } else if (view->parent == NULL)
1068 40236d76 2022-06-23 thomas ncols = COLS;
1069 669b5ffa 2018-10-07 stsp
1070 ea0bff04 2022-07-19 thomas if (view->resize && dif > 0) {
1071 ea0bff04 2022-07-19 thomas err = view->resize(view, dif);
1072 ea0bff04 2022-07-19 thomas if (err)
1073 ea0bff04 2022-07-19 thomas return err;
1074 ea0bff04 2022-07-19 thomas }
1075 ea0bff04 2022-07-19 thomas
1076 40236d76 2022-06-23 thomas if (wresize(view->window, nlines, ncols) == ERR)
1077 40236d76 2022-06-23 thomas return got_error_from_errno("wresize");
1078 40236d76 2022-06-23 thomas if (replace_panel(view->panel, view->window) == ERR)
1079 40236d76 2022-06-23 thomas return got_error_from_errno("replace_panel");
1080 40236d76 2022-06-23 thomas wclear(view->window);
1081 40236d76 2022-06-23 thomas
1082 40236d76 2022-06-23 thomas view->nlines = nlines;
1083 40236d76 2022-06-23 thomas view->ncols = ncols;
1084 40236d76 2022-06-23 thomas view->lines = LINES;
1085 40236d76 2022-06-23 thomas view->cols = COLS;
1086 40236d76 2022-06-23 thomas
1087 5c60c32a 2018-10-18 stsp return NULL;
1088 ea0bff04 2022-07-19 thomas }
1089 ea0bff04 2022-07-19 thomas
1090 ea0bff04 2022-07-19 thomas static const struct got_error *
1091 ea0bff04 2022-07-19 thomas resize_log_view(struct tog_view *view, int increase)
1092 ea0bff04 2022-07-19 thomas {
1093 3a0139e8 2022-07-22 thomas struct tog_log_view_state *s = &view->state.log;
1094 3a0139e8 2022-07-22 thomas const struct got_error *err = NULL;
1095 3a0139e8 2022-07-22 thomas int n = 0;
1096 ea0bff04 2022-07-19 thomas
1097 3a0139e8 2022-07-22 thomas if (s->selected_entry)
1098 3a0139e8 2022-07-22 thomas n = s->selected_entry->idx + view->lines - s->selected;
1099 3a0139e8 2022-07-22 thomas
1100 ea0bff04 2022-07-19 thomas /*
1101 ea0bff04 2022-07-19 thomas * Request commits to account for the increased
1102 ea0bff04 2022-07-19 thomas * height so we have enough to populate the view.
1103 ea0bff04 2022-07-19 thomas */
1104 7e8004ba 2022-09-11 thomas if (s->commits->ncommits < n) {
1105 7e8004ba 2022-09-11 thomas view->nscrolled = n - s->commits->ncommits + increase + 1;
1106 ea0bff04 2022-07-19 thomas err = request_log_commits(view);
1107 ea0bff04 2022-07-19 thomas }
1108 ea0bff04 2022-07-19 thomas
1109 ea0bff04 2022-07-19 thomas return err;
1110 97cb21cd 2022-07-12 thomas }
1111 97cb21cd 2022-07-12 thomas
1112 97cb21cd 2022-07-12 thomas static void
1113 97cb21cd 2022-07-12 thomas view_adjust_offset(struct tog_view *view, int n)
1114 97cb21cd 2022-07-12 thomas {
1115 97cb21cd 2022-07-12 thomas if (n == 0)
1116 97cb21cd 2022-07-12 thomas return;
1117 97cb21cd 2022-07-12 thomas
1118 97cb21cd 2022-07-12 thomas if (view->parent && view->parent->offset) {
1119 97cb21cd 2022-07-12 thomas if (view->parent->offset + n >= 0)
1120 97cb21cd 2022-07-12 thomas view->parent->offset += n;
1121 97cb21cd 2022-07-12 thomas else
1122 97cb21cd 2022-07-12 thomas view->parent->offset = 0;
1123 97cb21cd 2022-07-12 thomas } else if (view->offset) {
1124 97cb21cd 2022-07-12 thomas if (view->offset - n >= 0)
1125 97cb21cd 2022-07-12 thomas view->offset -= n;
1126 97cb21cd 2022-07-12 thomas else
1127 97cb21cd 2022-07-12 thomas view->offset = 0;
1128 97cb21cd 2022-07-12 thomas }
1129 53d2bdd3 2022-07-10 thomas }
1130 53d2bdd3 2022-07-10 thomas
1131 53d2bdd3 2022-07-10 thomas static const struct got_error *
1132 53d2bdd3 2022-07-10 thomas view_resize_split(struct tog_view *view, int resize)
1133 53d2bdd3 2022-07-10 thomas {
1134 53d2bdd3 2022-07-10 thomas const struct got_error *err = NULL;
1135 53d2bdd3 2022-07-10 thomas struct tog_view *v = NULL;
1136 53d2bdd3 2022-07-10 thomas
1137 53d2bdd3 2022-07-10 thomas if (view->parent)
1138 53d2bdd3 2022-07-10 thomas v = view->parent;
1139 53d2bdd3 2022-07-10 thomas else
1140 53d2bdd3 2022-07-10 thomas v = view;
1141 53d2bdd3 2022-07-10 thomas
1142 53d2bdd3 2022-07-10 thomas if (!v->child || !view_is_splitscreen(v->child))
1143 53d2bdd3 2022-07-10 thomas return NULL;
1144 53d2bdd3 2022-07-10 thomas
1145 ea0bff04 2022-07-19 thomas v->resized = v->child->resized = resize; /* lock for resize event */
1146 53d2bdd3 2022-07-10 thomas
1147 53d2bdd3 2022-07-10 thomas if (view->mode == TOG_VIEW_SPLIT_HRZN) {
1148 53d2bdd3 2022-07-10 thomas if (v->child->resized_y)
1149 53d2bdd3 2022-07-10 thomas v->child->begin_y = v->child->resized_y;
1150 53d2bdd3 2022-07-10 thomas if (view->parent)
1151 53d2bdd3 2022-07-10 thomas v->child->begin_y -= resize;
1152 53d2bdd3 2022-07-10 thomas else
1153 53d2bdd3 2022-07-10 thomas v->child->begin_y += resize;
1154 53d2bdd3 2022-07-10 thomas if (v->child->begin_y < 3) {
1155 53d2bdd3 2022-07-10 thomas view->count = 0;
1156 53d2bdd3 2022-07-10 thomas v->child->begin_y = 3;
1157 53d2bdd3 2022-07-10 thomas } else if (v->child->begin_y > LINES - 1) {
1158 53d2bdd3 2022-07-10 thomas view->count = 0;
1159 53d2bdd3 2022-07-10 thomas v->child->begin_y = LINES - 1;
1160 53d2bdd3 2022-07-10 thomas }
1161 53d2bdd3 2022-07-10 thomas v->ncols = COLS;
1162 53d2bdd3 2022-07-10 thomas v->child->ncols = COLS;
1163 97cb21cd 2022-07-12 thomas view_adjust_offset(view, resize);
1164 53d2bdd3 2022-07-10 thomas err = view_init_hsplit(v, v->child->begin_y);
1165 53d2bdd3 2022-07-10 thomas if (err)
1166 53d2bdd3 2022-07-10 thomas return err;
1167 53d2bdd3 2022-07-10 thomas v->child->resized_y = v->child->begin_y;
1168 53d2bdd3 2022-07-10 thomas } else {
1169 53d2bdd3 2022-07-10 thomas if (v->child->resized_x)
1170 53d2bdd3 2022-07-10 thomas v->child->begin_x = v->child->resized_x;
1171 53d2bdd3 2022-07-10 thomas if (view->parent)
1172 53d2bdd3 2022-07-10 thomas v->child->begin_x -= resize;
1173 53d2bdd3 2022-07-10 thomas else
1174 53d2bdd3 2022-07-10 thomas v->child->begin_x += resize;
1175 53d2bdd3 2022-07-10 thomas if (v->child->begin_x < 11) {
1176 53d2bdd3 2022-07-10 thomas view->count = 0;
1177 53d2bdd3 2022-07-10 thomas v->child->begin_x = 11;
1178 53d2bdd3 2022-07-10 thomas } else if (v->child->begin_x > COLS - 1) {
1179 53d2bdd3 2022-07-10 thomas view->count = 0;
1180 53d2bdd3 2022-07-10 thomas v->child->begin_x = COLS - 1;
1181 53d2bdd3 2022-07-10 thomas }
1182 53d2bdd3 2022-07-10 thomas v->child->resized_x = v->child->begin_x;
1183 53d2bdd3 2022-07-10 thomas }
1184 53d2bdd3 2022-07-10 thomas
1185 53d2bdd3 2022-07-10 thomas v->child->mode = v->mode;
1186 53d2bdd3 2022-07-10 thomas v->child->nlines = v->lines - v->child->begin_y;
1187 53d2bdd3 2022-07-10 thomas v->child->ncols = v->cols - v->child->begin_x;
1188 53d2bdd3 2022-07-10 thomas v->focus_child = 1;
1189 53d2bdd3 2022-07-10 thomas
1190 53d2bdd3 2022-07-10 thomas err = view_fullscreen(v);
1191 53d2bdd3 2022-07-10 thomas if (err)
1192 53d2bdd3 2022-07-10 thomas return err;
1193 53d2bdd3 2022-07-10 thomas err = view_splitscreen(v->child);
1194 53d2bdd3 2022-07-10 thomas if (err)
1195 53d2bdd3 2022-07-10 thomas return err;
1196 53d2bdd3 2022-07-10 thomas
1197 53d2bdd3 2022-07-10 thomas if (v->mode == TOG_VIEW_SPLIT_HRZN) {
1198 53d2bdd3 2022-07-10 thomas err = offset_selection_down(v->child);
1199 53d2bdd3 2022-07-10 thomas if (err)
1200 53d2bdd3 2022-07-10 thomas return err;
1201 53d2bdd3 2022-07-10 thomas }
1202 53d2bdd3 2022-07-10 thomas
1203 3a0139e8 2022-07-22 thomas if (v->resize)
1204 3a0139e8 2022-07-22 thomas err = v->resize(v, 0);
1205 3a0139e8 2022-07-22 thomas else if (v->child->resize)
1206 3a0139e8 2022-07-22 thomas err = v->child->resize(v->child, 0);
1207 53d2bdd3 2022-07-10 thomas
1208 ea0bff04 2022-07-19 thomas v->resized = v->child->resized = 0;
1209 53d2bdd3 2022-07-10 thomas
1210 53d2bdd3 2022-07-10 thomas return err;
1211 53d2bdd3 2022-07-10 thomas }
1212 53d2bdd3 2022-07-10 thomas
1213 53d2bdd3 2022-07-10 thomas static void
1214 53d2bdd3 2022-07-10 thomas view_transfer_size(struct tog_view *dst, struct tog_view *src)
1215 53d2bdd3 2022-07-10 thomas {
1216 53d2bdd3 2022-07-10 thomas struct tog_view *v = src->child ? src->child : src;
1217 53d2bdd3 2022-07-10 thomas
1218 53d2bdd3 2022-07-10 thomas dst->resized_x = v->resized_x;
1219 53d2bdd3 2022-07-10 thomas dst->resized_y = v->resized_y;
1220 669b5ffa 2018-10-07 stsp }
1221 669b5ffa 2018-10-07 stsp
1222 669b5ffa 2018-10-07 stsp static const struct got_error *
1223 669b5ffa 2018-10-07 stsp view_close_child(struct tog_view *view)
1224 669b5ffa 2018-10-07 stsp {
1225 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
1226 669b5ffa 2018-10-07 stsp
1227 669b5ffa 2018-10-07 stsp if (view->child == NULL)
1228 669b5ffa 2018-10-07 stsp return NULL;
1229 669b5ffa 2018-10-07 stsp
1230 669b5ffa 2018-10-07 stsp err = view_close(view->child);
1231 669b5ffa 2018-10-07 stsp view->child = NULL;
1232 669b5ffa 2018-10-07 stsp return err;
1233 669b5ffa 2018-10-07 stsp }
1234 669b5ffa 2018-10-07 stsp
1235 40236d76 2022-06-23 thomas static const struct got_error *
1236 669b5ffa 2018-10-07 stsp view_set_child(struct tog_view *view, struct tog_view *child)
1237 669b5ffa 2018-10-07 stsp {
1238 53d2bdd3 2022-07-10 thomas const struct got_error *err = NULL;
1239 53d2bdd3 2022-07-10 thomas
1240 669b5ffa 2018-10-07 stsp view->child = child;
1241 669b5ffa 2018-10-07 stsp child->parent = view;
1242 40236d76 2022-06-23 thomas
1243 53d2bdd3 2022-07-10 thomas err = view_resize(view);
1244 53d2bdd3 2022-07-10 thomas if (err)
1245 53d2bdd3 2022-07-10 thomas return err;
1246 53d2bdd3 2022-07-10 thomas
1247 53d2bdd3 2022-07-10 thomas if (view->child->resized_x || view->child->resized_y)
1248 53d2bdd3 2022-07-10 thomas err = view_resize_split(view, 0);
1249 53d2bdd3 2022-07-10 thomas
1250 53d2bdd3 2022-07-10 thomas return err;
1251 bfddd0d9 2018-09-29 stsp }
1252 2a31b33b 2022-07-23 thomas
1253 2a31b33b 2022-07-23 thomas static const struct got_error *view_dispatch_request(struct tog_view **,
1254 2a31b33b 2022-07-23 thomas struct tog_view *, enum tog_view_type, int, int);
1255 2a31b33b 2022-07-23 thomas
1256 2a31b33b 2022-07-23 thomas static const struct got_error *
1257 2a31b33b 2022-07-23 thomas view_request_new(struct tog_view **requested, struct tog_view *view,
1258 2a31b33b 2022-07-23 thomas enum tog_view_type request)
1259 2a31b33b 2022-07-23 thomas {
1260 2a31b33b 2022-07-23 thomas struct tog_view *new_view = NULL;
1261 2a31b33b 2022-07-23 thomas const struct got_error *err;
1262 2a31b33b 2022-07-23 thomas int y = 0, x = 0;
1263 2a31b33b 2022-07-23 thomas
1264 2a31b33b 2022-07-23 thomas *requested = NULL;
1265 2a31b33b 2022-07-23 thomas
1266 a7dd23ad 2022-09-19 thomas if (view_is_parent_view(view) && request != TOG_VIEW_HELP)
1267 2a31b33b 2022-07-23 thomas view_get_split(view, &y, &x);
1268 bfddd0d9 2018-09-29 stsp
1269 2a31b33b 2022-07-23 thomas err = view_dispatch_request(&new_view, view, request, y, x);
1270 2a31b33b 2022-07-23 thomas if (err)
1271 2a31b33b 2022-07-23 thomas return err;
1272 2a31b33b 2022-07-23 thomas
1273 a7dd23ad 2022-09-19 thomas if (view_is_parent_view(view) && view->mode == TOG_VIEW_SPLIT_HRZN &&
1274 a7dd23ad 2022-09-19 thomas request != TOG_VIEW_HELP) {
1275 2a31b33b 2022-07-23 thomas err = view_init_hsplit(view, y);
1276 2a31b33b 2022-07-23 thomas if (err)
1277 2a31b33b 2022-07-23 thomas return err;
1278 2a31b33b 2022-07-23 thomas }
1279 2a31b33b 2022-07-23 thomas
1280 2a31b33b 2022-07-23 thomas view->focussed = 0;
1281 2a31b33b 2022-07-23 thomas new_view->focussed = 1;
1282 2a31b33b 2022-07-23 thomas new_view->mode = view->mode;
1283 a7dd23ad 2022-09-19 thomas new_view->nlines = request == TOG_VIEW_HELP ?
1284 a7dd23ad 2022-09-19 thomas view->lines : view->lines - y;
1285 2a31b33b 2022-07-23 thomas
1286 a7dd23ad 2022-09-19 thomas if (view_is_parent_view(view) && request != TOG_VIEW_HELP) {
1287 2a31b33b 2022-07-23 thomas view_transfer_size(new_view, view);
1288 2a31b33b 2022-07-23 thomas err = view_close_child(view);
1289 2a31b33b 2022-07-23 thomas if (err)
1290 2a31b33b 2022-07-23 thomas return err;
1291 2a31b33b 2022-07-23 thomas err = view_set_child(view, new_view);
1292 2a31b33b 2022-07-23 thomas if (err)
1293 2a31b33b 2022-07-23 thomas return err;
1294 2a31b33b 2022-07-23 thomas view->focus_child = 1;
1295 2a31b33b 2022-07-23 thomas } else
1296 2a31b33b 2022-07-23 thomas *requested = new_view;
1297 2a31b33b 2022-07-23 thomas
1298 2a31b33b 2022-07-23 thomas return NULL;
1299 2a31b33b 2022-07-23 thomas }
1300 2a31b33b 2022-07-23 thomas
1301 34bc9ec9 2019-02-22 stsp static void
1302 79fcf3e4 2018-11-04 stsp tog_resizeterm(void)
1303 25791caa 2018-10-24 stsp {
1304 25791caa 2018-10-24 stsp int cols, lines;
1305 25791caa 2018-10-24 stsp struct winsize size;
1306 25791caa 2018-10-24 stsp
1307 25791caa 2018-10-24 stsp if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0) {
1308 25791caa 2018-10-24 stsp cols = 80; /* Default */
1309 25791caa 2018-10-24 stsp lines = 24;
1310 25791caa 2018-10-24 stsp } else {
1311 25791caa 2018-10-24 stsp cols = size.ws_col;
1312 25791caa 2018-10-24 stsp lines = size.ws_row;
1313 25791caa 2018-10-24 stsp }
1314 25791caa 2018-10-24 stsp resize_term(lines, cols);
1315 2b49a8ae 2019-06-22 stsp }
1316 2b49a8ae 2019-06-22 stsp
1317 2b49a8ae 2019-06-22 stsp static const struct got_error *
1318 f54d892e 2023-02-17 thomas view_search_start(struct tog_view *view, int fast_refresh)
1319 2b49a8ae 2019-06-22 stsp {
1320 7c32bd05 2019-06-22 stsp const struct got_error *err = NULL;
1321 a5d43cac 2022-07-01 thomas struct tog_view *v = view;
1322 2b49a8ae 2019-06-22 stsp char pattern[1024];
1323 2b49a8ae 2019-06-22 stsp int ret;
1324 c0c4acc8 2021-01-24 stsp
1325 c0c4acc8 2021-01-24 stsp if (view->search_started) {
1326 c0c4acc8 2021-01-24 stsp regfree(&view->regex);
1327 c0c4acc8 2021-01-24 stsp view->searching = 0;
1328 c0c4acc8 2021-01-24 stsp memset(&view->regmatch, 0, sizeof(view->regmatch));
1329 c0c4acc8 2021-01-24 stsp }
1330 c0c4acc8 2021-01-24 stsp view->search_started = 0;
1331 2b49a8ae 2019-06-22 stsp
1332 2b49a8ae 2019-06-22 stsp if (view->nlines < 1)
1333 2b49a8ae 2019-06-22 stsp return NULL;
1334 2b49a8ae 2019-06-22 stsp
1335 444d5325 2022-07-03 thomas if (view_is_hsplit_top(view))
1336 a5d43cac 2022-07-01 thomas v = view->child;
1337 d07291c6 2022-12-30 thomas else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent)
1338 d07291c6 2022-12-30 thomas v = view->parent;
1339 2b49a8ae 2019-06-22 stsp
1340 1fc091f3 2023-09-05 thomas if (tog_io.input_str != NULL) {
1341 1fc091f3 2023-09-05 thomas if (strlcpy(pattern, tog_io.input_str, sizeof(pattern)) >=
1342 1fc091f3 2023-09-05 thomas sizeof(pattern))
1343 1fc091f3 2023-09-05 thomas return got_error(GOT_ERR_NO_SPACE);
1344 1fc091f3 2023-09-05 thomas } else {
1345 1fc091f3 2023-09-05 thomas mvwaddstr(v->window, v->nlines - 1, 0, "/");
1346 1fc091f3 2023-09-05 thomas wclrtoeol(v->window);
1347 1fc091f3 2023-09-05 thomas nodelay(v->window, FALSE); /* block for search term input */
1348 1fc091f3 2023-09-05 thomas nocbreak();
1349 1fc091f3 2023-09-05 thomas echo();
1350 1fc091f3 2023-09-05 thomas ret = wgetnstr(v->window, pattern, sizeof(pattern));
1351 1fc091f3 2023-09-05 thomas wrefresh(v->window);
1352 1fc091f3 2023-09-05 thomas cbreak();
1353 1fc091f3 2023-09-05 thomas noecho();
1354 1fc091f3 2023-09-05 thomas nodelay(v->window, TRUE);
1355 1fc091f3 2023-09-05 thomas if (!fast_refresh && !using_mock_io)
1356 1fc091f3 2023-09-05 thomas halfdelay(10);
1357 1fc091f3 2023-09-05 thomas if (ret == ERR)
1358 1fc091f3 2023-09-05 thomas return NULL;
1359 1fc091f3 2023-09-05 thomas }
1360 2b49a8ae 2019-06-22 stsp
1361 41605754 2020-11-12 stsp if (regcomp(&view->regex, pattern, REG_EXTENDED | REG_NEWLINE) == 0) {
1362 7c32bd05 2019-06-22 stsp err = view->search_start(view);
1363 7c32bd05 2019-06-22 stsp if (err) {
1364 7c32bd05 2019-06-22 stsp regfree(&view->regex);
1365 7c32bd05 2019-06-22 stsp return err;
1366 7c32bd05 2019-06-22 stsp }
1367 c0c4acc8 2021-01-24 stsp view->search_started = 1;
1368 2b49a8ae 2019-06-22 stsp view->searching = TOG_SEARCH_FORWARD;
1369 2b49a8ae 2019-06-22 stsp view->search_next_done = 0;
1370 2b49a8ae 2019-06-22 stsp view->search_next(view);
1371 2b49a8ae 2019-06-22 stsp }
1372 2b49a8ae 2019-06-22 stsp
1373 2b49a8ae 2019-06-22 stsp return NULL;
1374 64486692 2022-07-07 thomas }
1375 64486692 2022-07-07 thomas
1376 ddbc4d37 2022-07-12 thomas /* Switch split mode. If view is a parent or child, draw the new splitscreen. */
1377 64486692 2022-07-07 thomas static const struct got_error *
1378 64486692 2022-07-07 thomas switch_split(struct tog_view *view)
1379 64486692 2022-07-07 thomas {
1380 64486692 2022-07-07 thomas const struct got_error *err = NULL;
1381 64486692 2022-07-07 thomas struct tog_view *v = NULL;
1382 64486692 2022-07-07 thomas
1383 64486692 2022-07-07 thomas if (view->parent)
1384 64486692 2022-07-07 thomas v = view->parent;
1385 64486692 2022-07-07 thomas else
1386 64486692 2022-07-07 thomas v = view;
1387 64486692 2022-07-07 thomas
1388 ddbc4d37 2022-07-12 thomas if (v->mode == TOG_VIEW_SPLIT_HRZN)
1389 ddbc4d37 2022-07-12 thomas v->mode = TOG_VIEW_SPLIT_VERT;
1390 ddbc4d37 2022-07-12 thomas else
1391 64486692 2022-07-07 thomas v->mode = TOG_VIEW_SPLIT_HRZN;
1392 64486692 2022-07-07 thomas
1393 ddbc4d37 2022-07-12 thomas if (!v->child)
1394 ddbc4d37 2022-07-12 thomas return NULL;
1395 ddbc4d37 2022-07-12 thomas else if (v->mode == TOG_VIEW_SPLIT_VERT && v->cols < 120)
1396 ddbc4d37 2022-07-12 thomas v->mode = TOG_VIEW_SPLIT_NONE;
1397 ddbc4d37 2022-07-12 thomas
1398 64486692 2022-07-07 thomas view_get_split(v, &v->child->begin_y, &v->child->begin_x);
1399 53d2bdd3 2022-07-10 thomas if (v->mode == TOG_VIEW_SPLIT_HRZN && v->child->resized_y)
1400 53d2bdd3 2022-07-10 thomas v->child->begin_y = v->child->resized_y;
1401 ddbc4d37 2022-07-12 thomas else if (v->mode == TOG_VIEW_SPLIT_VERT && v->child->resized_x)
1402 53d2bdd3 2022-07-10 thomas v->child->begin_x = v->child->resized_x;
1403 64486692 2022-07-07 thomas
1404 ddbc4d37 2022-07-12 thomas
1405 64486692 2022-07-07 thomas if (v->mode == TOG_VIEW_SPLIT_HRZN) {
1406 64486692 2022-07-07 thomas v->ncols = COLS;
1407 64486692 2022-07-07 thomas v->child->ncols = COLS;
1408 ddbc4d37 2022-07-12 thomas v->child->nscrolled = LINES - v->child->nlines;
1409 64486692 2022-07-07 thomas
1410 64486692 2022-07-07 thomas err = view_init_hsplit(v, v->child->begin_y);
1411 64486692 2022-07-07 thomas if (err)
1412 64486692 2022-07-07 thomas return err;
1413 64486692 2022-07-07 thomas }
1414 64486692 2022-07-07 thomas v->child->mode = v->mode;
1415 64486692 2022-07-07 thomas v->child->nlines = v->lines - v->child->begin_y;
1416 64486692 2022-07-07 thomas v->focus_child = 1;
1417 64486692 2022-07-07 thomas
1418 64486692 2022-07-07 thomas err = view_fullscreen(v);
1419 64486692 2022-07-07 thomas if (err)
1420 64486692 2022-07-07 thomas return err;
1421 64486692 2022-07-07 thomas err = view_splitscreen(v->child);
1422 64486692 2022-07-07 thomas if (err)
1423 64486692 2022-07-07 thomas return err;
1424 64486692 2022-07-07 thomas
1425 ddbc4d37 2022-07-12 thomas if (v->mode == TOG_VIEW_SPLIT_NONE)
1426 ddbc4d37 2022-07-12 thomas v->mode = TOG_VIEW_SPLIT_VERT;
1427 ddbc4d37 2022-07-12 thomas if (v->mode == TOG_VIEW_SPLIT_HRZN) {
1428 ddbc4d37 2022-07-12 thomas err = offset_selection_down(v);
1429 cf1fe301 2022-07-29 thomas if (err)
1430 cf1fe301 2022-07-29 thomas return err;
1431 64486692 2022-07-07 thomas err = offset_selection_down(v->child);
1432 cf1fe301 2022-07-29 thomas if (err)
1433 cf1fe301 2022-07-29 thomas return err;
1434 ddbc4d37 2022-07-12 thomas } else {
1435 ddbc4d37 2022-07-12 thomas offset_selection_up(v);
1436 ddbc4d37 2022-07-12 thomas offset_selection_up(v->child);
1437 64486692 2022-07-07 thomas }
1438 f4e6231a 2022-07-22 thomas if (v->resize)
1439 f4e6231a 2022-07-22 thomas err = v->resize(v, 0);
1440 f4e6231a 2022-07-22 thomas else if (v->child->resize)
1441 f4e6231a 2022-07-22 thomas err = v->child->resize(v->child, 0);
1442 64486692 2022-07-07 thomas
1443 64486692 2022-07-07 thomas return err;
1444 0cf4efb1 2018-09-29 stsp }
1445 6d0fee91 2018-08-01 stsp
1446 07b0611c 2022-06-23 thomas /*
1447 b85a3496 2023-04-14 thomas * Strip trailing whitespace from str starting at byte *n;
1448 b85a3496 2023-04-14 thomas * if *n < 0, use strlen(str). Return new str length in *n.
1449 b85a3496 2023-04-14 thomas */
1450 b85a3496 2023-04-14 thomas static void
1451 b85a3496 2023-04-14 thomas strip_trailing_ws(char *str, int *n)
1452 b85a3496 2023-04-14 thomas {
1453 b85a3496 2023-04-14 thomas size_t x = *n;
1454 b85a3496 2023-04-14 thomas
1455 b85a3496 2023-04-14 thomas if (str == NULL || *str == '\0')
1456 b85a3496 2023-04-14 thomas return;
1457 b85a3496 2023-04-14 thomas
1458 b85a3496 2023-04-14 thomas if (x < 0)
1459 b85a3496 2023-04-14 thomas x = strlen(str);
1460 b85a3496 2023-04-14 thomas
1461 b85a3496 2023-04-14 thomas while (x-- > 0 && isspace((unsigned char)str[x]))
1462 b85a3496 2023-04-14 thomas str[x] = '\0';
1463 b85a3496 2023-04-14 thomas
1464 b85a3496 2023-04-14 thomas *n = x + 1;
1465 b85a3496 2023-04-14 thomas }
1466 b85a3496 2023-04-14 thomas
1467 b85a3496 2023-04-14 thomas /*
1468 b85a3496 2023-04-14 thomas * Extract visible substring of line y from the curses screen
1469 13bc6832 2023-04-22 thomas * and strip trailing whitespace. If vline is set, overwrite
1470 13bc6832 2023-04-22 thomas * line[vline] with '|' because the ACS_VLINE character is
1471 13bc6832 2023-04-22 thomas * written out as 'x'. Write the line to file f.
1472 b85a3496 2023-04-14 thomas */
1473 b85a3496 2023-04-14 thomas static const struct got_error *
1474 b85a3496 2023-04-14 thomas view_write_line(FILE *f, int y, int vline)
1475 b85a3496 2023-04-14 thomas {
1476 b85a3496 2023-04-14 thomas char line[COLS * MB_LEN_MAX]; /* allow for multibyte chars */
1477 b85a3496 2023-04-14 thomas int r, w;
1478 b85a3496 2023-04-14 thomas
1479 b85a3496 2023-04-14 thomas r = mvwinnstr(curscr, y, 0, line, sizeof(line));
1480 b85a3496 2023-04-14 thomas if (r == ERR)
1481 b85a3496 2023-04-14 thomas return got_error_fmt(GOT_ERR_RANGE,
1482 b85a3496 2023-04-14 thomas "failed to extract line %d", y);
1483 b85a3496 2023-04-14 thomas
1484 b85a3496 2023-04-14 thomas /*
1485 b85a3496 2023-04-14 thomas * In some views, lines are padded with blanks to COLS width.
1486 b85a3496 2023-04-14 thomas * Strip them so we can diff without the -b flag when testing.
1487 b85a3496 2023-04-14 thomas */
1488 b85a3496 2023-04-14 thomas strip_trailing_ws(line, &r);
1489 b85a3496 2023-04-14 thomas
1490 13bc6832 2023-04-22 thomas if (vline > 0)
1491 b85a3496 2023-04-14 thomas line[vline] = '|';
1492 b85a3496 2023-04-14 thomas
1493 b85a3496 2023-04-14 thomas w = fprintf(f, "%s\n", line);
1494 b85a3496 2023-04-14 thomas if (w != r + 1) /* \n */
1495 b85a3496 2023-04-14 thomas return got_ferror(f, GOT_ERR_IO);
1496 b85a3496 2023-04-14 thomas
1497 b85a3496 2023-04-14 thomas return NULL;
1498 b85a3496 2023-04-14 thomas }
1499 b85a3496 2023-04-14 thomas
1500 b85a3496 2023-04-14 thomas /*
1501 b85a3496 2023-04-14 thomas * Capture the visible curses screen by writing each line to the
1502 b85a3496 2023-04-14 thomas * file at the path set via the TOG_SCR_DUMP environment variable.
1503 b85a3496 2023-04-14 thomas */
1504 b85a3496 2023-04-14 thomas static const struct got_error *
1505 b85a3496 2023-04-14 thomas screendump(struct tog_view *view)
1506 b85a3496 2023-04-14 thomas {
1507 b85a3496 2023-04-14 thomas const struct got_error *err;
1508 b85a3496 2023-04-14 thomas int i;
1509 b85a3496 2023-04-14 thomas
1510 5b3a801d 2023-04-22 thomas err = got_opentemp_truncate(tog_io.sdump);
1511 5b3a801d 2023-04-22 thomas if (err)
1512 5b3a801d 2023-04-22 thomas return err;
1513 b85a3496 2023-04-14 thomas
1514 b85a3496 2023-04-14 thomas if ((view->child && view->child->begin_x) ||
1515 b85a3496 2023-04-14 thomas (view->parent && view->begin_x)) {
1516 b85a3496 2023-04-14 thomas int ncols = view->child ? view->ncols : view->parent->ncols;
1517 b85a3496 2023-04-14 thomas
1518 b85a3496 2023-04-14 thomas /* vertical splitscreen */
1519 b85a3496 2023-04-14 thomas for (i = 0; i < view->nlines; ++i) {
1520 5b3a801d 2023-04-22 thomas err = view_write_line(tog_io.sdump, i, ncols - 1);
1521 b85a3496 2023-04-14 thomas if (err)
1522 b85a3496 2023-04-14 thomas goto done;
1523 b85a3496 2023-04-14 thomas }
1524 b85a3496 2023-04-14 thomas } else {
1525 b85a3496 2023-04-14 thomas int hline = 0;
1526 b85a3496 2023-04-14 thomas
1527 b85a3496 2023-04-14 thomas /* fullscreen or horizontal splitscreen */
1528 b85a3496 2023-04-14 thomas if ((view->child && view->child->begin_y) ||
1529 b85a3496 2023-04-14 thomas (view->parent && view->begin_y)) /* hsplit */
1530 b85a3496 2023-04-14 thomas hline = view->child ?
1531 b85a3496 2023-04-14 thomas view->child->begin_y : view->begin_y;
1532 b85a3496 2023-04-14 thomas
1533 b85a3496 2023-04-14 thomas for (i = 0; i < view->lines; i++) {
1534 13bc6832 2023-04-22 thomas if (hline && i == hline - 1) {
1535 b85a3496 2023-04-14 thomas int c;
1536 b85a3496 2023-04-14 thomas
1537 b85a3496 2023-04-14 thomas /* ACS_HLINE writes out as 'q', overwrite it */
1538 b85a3496 2023-04-14 thomas for (c = 0; c < view->cols; ++c)
1539 5b3a801d 2023-04-22 thomas fputc('-', tog_io.sdump);
1540 5b3a801d 2023-04-22 thomas fputc('\n', tog_io.sdump);
1541 b85a3496 2023-04-14 thomas continue;
1542 b85a3496 2023-04-14 thomas }
1543 b85a3496 2023-04-14 thomas
1544 5b3a801d 2023-04-22 thomas err = view_write_line(tog_io.sdump, i, 0);
1545 b85a3496 2023-04-14 thomas if (err)
1546 b85a3496 2023-04-14 thomas goto done;
1547 b85a3496 2023-04-14 thomas }
1548 b85a3496 2023-04-14 thomas }
1549 b85a3496 2023-04-14 thomas
1550 b85a3496 2023-04-14 thomas done:
1551 b85a3496 2023-04-14 thomas return err;
1552 b85a3496 2023-04-14 thomas }
1553 b85a3496 2023-04-14 thomas
1554 b85a3496 2023-04-14 thomas /*
1555 fa502711 2022-07-03 thomas * Compute view->count from numeric input. Assign total to view->count and
1556 fa502711 2022-07-03 thomas * return first non-numeric key entered.
1557 07b0611c 2022-06-23 thomas */
1558 07b0611c 2022-06-23 thomas static int
1559 07b0611c 2022-06-23 thomas get_compound_key(struct tog_view *view, int c)
1560 07b0611c 2022-06-23 thomas {
1561 a5d43cac 2022-07-01 thomas struct tog_view *v = view;
1562 a5d43cac 2022-07-01 thomas int x, n = 0;
1563 07b0611c 2022-06-23 thomas
1564 444d5325 2022-07-03 thomas if (view_is_hsplit_top(view))
1565 a5d43cac 2022-07-01 thomas v = view->child;
1566 a5d43cac 2022-07-01 thomas else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent)
1567 a5d43cac 2022-07-01 thomas v = view->parent;
1568 a5d43cac 2022-07-01 thomas
1569 07b0611c 2022-06-23 thomas view->count = 0;
1570 fa502711 2022-07-03 thomas cbreak(); /* block for input */
1571 07dd3ed3 2022-08-06 thomas nodelay(view->window, FALSE);
1572 a5d43cac 2022-07-01 thomas wmove(v->window, v->nlines - 1, 0);
1573 a5d43cac 2022-07-01 thomas wclrtoeol(v->window);
1574 a5d43cac 2022-07-01 thomas waddch(v->window, ':');
1575 07b0611c 2022-06-23 thomas
1576 07b0611c 2022-06-23 thomas do {
1577 a5d43cac 2022-07-01 thomas x = getcurx(v->window);
1578 a5d43cac 2022-07-01 thomas if (x != ERR && x < view->ncols) {
1579 a5d43cac 2022-07-01 thomas waddch(v->window, c);
1580 a5d43cac 2022-07-01 thomas wrefresh(v->window);
1581 a5d43cac 2022-07-01 thomas }
1582 a5d43cac 2022-07-01 thomas
1583 07b0611c 2022-06-23 thomas /*
1584 07b0611c 2022-06-23 thomas * Don't overflow. Max valid request should be the greatest
1585 07b0611c 2022-06-23 thomas * between the longest and total lines; cap at 10 million.
1586 07b0611c 2022-06-23 thomas */
1587 07b0611c 2022-06-23 thomas if (n >= 9999999)
1588 07b0611c 2022-06-23 thomas n = 9999999;
1589 07b0611c 2022-06-23 thomas else
1590 07b0611c 2022-06-23 thomas n = n * 10 + (c - '0');
1591 07b0611c 2022-06-23 thomas } while (((c = wgetch(view->window))) >= '0' && c <= '9' && c != ERR);
1592 07b0611c 2022-06-23 thomas
1593 07dd3ed3 2022-08-06 thomas if (c == 'G' || c == 'g') { /* nG key map */
1594 07dd3ed3 2022-08-06 thomas view->gline = view->hiline = n;
1595 07dd3ed3 2022-08-06 thomas n = 0;
1596 07dd3ed3 2022-08-06 thomas c = 0;
1597 07dd3ed3 2022-08-06 thomas }
1598 07dd3ed3 2022-08-06 thomas
1599 07b0611c 2022-06-23 thomas /* Massage excessive or inapplicable values at the input handler. */
1600 07b0611c 2022-06-23 thomas view->count = n;
1601 07b0611c 2022-06-23 thomas
1602 07b0611c 2022-06-23 thomas return c;
1603 f2d06bef 2023-01-23 thomas }
1604 f2d06bef 2023-01-23 thomas
1605 f2d06bef 2023-01-23 thomas static void
1606 f2d06bef 2023-01-23 thomas action_report(struct tog_view *view)
1607 f2d06bef 2023-01-23 thomas {
1608 f2d06bef 2023-01-23 thomas struct tog_view *v = view;
1609 f2d06bef 2023-01-23 thomas
1610 f2d06bef 2023-01-23 thomas if (view_is_hsplit_top(view))
1611 f2d06bef 2023-01-23 thomas v = view->child;
1612 f2d06bef 2023-01-23 thomas else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent)
1613 f2d06bef 2023-01-23 thomas v = view->parent;
1614 f2d06bef 2023-01-23 thomas
1615 f2d06bef 2023-01-23 thomas wmove(v->window, v->nlines - 1, 0);
1616 f2d06bef 2023-01-23 thomas wclrtoeol(v->window);
1617 f2d06bef 2023-01-23 thomas wprintw(v->window, ":%s", view->action);
1618 f2d06bef 2023-01-23 thomas wrefresh(v->window);
1619 f2d06bef 2023-01-23 thomas
1620 f2d06bef 2023-01-23 thomas /*
1621 f2d06bef 2023-01-23 thomas * Clear action status report. Only clear in blame view
1622 f2d06bef 2023-01-23 thomas * once annotating is complete, otherwise it's too fast.
1623 f2d06bef 2023-01-23 thomas */
1624 f2d06bef 2023-01-23 thomas if (view->type == TOG_VIEW_BLAME) {
1625 f2d06bef 2023-01-23 thomas if (view->state.blame.blame_complete)
1626 f2d06bef 2023-01-23 thomas view->action = NULL;
1627 f2d06bef 2023-01-23 thomas } else
1628 f2d06bef 2023-01-23 thomas view->action = NULL;
1629 07b0611c 2022-06-23 thomas }
1630 07b0611c 2022-06-23 thomas
1631 b85a3496 2023-04-14 thomas /*
1632 b85a3496 2023-04-14 thomas * Read the next line from the test script and assign
1633 b85a3496 2023-04-14 thomas * key instruction to *ch. If at EOF, set the *done flag.
1634 b85a3496 2023-04-14 thomas */
1635 0cf4efb1 2018-09-29 stsp static const struct got_error *
1636 a184c764 2023-04-22 thomas tog_read_script_key(FILE *script, struct tog_view *view, int *ch, int *done)
1637 b85a3496 2023-04-14 thomas {
1638 b85a3496 2023-04-14 thomas const struct got_error *err = NULL;
1639 b85a3496 2023-04-14 thomas char *line = NULL;
1640 b85a3496 2023-04-14 thomas size_t linesz = 0;
1641 1fc091f3 2023-09-05 thomas ssize_t n;
1642 8e778ade 2023-04-22 thomas
1643 1fc091f3 2023-09-05 thomas
1644 a184c764 2023-04-22 thomas if (view->count && --view->count) {
1645 a184c764 2023-04-22 thomas *ch = view->ch;
1646 a184c764 2023-04-22 thomas return NULL;
1647 a184c764 2023-04-22 thomas } else
1648 a184c764 2023-04-22 thomas *ch = -1;
1649 b85a3496 2023-04-14 thomas
1650 1fc091f3 2023-09-05 thomas if ((n = getline(&line, &linesz, script)) == -1) {
1651 b85a3496 2023-04-14 thomas if (feof(script)) {
1652 b85a3496 2023-04-14 thomas *done = 1;
1653 b85a3496 2023-04-14 thomas goto done;
1654 b85a3496 2023-04-14 thomas } else {
1655 b85a3496 2023-04-14 thomas err = got_ferror(script, GOT_ERR_IO);
1656 b85a3496 2023-04-14 thomas goto done;
1657 b85a3496 2023-04-14 thomas }
1658 8e778ade 2023-04-22 thomas }
1659 1134ebde 2023-04-22 thomas
1660 8e778ade 2023-04-22 thomas if (strncasecmp(line, "WAIT_FOR_UI", 11) == 0)
1661 8e778ade 2023-04-22 thomas tog_io.wait_for_ui = 1;
1662 8e778ade 2023-04-22 thomas else if (strncasecmp(line, "KEY_ENTER", 9) == 0)
1663 b85a3496 2023-04-14 thomas *ch = KEY_ENTER;
1664 b85a3496 2023-04-14 thomas else if (strncasecmp(line, "KEY_RIGHT", 9) == 0)
1665 b85a3496 2023-04-14 thomas *ch = KEY_RIGHT;
1666 b85a3496 2023-04-14 thomas else if (strncasecmp(line, "KEY_LEFT", 8) == 0)
1667 b85a3496 2023-04-14 thomas *ch = KEY_LEFT;
1668 b85a3496 2023-04-14 thomas else if (strncasecmp(line, "KEY_DOWN", 8) == 0)
1669 b85a3496 2023-04-14 thomas *ch = KEY_DOWN;
1670 b85a3496 2023-04-14 thomas else if (strncasecmp(line, "KEY_UP", 6) == 0)
1671 b85a3496 2023-04-14 thomas *ch = KEY_UP;
1672 52c5094b 2023-04-28 thomas else if (strncasecmp(line, "TAB", 3) == 0)
1673 52c5094b 2023-04-28 thomas *ch = '\t';
1674 13bc6832 2023-04-22 thomas else if (strncasecmp(line, "SCREENDUMP", 10) == 0)
1675 b85a3496 2023-04-14 thomas *ch = TOG_KEY_SCRDUMP;
1676 a184c764 2023-04-22 thomas else if (isdigit((unsigned char)*line)) {
1677 a184c764 2023-04-22 thomas char *t = line;
1678 a184c764 2023-04-22 thomas
1679 a184c764 2023-04-22 thomas while (isdigit((unsigned char)*t))
1680 a184c764 2023-04-22 thomas ++t;
1681 a184c764 2023-04-22 thomas view->ch = *ch = *t;
1682 a184c764 2023-04-22 thomas *t = '\0';
1683 a184c764 2023-04-22 thomas /* ignore error, view->count is 0 if instruction is invalid */
1684 a184c764 2023-04-22 thomas view->count = strtonum(line, 0, INT_MAX, NULL);
1685 1fc091f3 2023-09-05 thomas } else {
1686 b85a3496 2023-04-14 thomas *ch = *line;
1687 1fc091f3 2023-09-05 thomas if (n > 2 && (*ch == '/' || *ch == '&')) {
1688 1fc091f3 2023-09-05 thomas /* skip leading keymap and trim trailing newline */
1689 1fc091f3 2023-09-05 thomas tog_io.input_str = strndup(line + 1, n - 2);
1690 1fc091f3 2023-09-05 thomas if (tog_io.input_str == NULL) {
1691 1fc091f3 2023-09-05 thomas err = got_error_from_errno("strndup");
1692 1fc091f3 2023-09-05 thomas goto done;
1693 1fc091f3 2023-09-05 thomas }
1694 1fc091f3 2023-09-05 thomas }
1695 1fc091f3 2023-09-05 thomas }
1696 b85a3496 2023-04-14 thomas
1697 b85a3496 2023-04-14 thomas done:
1698 b85a3496 2023-04-14 thomas free(line);
1699 b85a3496 2023-04-14 thomas return err;
1700 b85a3496 2023-04-14 thomas }
1701 b85a3496 2023-04-14 thomas
1702 b85a3496 2023-04-14 thomas static const struct got_error *
1703 e78dc838 2020-12-04 stsp view_input(struct tog_view **new, int *done, struct tog_view *view,
1704 557d3365 2023-04-14 thomas struct tog_view_list_head *views, int fast_refresh)
1705 e5a0f69f 2018-08-18 stsp {
1706 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
1707 669b5ffa 2018-10-07 stsp struct tog_view *v;
1708 1a76625f 2018-10-22 stsp int ch, errcode;
1709 e5a0f69f 2018-08-18 stsp
1710 e5a0f69f 2018-08-18 stsp *new = NULL;
1711 f2d06bef 2023-01-23 thomas
1712 f2d06bef 2023-01-23 thomas if (view->action)
1713 f2d06bef 2023-01-23 thomas action_report(view);
1714 8f4ed634 2020-03-26 stsp
1715 f9967bca 2020-03-27 stsp /* Clear "no matches" indicator. */
1716 f9967bca 2020-03-27 stsp if (view->search_next_done == TOG_SEARCH_NO_MORE ||
1717 07b0611c 2022-06-23 thomas view->search_next_done == TOG_SEARCH_HAVE_NONE) {
1718 8f4ed634 2020-03-26 stsp view->search_next_done = TOG_SEARCH_HAVE_MORE;
1719 07b0611c 2022-06-23 thomas view->count = 0;
1720 07b0611c 2022-06-23 thomas }
1721 e5a0f69f 2018-08-18 stsp
1722 60493ae3 2019-06-20 stsp if (view->searching && !view->search_next_done) {
1723 60493ae3 2019-06-20 stsp view->search_next(view);
1724 60493ae3 2019-06-20 stsp return NULL;
1725 60493ae3 2019-06-20 stsp }
1726 60493ae3 2019-06-20 stsp
1727 1a76625f 2018-10-22 stsp /* Allow threads to make progress while we are waiting for input. */
1728 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1729 1a76625f 2018-10-22 stsp if (errcode)
1730 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_unlock");
1731 b85a3496 2023-04-14 thomas
1732 557d3365 2023-04-14 thomas if (using_mock_io) {
1733 a184c764 2023-04-22 thomas err = tog_read_script_key(tog_io.f, view, &ch, done);
1734 9d9cab5e 2023-04-22 thomas if (err) {
1735 9d9cab5e 2023-04-22 thomas errcode = pthread_mutex_lock(&tog_mutex);
1736 b85a3496 2023-04-14 thomas return err;
1737 9d9cab5e 2023-04-22 thomas }
1738 b85a3496 2023-04-14 thomas } else if (view->count && --view->count) {
1739 634cb454 2022-07-03 thomas cbreak();
1740 634cb454 2022-07-03 thomas nodelay(view->window, TRUE);
1741 07b0611c 2022-06-23 thomas ch = wgetch(view->window);
1742 b85a3496 2023-04-14 thomas /* let C-g or backspace abort unfinished count */
1743 634cb454 2022-07-03 thomas if (ch == CTRL('g') || ch == KEY_BACKSPACE)
1744 634cb454 2022-07-03 thomas view->count = 0;
1745 634cb454 2022-07-03 thomas else
1746 634cb454 2022-07-03 thomas ch = view->ch;
1747 634cb454 2022-07-03 thomas } else {
1748 634cb454 2022-07-03 thomas ch = wgetch(view->window);
1749 07b0611c 2022-06-23 thomas if (ch >= '1' && ch <= '9')
1750 07b0611c 2022-06-23 thomas view->ch = ch = get_compound_key(view, ch);
1751 07b0611c 2022-06-23 thomas }
1752 07dd3ed3 2022-08-06 thomas if (view->hiline && ch != ERR && ch != 0)
1753 07dd3ed3 2022-08-06 thomas view->hiline = 0; /* key pressed, clear line highlight */
1754 07dd3ed3 2022-08-06 thomas nodelay(view->window, TRUE);
1755 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
1756 1a76625f 2018-10-22 stsp if (errcode)
1757 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_lock");
1758 25791caa 2018-10-24 stsp
1759 61266923 2020-01-14 stsp if (tog_sigwinch_received || tog_sigcont_received) {
1760 25791caa 2018-10-24 stsp tog_resizeterm();
1761 25791caa 2018-10-24 stsp tog_sigwinch_received = 0;
1762 61266923 2020-01-14 stsp tog_sigcont_received = 0;
1763 25791caa 2018-10-24 stsp TAILQ_FOREACH(v, views, entry) {
1764 25791caa 2018-10-24 stsp err = view_resize(v);
1765 25791caa 2018-10-24 stsp if (err)
1766 25791caa 2018-10-24 stsp return err;
1767 e78dc838 2020-12-04 stsp err = v->input(new, v, KEY_RESIZE);
1768 25791caa 2018-10-24 stsp if (err)
1769 25791caa 2018-10-24 stsp return err;
1770 cdfcfb03 2020-12-06 stsp if (v->child) {
1771 cdfcfb03 2020-12-06 stsp err = view_resize(v->child);
1772 cdfcfb03 2020-12-06 stsp if (err)
1773 cdfcfb03 2020-12-06 stsp return err;
1774 cdfcfb03 2020-12-06 stsp err = v->child->input(new, v->child,
1775 cdfcfb03 2020-12-06 stsp KEY_RESIZE);
1776 cdfcfb03 2020-12-06 stsp if (err)
1777 cdfcfb03 2020-12-06 stsp return err;
1778 53d2bdd3 2022-07-10 thomas if (v->child->resized_x || v->child->resized_y) {
1779 53d2bdd3 2022-07-10 thomas err = view_resize_split(v, 0);
1780 53d2bdd3 2022-07-10 thomas if (err)
1781 53d2bdd3 2022-07-10 thomas return err;
1782 53d2bdd3 2022-07-10 thomas }
1783 cdfcfb03 2020-12-06 stsp }
1784 25791caa 2018-10-24 stsp }
1785 25791caa 2018-10-24 stsp }
1786 25791caa 2018-10-24 stsp
1787 e5a0f69f 2018-08-18 stsp switch (ch) {
1788 fc2737d5 2022-09-15 thomas case '?':
1789 fc2737d5 2022-09-15 thomas case 'H':
1790 fc2737d5 2022-09-15 thomas case KEY_F(1):
1791 fc2737d5 2022-09-15 thomas if (view->type == TOG_VIEW_HELP)
1792 fc2737d5 2022-09-15 thomas err = view->reset(view);
1793 fc2737d5 2022-09-15 thomas else
1794 fc2737d5 2022-09-15 thomas err = view_request_new(new, view, TOG_VIEW_HELP);
1795 fc2737d5 2022-09-15 thomas break;
1796 1e37a5c2 2019-05-12 jcs case '\t':
1797 07b0611c 2022-06-23 thomas view->count = 0;
1798 1e37a5c2 2019-05-12 jcs if (view->child) {
1799 e78dc838 2020-12-04 stsp view->focussed = 0;
1800 e78dc838 2020-12-04 stsp view->child->focussed = 1;
1801 e78dc838 2020-12-04 stsp view->focus_child = 1;
1802 1e37a5c2 2019-05-12 jcs } else if (view->parent) {
1803 e78dc838 2020-12-04 stsp view->focussed = 0;
1804 e78dc838 2020-12-04 stsp view->parent->focussed = 1;
1805 e78dc838 2020-12-04 stsp view->parent->focus_child = 0;
1806 a5d43cac 2022-07-01 thomas if (!view_is_splitscreen(view)) {
1807 3a0139e8 2022-07-22 thomas if (view->parent->resize) {
1808 3a0139e8 2022-07-22 thomas err = view->parent->resize(view->parent,
1809 3a0139e8 2022-07-22 thomas 0);
1810 a5d43cac 2022-07-01 thomas if (err)
1811 a5d43cac 2022-07-01 thomas return err;
1812 a5d43cac 2022-07-01 thomas }
1813 a5d43cac 2022-07-01 thomas offset_selection_up(view->parent);
1814 b65b3ea0 2022-06-23 thomas err = view_fullscreen(view->parent);
1815 a5d43cac 2022-07-01 thomas if (err)
1816 a5d43cac 2022-07-01 thomas return err;
1817 a5d43cac 2022-07-01 thomas }
1818 1e37a5c2 2019-05-12 jcs }
1819 1e37a5c2 2019-05-12 jcs break;
1820 1e37a5c2 2019-05-12 jcs case 'q':
1821 a5d43cac 2022-07-01 thomas if (view->parent && view->mode == TOG_VIEW_SPLIT_HRZN) {
1822 3a0139e8 2022-07-22 thomas if (view->parent->resize) {
1823 a5d43cac 2022-07-01 thomas /* might need more commits to fill fullscreen */
1824 3a0139e8 2022-07-22 thomas err = view->parent->resize(view->parent, 0);
1825 a5d43cac 2022-07-01 thomas if (err)
1826 a5d43cac 2022-07-01 thomas break;
1827 a5d43cac 2022-07-01 thomas }
1828 a5d43cac 2022-07-01 thomas offset_selection_up(view->parent);
1829 a5d43cac 2022-07-01 thomas }
1830 e78dc838 2020-12-04 stsp err = view->input(new, view, ch);
1831 9970f7fc 2020-12-03 stsp view->dying = 1;
1832 1e37a5c2 2019-05-12 jcs break;
1833 1e37a5c2 2019-05-12 jcs case 'Q':
1834 1e37a5c2 2019-05-12 jcs *done = 1;
1835 1e37a5c2 2019-05-12 jcs break;
1836 1c5e5faa 2022-06-23 thomas case 'F':
1837 07b0611c 2022-06-23 thomas view->count = 0;
1838 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view)) {
1839 1e37a5c2 2019-05-12 jcs if (view->child == NULL)
1840 1e37a5c2 2019-05-12 jcs break;
1841 1e37a5c2 2019-05-12 jcs if (view_is_splitscreen(view->child)) {
1842 e78dc838 2020-12-04 stsp view->focussed = 0;
1843 e78dc838 2020-12-04 stsp view->child->focussed = 1;
1844 1e37a5c2 2019-05-12 jcs err = view_fullscreen(view->child);
1845 53d2bdd3 2022-07-10 thomas } else {
1846 1e37a5c2 2019-05-12 jcs err = view_splitscreen(view->child);
1847 53d2bdd3 2022-07-10 thomas if (!err)
1848 53d2bdd3 2022-07-10 thomas err = view_resize_split(view, 0);
1849 53d2bdd3 2022-07-10 thomas }
1850 1e37a5c2 2019-05-12 jcs if (err)
1851 1e37a5c2 2019-05-12 jcs break;
1852 e78dc838 2020-12-04 stsp err = view->child->input(new, view->child,
1853 9970f7fc 2020-12-03 stsp KEY_RESIZE);
1854 1e37a5c2 2019-05-12 jcs } else {
1855 1e37a5c2 2019-05-12 jcs if (view_is_splitscreen(view)) {
1856 e78dc838 2020-12-04 stsp view->parent->focussed = 0;
1857 e78dc838 2020-12-04 stsp view->focussed = 1;
1858 1e37a5c2 2019-05-12 jcs err = view_fullscreen(view);
1859 1e37a5c2 2019-05-12 jcs } else {
1860 1e37a5c2 2019-05-12 jcs err = view_splitscreen(view);
1861 a5d43cac 2022-07-01 thomas if (!err && view->mode != TOG_VIEW_SPLIT_HRZN)
1862 b65b3ea0 2022-06-23 thomas err = view_resize(view->parent);
1863 53d2bdd3 2022-07-10 thomas if (!err)
1864 53d2bdd3 2022-07-10 thomas err = view_resize_split(view, 0);
1865 669b5ffa 2018-10-07 stsp }
1866 1e37a5c2 2019-05-12 jcs if (err)
1867 1e37a5c2 2019-05-12 jcs break;
1868 e78dc838 2020-12-04 stsp err = view->input(new, view, KEY_RESIZE);
1869 a5d43cac 2022-07-01 thomas }
1870 a5d43cac 2022-07-01 thomas if (err)
1871 a5d43cac 2022-07-01 thomas break;
1872 3a0139e8 2022-07-22 thomas if (view->resize) {
1873 3a0139e8 2022-07-22 thomas err = view->resize(view, 0);
1874 a5d43cac 2022-07-01 thomas if (err)
1875 a5d43cac 2022-07-01 thomas break;
1876 1e37a5c2 2019-05-12 jcs }
1877 e0bcabc5 2023-04-28 thomas if (view->parent) {
1878 e0bcabc5 2023-04-28 thomas if (view->parent->resize) {
1879 e0bcabc5 2023-04-28 thomas err = view->parent->resize(view->parent, 0);
1880 e0bcabc5 2023-04-28 thomas if (err != NULL)
1881 e0bcabc5 2023-04-28 thomas break;
1882 e0bcabc5 2023-04-28 thomas }
1883 a5d43cac 2022-07-01 thomas err = offset_selection_down(view->parent);
1884 e0bcabc5 2023-04-28 thomas if (err != NULL)
1885 e0bcabc5 2023-04-28 thomas break;
1886 e0bcabc5 2023-04-28 thomas }
1887 e0bcabc5 2023-04-28 thomas err = offset_selection_down(view);
1888 1e37a5c2 2019-05-12 jcs break;
1889 64486692 2022-07-07 thomas case 'S':
1890 53d2bdd3 2022-07-10 thomas view->count = 0;
1891 64486692 2022-07-07 thomas err = switch_split(view);
1892 53d2bdd3 2022-07-10 thomas break;
1893 53d2bdd3 2022-07-10 thomas case '-':
1894 53d2bdd3 2022-07-10 thomas err = view_resize_split(view, -1);
1895 64486692 2022-07-07 thomas break;
1896 53d2bdd3 2022-07-10 thomas case '+':
1897 53d2bdd3 2022-07-10 thomas err = view_resize_split(view, 1);
1898 53d2bdd3 2022-07-10 thomas break;
1899 1e37a5c2 2019-05-12 jcs case KEY_RESIZE:
1900 60493ae3 2019-06-20 stsp break;
1901 60493ae3 2019-06-20 stsp case '/':
1902 07b0611c 2022-06-23 thomas view->count = 0;
1903 60493ae3 2019-06-20 stsp if (view->search_start)
1904 f54d892e 2023-02-17 thomas view_search_start(view, fast_refresh);
1905 60493ae3 2019-06-20 stsp else
1906 e78dc838 2020-12-04 stsp err = view->input(new, view, ch);
1907 1e37a5c2 2019-05-12 jcs break;
1908 b1bf1435 2019-06-21 stsp case 'N':
1909 60493ae3 2019-06-20 stsp case 'n':
1910 c0c4acc8 2021-01-24 stsp if (view->search_started && view->search_next) {
1911 b1bf1435 2019-06-21 stsp view->searching = (ch == 'n' ?
1912 b1bf1435 2019-06-21 stsp TOG_SEARCH_FORWARD : TOG_SEARCH_BACKWARD);
1913 60493ae3 2019-06-20 stsp view->search_next_done = 0;
1914 60493ae3 2019-06-20 stsp view->search_next(view);
1915 60493ae3 2019-06-20 stsp } else
1916 e78dc838 2020-12-04 stsp err = view->input(new, view, ch);
1917 adf4c9e0 2022-07-03 thomas break;
1918 adf4c9e0 2022-07-03 thomas case 'A':
1919 f2d06bef 2023-01-23 thomas if (tog_diff_algo == GOT_DIFF_ALGORITHM_MYERS) {
1920 adf4c9e0 2022-07-03 thomas tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
1921 f2d06bef 2023-01-23 thomas view->action = "Patience diff algorithm";
1922 f2d06bef 2023-01-23 thomas } else {
1923 adf4c9e0 2022-07-03 thomas tog_diff_algo = GOT_DIFF_ALGORITHM_MYERS;
1924 f2d06bef 2023-01-23 thomas view->action = "Myers diff algorithm";
1925 f2d06bef 2023-01-23 thomas }
1926 adf4c9e0 2022-07-03 thomas TAILQ_FOREACH(v, views, entry) {
1927 adf4c9e0 2022-07-03 thomas if (v->reset) {
1928 adf4c9e0 2022-07-03 thomas err = v->reset(v);
1929 adf4c9e0 2022-07-03 thomas if (err)
1930 adf4c9e0 2022-07-03 thomas return err;
1931 adf4c9e0 2022-07-03 thomas }
1932 adf4c9e0 2022-07-03 thomas if (v->child && v->child->reset) {
1933 adf4c9e0 2022-07-03 thomas err = v->child->reset(v->child);
1934 adf4c9e0 2022-07-03 thomas if (err)
1935 adf4c9e0 2022-07-03 thomas return err;
1936 adf4c9e0 2022-07-03 thomas }
1937 adf4c9e0 2022-07-03 thomas }
1938 60493ae3 2019-06-20 stsp break;
1939 b85a3496 2023-04-14 thomas case TOG_KEY_SCRDUMP:
1940 b85a3496 2023-04-14 thomas err = screendump(view);
1941 b85a3496 2023-04-14 thomas break;
1942 1e37a5c2 2019-05-12 jcs default:
1943 e78dc838 2020-12-04 stsp err = view->input(new, view, ch);
1944 1e37a5c2 2019-05-12 jcs break;
1945 e5a0f69f 2018-08-18 stsp }
1946 e5a0f69f 2018-08-18 stsp
1947 e5a0f69f 2018-08-18 stsp return err;
1948 bcbd79e2 2018-08-19 stsp }
1949 bcbd79e2 2018-08-19 stsp
1950 ef20f542 2022-06-26 thomas static int
1951 a3404814 2018-09-02 stsp view_needs_focus_indication(struct tog_view *view)
1952 a3404814 2018-09-02 stsp {
1953 669b5ffa 2018-10-07 stsp if (view_is_parent_view(view)) {
1954 acdafe9c 2020-12-03 stsp if (view->child == NULL || view->child->focussed)
1955 669b5ffa 2018-10-07 stsp return 0;
1956 669b5ffa 2018-10-07 stsp if (!view_is_splitscreen(view->child))
1957 669b5ffa 2018-10-07 stsp return 0;
1958 669b5ffa 2018-10-07 stsp } else if (!view_is_splitscreen(view))
1959 a3404814 2018-09-02 stsp return 0;
1960 a3404814 2018-09-02 stsp
1961 669b5ffa 2018-10-07 stsp return view->focussed;
1962 a3404814 2018-09-02 stsp }
1963 a3404814 2018-09-02 stsp
1964 bcbd79e2 2018-08-19 stsp static const struct got_error *
1965 557d3365 2023-04-14 thomas tog_io_close(void)
1966 e5a0f69f 2018-08-18 stsp {
1967 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
1968 b85a3496 2023-04-14 thomas
1969 557d3365 2023-04-14 thomas if (tog_io.cin && fclose(tog_io.cin) == EOF)
1970 557d3365 2023-04-14 thomas err = got_ferror(tog_io.cin, GOT_ERR_IO);
1971 557d3365 2023-04-14 thomas if (tog_io.cout && fclose(tog_io.cout) == EOF && err == NULL)
1972 557d3365 2023-04-14 thomas err = got_ferror(tog_io.cout, GOT_ERR_IO);
1973 557d3365 2023-04-14 thomas if (tog_io.f && fclose(tog_io.f) == EOF && err == NULL)
1974 557d3365 2023-04-14 thomas err = got_ferror(tog_io.f, GOT_ERR_IO);
1975 5b3a801d 2023-04-22 thomas if (tog_io.sdump && fclose(tog_io.sdump) == EOF && err == NULL)
1976 5b3a801d 2023-04-22 thomas err = got_ferror(tog_io.sdump, GOT_ERR_IO);
1977 1fc091f3 2023-09-05 thomas if (tog_io.input_str != NULL)
1978 1fc091f3 2023-09-05 thomas free(tog_io.input_str);
1979 b85a3496 2023-04-14 thomas
1980 b85a3496 2023-04-14 thomas return err;
1981 b85a3496 2023-04-14 thomas }
1982 b85a3496 2023-04-14 thomas
1983 b85a3496 2023-04-14 thomas static const struct got_error *
1984 557d3365 2023-04-14 thomas view_loop(struct tog_view *view)
1985 b85a3496 2023-04-14 thomas {
1986 b85a3496 2023-04-14 thomas const struct got_error *err = NULL;
1987 e5a0f69f 2018-08-18 stsp struct tog_view_list_head views;
1988 fb59748f 2020-12-05 stsp struct tog_view *new_view;
1989 64486692 2022-07-07 thomas char *mode;
1990 fd823528 2018-10-22 stsp int fast_refresh = 10;
1991 1a76625f 2018-10-22 stsp int done = 0, errcode;
1992 e5a0f69f 2018-08-18 stsp
1993 64486692 2022-07-07 thomas mode = getenv("TOG_VIEW_SPLIT_MODE");
1994 64486692 2022-07-07 thomas if (!mode || !(*mode == 'h' || *mode == 'H'))
1995 64486692 2022-07-07 thomas view->mode = TOG_VIEW_SPLIT_VERT;
1996 64486692 2022-07-07 thomas else
1997 64486692 2022-07-07 thomas view->mode = TOG_VIEW_SPLIT_HRZN;
1998 64486692 2022-07-07 thomas
1999 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
2000 1a76625f 2018-10-22 stsp if (errcode)
2001 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_lock");
2002 1a76625f 2018-10-22 stsp
2003 e5a0f69f 2018-08-18 stsp TAILQ_INIT(&views);
2004 e5a0f69f 2018-08-18 stsp TAILQ_INSERT_HEAD(&views, view, entry);
2005 e5a0f69f 2018-08-18 stsp
2006 1004088d 2018-09-29 stsp view->focussed = 1;
2007 878940b7 2018-09-29 stsp err = view->show(view);
2008 0cf4efb1 2018-09-29 stsp if (err)
2009 0cf4efb1 2018-09-29 stsp return err;
2010 0cf4efb1 2018-09-29 stsp update_panels();
2011 0cf4efb1 2018-09-29 stsp doupdate();
2012 f2d749db 2022-07-12 thomas while (!TAILQ_EMPTY(&views) && !done && !tog_thread_error &&
2013 f2d749db 2022-07-12 thomas !tog_fatal_signal_received()) {
2014 fd823528 2018-10-22 stsp /* Refresh fast during initialization, then become slower. */
2015 557d3365 2023-04-14 thomas if (fast_refresh && --fast_refresh == 0 && !using_mock_io)
2016 fd823528 2018-10-22 stsp halfdelay(10); /* switch to once per second */
2017 fd823528 2018-10-22 stsp
2018 557d3365 2023-04-14 thomas err = view_input(&new_view, &done, view, &views, fast_refresh);
2019 e5a0f69f 2018-08-18 stsp if (err)
2020 e5a0f69f 2018-08-18 stsp break;
2021 6ec3d39c 2023-01-23 thomas
2022 6ec3d39c 2023-01-23 thomas if (view->dying && view == TAILQ_FIRST(&views) &&
2023 6ec3d39c 2023-01-23 thomas TAILQ_NEXT(view, entry) == NULL)
2024 6ec3d39c 2023-01-23 thomas done = 1;
2025 6ec3d39c 2023-01-23 thomas if (done) {
2026 6ec3d39c 2023-01-23 thomas struct tog_view *v;
2027 6ec3d39c 2023-01-23 thomas
2028 6ec3d39c 2023-01-23 thomas /*
2029 6ec3d39c 2023-01-23 thomas * When we quit, scroll the screen up a single line
2030 6ec3d39c 2023-01-23 thomas * so we don't lose any information.
2031 6ec3d39c 2023-01-23 thomas */
2032 6ec3d39c 2023-01-23 thomas TAILQ_FOREACH(v, &views, entry) {
2033 6ec3d39c 2023-01-23 thomas wmove(v->window, 0, 0);
2034 6ec3d39c 2023-01-23 thomas wdeleteln(v->window);
2035 6ec3d39c 2023-01-23 thomas wnoutrefresh(v->window);
2036 6ec3d39c 2023-01-23 thomas if (v->child && !view_is_fullscreen(v)) {
2037 6ec3d39c 2023-01-23 thomas wmove(v->child->window, 0, 0);
2038 6ec3d39c 2023-01-23 thomas wdeleteln(v->child->window);
2039 6ec3d39c 2023-01-23 thomas wnoutrefresh(v->child->window);
2040 6ec3d39c 2023-01-23 thomas }
2041 6ec3d39c 2023-01-23 thomas }
2042 6ec3d39c 2023-01-23 thomas doupdate();
2043 6ec3d39c 2023-01-23 thomas }
2044 6ec3d39c 2023-01-23 thomas
2045 9970f7fc 2020-12-03 stsp if (view->dying) {
2046 e78dc838 2020-12-04 stsp struct tog_view *v, *prev = NULL;
2047 669b5ffa 2018-10-07 stsp
2048 9970f7fc 2020-12-03 stsp if (view_is_parent_view(view))
2049 9970f7fc 2020-12-03 stsp prev = TAILQ_PREV(view, tog_view_list_head,
2050 9970f7fc 2020-12-03 stsp entry);
2051 e78dc838 2020-12-04 stsp else if (view->parent)
2052 669b5ffa 2018-10-07 stsp prev = view->parent;
2053 669b5ffa 2018-10-07 stsp
2054 e78dc838 2020-12-04 stsp if (view->parent) {
2055 9970f7fc 2020-12-03 stsp view->parent->child = NULL;
2056 e78dc838 2020-12-04 stsp view->parent->focus_child = 0;
2057 a5d43cac 2022-07-01 thomas /* Restore fullscreen line height. */
2058 a5d43cac 2022-07-01 thomas view->parent->nlines = view->parent->lines;
2059 40236d76 2022-06-23 thomas err = view_resize(view->parent);
2060 40236d76 2022-06-23 thomas if (err)
2061 40236d76 2022-06-23 thomas break;
2062 53d2bdd3 2022-07-10 thomas /* Make resized splits persist. */
2063 53d2bdd3 2022-07-10 thomas view_transfer_size(view->parent, view);
2064 e78dc838 2020-12-04 stsp } else
2065 9970f7fc 2020-12-03 stsp TAILQ_REMOVE(&views, view, entry);
2066 669b5ffa 2018-10-07 stsp
2067 9970f7fc 2020-12-03 stsp err = view_close(view);
2068 fb59748f 2020-12-05 stsp if (err)
2069 e5a0f69f 2018-08-18 stsp goto done;
2070 669b5ffa 2018-10-07 stsp
2071 e78dc838 2020-12-04 stsp view = NULL;
2072 e78dc838 2020-12-04 stsp TAILQ_FOREACH(v, &views, entry) {
2073 e78dc838 2020-12-04 stsp if (v->focussed)
2074 e78dc838 2020-12-04 stsp break;
2075 0cf4efb1 2018-09-29 stsp }
2076 e78dc838 2020-12-04 stsp if (view == NULL && new_view == NULL) {
2077 e78dc838 2020-12-04 stsp /* No view has focus. Try to pick one. */
2078 e78dc838 2020-12-04 stsp if (prev)
2079 e78dc838 2020-12-04 stsp view = prev;
2080 e78dc838 2020-12-04 stsp else if (!TAILQ_EMPTY(&views)) {
2081 e78dc838 2020-12-04 stsp view = TAILQ_LAST(&views,
2082 e78dc838 2020-12-04 stsp tog_view_list_head);
2083 e78dc838 2020-12-04 stsp }
2084 e78dc838 2020-12-04 stsp if (view) {
2085 e78dc838 2020-12-04 stsp if (view->focus_child) {
2086 e78dc838 2020-12-04 stsp view->child->focussed = 1;
2087 e78dc838 2020-12-04 stsp view = view->child;
2088 e78dc838 2020-12-04 stsp } else
2089 e78dc838 2020-12-04 stsp view->focussed = 1;
2090 e78dc838 2020-12-04 stsp }
2091 e78dc838 2020-12-04 stsp }
2092 e5a0f69f 2018-08-18 stsp }
2093 bcbd79e2 2018-08-19 stsp if (new_view) {
2094 86c66b02 2018-10-18 stsp struct tog_view *v, *t;
2095 86c66b02 2018-10-18 stsp /* Only allow one parent view per type. */
2096 86c66b02 2018-10-18 stsp TAILQ_FOREACH_SAFE(v, &views, entry, t) {
2097 86c66b02 2018-10-18 stsp if (v->type != new_view->type)
2098 86c66b02 2018-10-18 stsp continue;
2099 86c66b02 2018-10-18 stsp TAILQ_REMOVE(&views, v, entry);
2100 86c66b02 2018-10-18 stsp err = view_close(v);
2101 86c66b02 2018-10-18 stsp if (err)
2102 86c66b02 2018-10-18 stsp goto done;
2103 86c66b02 2018-10-18 stsp break;
2104 86c66b02 2018-10-18 stsp }
2105 bcbd79e2 2018-08-19 stsp TAILQ_INSERT_TAIL(&views, new_view, entry);
2106 fed7eaa8 2018-10-24 stsp view = new_view;
2107 7cd52833 2022-06-23 thomas }
2108 6ec3d39c 2023-01-23 thomas if (view && !done) {
2109 e78dc838 2020-12-04 stsp if (view_is_parent_view(view)) {
2110 e78dc838 2020-12-04 stsp if (view->child && view->child->focussed)
2111 e78dc838 2020-12-04 stsp view = view->child;
2112 e78dc838 2020-12-04 stsp } else {
2113 e78dc838 2020-12-04 stsp if (view->parent && view->parent->focussed)
2114 e78dc838 2020-12-04 stsp view = view->parent;
2115 1a76625f 2018-10-22 stsp }
2116 e78dc838 2020-12-04 stsp show_panel(view->panel);
2117 e78dc838 2020-12-04 stsp if (view->child && view_is_splitscreen(view->child))
2118 e78dc838 2020-12-04 stsp show_panel(view->child->panel);
2119 e78dc838 2020-12-04 stsp if (view->parent && view_is_splitscreen(view)) {
2120 669b5ffa 2018-10-07 stsp err = view->parent->show(view->parent);
2121 669b5ffa 2018-10-07 stsp if (err)
2122 1a76625f 2018-10-22 stsp goto done;
2123 669b5ffa 2018-10-07 stsp }
2124 669b5ffa 2018-10-07 stsp err = view->show(view);
2125 0cf4efb1 2018-09-29 stsp if (err)
2126 1a76625f 2018-10-22 stsp goto done;
2127 669b5ffa 2018-10-07 stsp if (view->child) {
2128 669b5ffa 2018-10-07 stsp err = view->child->show(view->child);
2129 669b5ffa 2018-10-07 stsp if (err)
2130 1a76625f 2018-10-22 stsp goto done;
2131 669b5ffa 2018-10-07 stsp }
2132 1a76625f 2018-10-22 stsp update_panels();
2133 1a76625f 2018-10-22 stsp doupdate();
2134 0cf4efb1 2018-09-29 stsp }
2135 e5a0f69f 2018-08-18 stsp }
2136 e5a0f69f 2018-08-18 stsp done:
2137 e5a0f69f 2018-08-18 stsp while (!TAILQ_EMPTY(&views)) {
2138 f2d749db 2022-07-12 thomas const struct got_error *close_err;
2139 e5a0f69f 2018-08-18 stsp view = TAILQ_FIRST(&views);
2140 e5a0f69f 2018-08-18 stsp TAILQ_REMOVE(&views, view, entry);
2141 f2d749db 2022-07-12 thomas close_err = view_close(view);
2142 f2d749db 2022-07-12 thomas if (close_err && err == NULL)
2143 f2d749db 2022-07-12 thomas err = close_err;
2144 e5a0f69f 2018-08-18 stsp }
2145 1a76625f 2018-10-22 stsp
2146 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
2147 963ecf2a 2019-08-12 stsp if (errcode && err == NULL)
2148 963ecf2a 2019-08-12 stsp err = got_error_set_errno(errcode, "pthread_mutex_unlock");
2149 1a76625f 2018-10-22 stsp
2150 e5a0f69f 2018-08-18 stsp return err;
2151 ea5e7bb5 2018-08-01 stsp }
2152 ea5e7bb5 2018-08-01 stsp
2153 4ed7e80c 2018-05-20 stsp __dead static void
2154 9f7d7167 2018-04-29 stsp usage_log(void)
2155 9f7d7167 2018-04-29 stsp {
2156 80ddbec8 2018-04-29 stsp endwin();
2157 c70c5802 2018-08-01 stsp fprintf(stderr,
2158 b672a97a 2020-01-27 stsp "usage: %s log [-b] [-c commit] [-r repository-path] [path]\n",
2159 9f7d7167 2018-04-29 stsp getprogname());
2160 9f7d7167 2018-04-29 stsp exit(1);
2161 80ddbec8 2018-04-29 stsp }
2162 80ddbec8 2018-04-29 stsp
2163 963b370f 2018-05-20 stsp /* Create newly allocated wide-character string equivalent to a byte string. */
2164 80ddbec8 2018-04-29 stsp static const struct got_error *
2165 963b370f 2018-05-20 stsp mbs2ws(wchar_t **ws, size_t *wlen, const char *s)
2166 963b370f 2018-05-20 stsp {
2167 00dfcb92 2018-06-11 stsp char *vis = NULL;
2168 963b370f 2018-05-20 stsp const struct got_error *err = NULL;
2169 963b370f 2018-05-20 stsp
2170 963b370f 2018-05-20 stsp *ws = NULL;
2171 963b370f 2018-05-20 stsp *wlen = mbstowcs(NULL, s, 0);
2172 00dfcb92 2018-06-11 stsp if (*wlen == (size_t)-1) {
2173 00dfcb92 2018-06-11 stsp int vislen;
2174 00dfcb92 2018-06-11 stsp if (errno != EILSEQ)
2175 638f9024 2019-05-13 stsp return got_error_from_errno("mbstowcs");
2176 00dfcb92 2018-06-11 stsp
2177 00dfcb92 2018-06-11 stsp /* byte string invalid in current encoding; try to "fix" it */
2178 00dfcb92 2018-06-11 stsp err = got_mbsavis(&vis, &vislen, s);
2179 00dfcb92 2018-06-11 stsp if (err)
2180 00dfcb92 2018-06-11 stsp return err;
2181 00dfcb92 2018-06-11 stsp *wlen = mbstowcs(NULL, vis, 0);
2182 a7f50699 2018-06-11 stsp if (*wlen == (size_t)-1) {
2183 638f9024 2019-05-13 stsp err = got_error_from_errno("mbstowcs"); /* give up */
2184 a7f50699 2018-06-11 stsp goto done;
2185 a7f50699 2018-06-11 stsp }
2186 00dfcb92 2018-06-11 stsp }
2187 963b370f 2018-05-20 stsp
2188 fd9f4a2d 2019-08-28 hiltjo *ws = calloc(*wlen + 1, sizeof(**ws));
2189 a7f50699 2018-06-11 stsp if (*ws == NULL) {
2190 638f9024 2019-05-13 stsp err = got_error_from_errno("calloc");
2191 a7f50699 2018-06-11 stsp goto done;
2192 a7f50699 2018-06-11 stsp }
2193 963b370f 2018-05-20 stsp
2194 00dfcb92 2018-06-11 stsp if (mbstowcs(*ws, vis ? vis : s, *wlen) != *wlen)
2195 638f9024 2019-05-13 stsp err = got_error_from_errno("mbstowcs");
2196 a7f50699 2018-06-11 stsp done:
2197 00dfcb92 2018-06-11 stsp free(vis);
2198 963b370f 2018-05-20 stsp if (err) {
2199 963b370f 2018-05-20 stsp free(*ws);
2200 963b370f 2018-05-20 stsp *ws = NULL;
2201 963b370f 2018-05-20 stsp *wlen = 0;
2202 963b370f 2018-05-20 stsp }
2203 963b370f 2018-05-20 stsp return err;
2204 05171be4 2022-06-23 thomas }
2205 05171be4 2022-06-23 thomas
2206 05171be4 2022-06-23 thomas static const struct got_error *
2207 05171be4 2022-06-23 thomas expand_tab(char **ptr, const char *src)
2208 05171be4 2022-06-23 thomas {
2209 05171be4 2022-06-23 thomas char *dst;
2210 05171be4 2022-06-23 thomas size_t len, n, idx = 0, sz = 0;
2211 05171be4 2022-06-23 thomas
2212 05171be4 2022-06-23 thomas *ptr = NULL;
2213 05171be4 2022-06-23 thomas n = len = strlen(src);
2214 83316834 2022-06-23 thomas dst = malloc(n + 1);
2215 05171be4 2022-06-23 thomas if (dst == NULL)
2216 05171be4 2022-06-23 thomas return got_error_from_errno("malloc");
2217 05171be4 2022-06-23 thomas
2218 05171be4 2022-06-23 thomas while (idx < len && src[idx]) {
2219 05171be4 2022-06-23 thomas const char c = src[idx];
2220 05171be4 2022-06-23 thomas
2221 05171be4 2022-06-23 thomas if (c == '\t') {
2222 05171be4 2022-06-23 thomas size_t nb = TABSIZE - sz % TABSIZE;
2223 b235ad5d 2022-06-23 thomas char *p;
2224 b235ad5d 2022-06-23 thomas
2225 b235ad5d 2022-06-23 thomas p = realloc(dst, n + nb);
2226 83316834 2022-06-23 thomas if (p == NULL) {
2227 83316834 2022-06-23 thomas free(dst);
2228 83316834 2022-06-23 thomas return got_error_from_errno("realloc");
2229 83316834 2022-06-23 thomas
2230 83316834 2022-06-23 thomas }
2231 83316834 2022-06-23 thomas dst = p;
2232 05171be4 2022-06-23 thomas n += nb;
2233 83316834 2022-06-23 thomas memset(dst + sz, ' ', nb);
2234 05171be4 2022-06-23 thomas sz += nb;
2235 05171be4 2022-06-23 thomas } else
2236 05171be4 2022-06-23 thomas dst[sz++] = src[idx];
2237 05171be4 2022-06-23 thomas ++idx;
2238 05171be4 2022-06-23 thomas }
2239 05171be4 2022-06-23 thomas
2240 05171be4 2022-06-23 thomas dst[sz] = '\0';
2241 05171be4 2022-06-23 thomas *ptr = dst;
2242 05171be4 2022-06-23 thomas return NULL;
2243 963b370f 2018-05-20 stsp }
2244 963b370f 2018-05-20 stsp
2245 8d208d34 2022-06-23 thomas /*
2246 8d208d34 2022-06-23 thomas * Advance at most n columns from wline starting at offset off.
2247 8d208d34 2022-06-23 thomas * Return the index to the first character after the span operation.
2248 20181212 2023-06-01 thomas * Return the combined column width of all spanned wide characters in
2249 8d208d34 2022-06-23 thomas * *rcol.
2250 f91a2b48 2022-06-23 thomas */
2251 8d208d34 2022-06-23 thomas static int
2252 8d208d34 2022-06-23 thomas span_wline(int *rcol, int off, wchar_t *wline, int n, int col_tab_align)
2253 8d208d34 2022-06-23 thomas {
2254 8d208d34 2022-06-23 thomas int width, i, cols = 0;
2255 f91a2b48 2022-06-23 thomas
2256 8d208d34 2022-06-23 thomas if (n == 0) {
2257 8d208d34 2022-06-23 thomas *rcol = cols;
2258 8d208d34 2022-06-23 thomas return off;
2259 8d208d34 2022-06-23 thomas }
2260 f91a2b48 2022-06-23 thomas
2261 8d208d34 2022-06-23 thomas for (i = off; wline[i] != L'\0'; ++i) {
2262 8d208d34 2022-06-23 thomas if (wline[i] == L'\t')
2263 8d208d34 2022-06-23 thomas width = TABSIZE - ((cols + col_tab_align) % TABSIZE);
2264 8d208d34 2022-06-23 thomas else
2265 8d208d34 2022-06-23 thomas width = wcwidth(wline[i]);
2266 f91a2b48 2022-06-23 thomas
2267 8d208d34 2022-06-23 thomas if (width == -1) {
2268 8d208d34 2022-06-23 thomas width = 1;
2269 8d208d34 2022-06-23 thomas wline[i] = L'.';
2270 f91a2b48 2022-06-23 thomas }
2271 f91a2b48 2022-06-23 thomas
2272 8d208d34 2022-06-23 thomas if (cols + width > n)
2273 8d208d34 2022-06-23 thomas break;
2274 8d208d34 2022-06-23 thomas cols += width;
2275 f91a2b48 2022-06-23 thomas }
2276 f91a2b48 2022-06-23 thomas
2277 8d208d34 2022-06-23 thomas *rcol = cols;
2278 8d208d34 2022-06-23 thomas return i;
2279 f91a2b48 2022-06-23 thomas }
2280 f91a2b48 2022-06-23 thomas
2281 f91a2b48 2022-06-23 thomas /*
2282 f91a2b48 2022-06-23 thomas * Format a line for display, ensuring that it won't overflow a width limit.
2283 f91a2b48 2022-06-23 thomas * With scrolling, the width returned refers to the scrolled version of the
2284 f91a2b48 2022-06-23 thomas * line, which starts at (*wlinep)[*scrollxp]. The caller must free *wlinep.
2285 f91a2b48 2022-06-23 thomas */
2286 f91a2b48 2022-06-23 thomas static const struct got_error *
2287 f91a2b48 2022-06-23 thomas format_line(wchar_t **wlinep, int *widthp, int *scrollxp,
2288 f91a2b48 2022-06-23 thomas const char *line, int nscroll, int wlimit, int col_tab_align, int expand)
2289 f91a2b48 2022-06-23 thomas {
2290 963b370f 2018-05-20 stsp const struct got_error *err = NULL;
2291 8d208d34 2022-06-23 thomas int cols;
2292 963b370f 2018-05-20 stsp wchar_t *wline = NULL;
2293 05171be4 2022-06-23 thomas char *exstr = NULL;
2294 963b370f 2018-05-20 stsp size_t wlen;
2295 8d208d34 2022-06-23 thomas int i, scrollx;
2296 963b370f 2018-05-20 stsp
2297 963b370f 2018-05-20 stsp *wlinep = NULL;
2298 b700b5d6 2018-07-10 stsp *widthp = 0;
2299 963b370f 2018-05-20 stsp
2300 05171be4 2022-06-23 thomas if (expand) {
2301 05171be4 2022-06-23 thomas err = expand_tab(&exstr, line);
2302 05171be4 2022-06-23 thomas if (err)
2303 05171be4 2022-06-23 thomas return err;
2304 05171be4 2022-06-23 thomas }
2305 05171be4 2022-06-23 thomas
2306 05171be4 2022-06-23 thomas err = mbs2ws(&wline, &wlen, expand ? exstr : line);
2307 05171be4 2022-06-23 thomas free(exstr);
2308 963b370f 2018-05-20 stsp if (err)
2309 963b370f 2018-05-20 stsp return err;
2310 963b370f 2018-05-20 stsp
2311 8d208d34 2022-06-23 thomas scrollx = span_wline(&cols, 0, wline, nscroll, col_tab_align);
2312 f91a2b48 2022-06-23 thomas
2313 3f670bfb 2020-12-10 stsp if (wlen > 0 && wline[wlen - 1] == L'\n') {
2314 3f670bfb 2020-12-10 stsp wline[wlen - 1] = L'\0';
2315 3f670bfb 2020-12-10 stsp wlen--;
2316 3f670bfb 2020-12-10 stsp }
2317 3f670bfb 2020-12-10 stsp if (wlen > 0 && wline[wlen - 1] == L'\r') {
2318 3f670bfb 2020-12-10 stsp wline[wlen - 1] = L'\0';
2319 3f670bfb 2020-12-10 stsp wlen--;
2320 3f670bfb 2020-12-10 stsp }
2321 3f670bfb 2020-12-10 stsp
2322 8d208d34 2022-06-23 thomas i = span_wline(&cols, scrollx, wline, wlimit, col_tab_align);
2323 8d208d34 2022-06-23 thomas wline[i] = L'\0';
2324 27a741e5 2019-09-11 stsp
2325 b700b5d6 2018-07-10 stsp if (widthp)
2326 b700b5d6 2018-07-10 stsp *widthp = cols;
2327 f91a2b48 2022-06-23 thomas if (scrollxp)
2328 f91a2b48 2022-06-23 thomas *scrollxp = scrollx;
2329 963b370f 2018-05-20 stsp if (err)
2330 963b370f 2018-05-20 stsp free(wline);
2331 963b370f 2018-05-20 stsp else
2332 963b370f 2018-05-20 stsp *wlinep = wline;
2333 963b370f 2018-05-20 stsp return err;
2334 963b370f 2018-05-20 stsp }
2335 963b370f 2018-05-20 stsp
2336 8b473291 2019-02-21 stsp static const struct got_error*
2337 8b473291 2019-02-21 stsp build_refs_str(char **refs_str, struct got_reflist_head *refs,
2338 52b5abe1 2019-08-13 stsp struct got_object_id *id, struct got_repository *repo)
2339 8b473291 2019-02-21 stsp {
2340 8b473291 2019-02-21 stsp static const struct got_error *err = NULL;
2341 8b473291 2019-02-21 stsp struct got_reflist_entry *re;
2342 8b473291 2019-02-21 stsp char *s;
2343 8b473291 2019-02-21 stsp const char *name;
2344 8b473291 2019-02-21 stsp
2345 8b473291 2019-02-21 stsp *refs_str = NULL;
2346 00ddec2f 2023-05-17 thomas
2347 00ddec2f 2023-05-17 thomas if (refs == NULL)
2348 00ddec2f 2023-05-17 thomas return NULL;
2349 8b473291 2019-02-21 stsp
2350 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, refs, entry) {
2351 52b5abe1 2019-08-13 stsp struct got_tag_object *tag = NULL;
2352 48cae60d 2020-09-22 stsp struct got_object_id *ref_id;
2353 52b5abe1 2019-08-13 stsp int cmp;
2354 52b5abe1 2019-08-13 stsp
2355 8b473291 2019-02-21 stsp name = got_ref_get_name(re->ref);
2356 8b473291 2019-02-21 stsp if (strcmp(name, GOT_REF_HEAD) == 0)
2357 8b473291 2019-02-21 stsp continue;
2358 8b473291 2019-02-21 stsp if (strncmp(name, "refs/", 5) == 0)
2359 8b473291 2019-02-21 stsp name += 5;
2360 0d095295 2023-06-01 thomas if (strncmp(name, "got/", 4) == 0)
2361 7143d404 2019-03-12 stsp continue;
2362 8b473291 2019-02-21 stsp if (strncmp(name, "heads/", 6) == 0)
2363 8b473291 2019-02-21 stsp name += 6;
2364 79cc719f 2020-04-24 stsp if (strncmp(name, "remotes/", 8) == 0) {
2365 8b473291 2019-02-21 stsp name += 8;
2366 79cc719f 2020-04-24 stsp s = strstr(name, "/" GOT_REF_HEAD);
2367 081e3dc2 2023-06-15 thomas if (s != NULL && strcmp(s, "/" GOT_REF_HEAD) == 0)
2368 79cc719f 2020-04-24 stsp continue;
2369 79cc719f 2020-04-24 stsp }
2370 48cae60d 2020-09-22 stsp err = got_ref_resolve(&ref_id, repo, re->ref);
2371 48cae60d 2020-09-22 stsp if (err)
2372 48cae60d 2020-09-22 stsp break;
2373 52b5abe1 2019-08-13 stsp if (strncmp(name, "tags/", 5) == 0) {
2374 48cae60d 2020-09-22 stsp err = got_object_open_as_tag(&tag, repo, ref_id);
2375 5d844a1e 2019-08-13 stsp if (err) {
2376 48cae60d 2020-09-22 stsp if (err->code != GOT_ERR_OBJ_TYPE) {
2377 48cae60d 2020-09-22 stsp free(ref_id);
2378 5d844a1e 2019-08-13 stsp break;
2379 48cae60d 2020-09-22 stsp }
2380 5d844a1e 2019-08-13 stsp /* Ref points at something other than a tag. */
2381 5d844a1e 2019-08-13 stsp err = NULL;
2382 5d844a1e 2019-08-13 stsp tag = NULL;
2383 5d844a1e 2019-08-13 stsp }
2384 52b5abe1 2019-08-13 stsp }
2385 52b5abe1 2019-08-13 stsp cmp = got_object_id_cmp(tag ?
2386 48cae60d 2020-09-22 stsp got_object_tag_get_object_id(tag) : ref_id, id);
2387 48cae60d 2020-09-22 stsp free(ref_id);
2388 52b5abe1 2019-08-13 stsp if (tag)
2389 52b5abe1 2019-08-13 stsp got_object_tag_close(tag);
2390 52b5abe1 2019-08-13 stsp if (cmp != 0)
2391 52b5abe1 2019-08-13 stsp continue;
2392 8b473291 2019-02-21 stsp s = *refs_str;
2393 8b473291 2019-02-21 stsp if (asprintf(refs_str, "%s%s%s", s ? s : "",
2394 8b473291 2019-02-21 stsp s ? ", " : "", name) == -1) {
2395 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
2396 8b473291 2019-02-21 stsp free(s);
2397 8b473291 2019-02-21 stsp *refs_str = NULL;
2398 8b473291 2019-02-21 stsp break;
2399 8b473291 2019-02-21 stsp }
2400 8b473291 2019-02-21 stsp free(s);
2401 8b473291 2019-02-21 stsp }
2402 8b473291 2019-02-21 stsp
2403 8b473291 2019-02-21 stsp return err;
2404 8b473291 2019-02-21 stsp }
2405 8b473291 2019-02-21 stsp
2406 963b370f 2018-05-20 stsp static const struct got_error *
2407 27a741e5 2019-09-11 stsp format_author(wchar_t **wauthor, int *author_width, char *author, int limit,
2408 27a741e5 2019-09-11 stsp int col_tab_align)
2409 5813d178 2019-03-09 stsp {
2410 e6b8b890 2020-12-29 naddy char *smallerthan;
2411 5813d178 2019-03-09 stsp
2412 5813d178 2019-03-09 stsp smallerthan = strchr(author, '<');
2413 5813d178 2019-03-09 stsp if (smallerthan && smallerthan[1] != '\0')
2414 5813d178 2019-03-09 stsp author = smallerthan + 1;
2415 e6b8b890 2020-12-29 naddy author[strcspn(author, "@>")] = '\0';
2416 f91a2b48 2022-06-23 thomas return format_line(wauthor, author_width, NULL, author, 0, limit,
2417 f91a2b48 2022-06-23 thomas col_tab_align, 0);
2418 5813d178 2019-03-09 stsp }
2419 5813d178 2019-03-09 stsp
2420 5813d178 2019-03-09 stsp static const struct got_error *
2421 349dfd1e 2023-07-23 thomas draw_commit(struct tog_view *view, struct commit_queue_entry *entry,
2422 349dfd1e 2023-07-23 thomas const size_t date_display_cols, int author_display_cols)
2423 80ddbec8 2018-04-29 stsp {
2424 8fdc79fe 2020-12-01 naddy struct tog_log_view_state *s = &view->state.log;
2425 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
2426 349dfd1e 2023-07-23 thomas struct got_commit_object *commit = entry->commit;
2427 349dfd1e 2023-07-23 thomas struct got_object_id *id = entry->id;
2428 6db9f7f6 2019-12-10 stsp char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */
2429 61dc16bb 2023-05-17 thomas char *refs_str = NULL;
2430 80ddbec8 2018-04-29 stsp char *logmsg0 = NULL, *logmsg = NULL;
2431 5813d178 2019-03-09 stsp char *author = NULL;
2432 cabb4cfd 2023-06-01 thomas wchar_t *wrefstr = NULL, *wlogmsg = NULL, *wauthor = NULL;
2433 cabb4cfd 2023-06-01 thomas int author_width, refstr_width, logmsg_width;
2434 5813d178 2019-03-09 stsp char *newline, *line = NULL;
2435 cabb4cfd 2023-06-01 thomas int col, limit, scrollx, logmsg_x;
2436 349dfd1e 2023-07-23 thomas const int avail = view->ncols, marker_column = author_display_cols + 1;
2437 ccb26ccd 2018-11-05 stsp struct tm tm;
2438 45d799e2 2018-12-23 stsp time_t committer_time;
2439 11b20872 2019-11-08 stsp struct tog_color *tc;
2440 9472af95 2023-05-15 thomas struct got_reflist_head *refs;
2441 80ddbec8 2018-04-29 stsp
2442 92845f09 2023-07-26 thomas if (tog_base_commit.id != NULL && tog_base_commit.idx == -1 &&
2443 92845f09 2023-07-26 thomas got_object_id_cmp(id, tog_base_commit.id) == 0)
2444 92845f09 2023-07-26 thomas tog_base_commit.idx = entry->idx;
2445 3a333429 2023-07-26 thomas if (tog_io.wait_for_ui && s->thread_args.need_commit_marker) {
2446 3a333429 2023-07-26 thomas int rc;
2447 3a333429 2023-07-26 thomas
2448 3a333429 2023-07-26 thomas rc = pthread_cond_wait(&s->thread_args.log_loaded, &tog_mutex);
2449 3a333429 2023-07-26 thomas if (rc)
2450 3a333429 2023-07-26 thomas return got_error_set_errno(rc, "pthread_cond_wait");
2451 3a333429 2023-07-26 thomas }
2452 92845f09 2023-07-26 thomas
2453 45d799e2 2018-12-23 stsp committer_time = got_object_commit_get_committer_time(commit);
2454 e385fc42 2021-08-30 stsp if (gmtime_r(&committer_time, &tm) == NULL)
2455 e385fc42 2021-08-30 stsp return got_error_from_errno("gmtime_r");
2456 c24e2d2e 2024-04-25 thomas.ad if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0)
2457 b39d25c7 2018-07-10 stsp return got_error(GOT_ERR_NO_SPACE);
2458 b39d25c7 2018-07-10 stsp
2459 27a741e5 2019-09-11 stsp if (avail <= date_display_cols)
2460 b39d25c7 2018-07-10 stsp limit = MIN(sizeof(datebuf) - 1, avail);
2461 b39d25c7 2018-07-10 stsp else
2462 b39d25c7 2018-07-10 stsp limit = MIN(date_display_cols, sizeof(datebuf) - 1);
2463 8fdc79fe 2020-12-01 naddy tc = get_color(&s->colors, TOG_COLOR_DATE);
2464 11b20872 2019-11-08 stsp if (tc)
2465 11b20872 2019-11-08 stsp wattr_on(view->window,
2466 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
2467 2814baeb 2018-08-01 stsp waddnstr(view->window, datebuf, limit);
2468 11b20872 2019-11-08 stsp if (tc)
2469 11b20872 2019-11-08 stsp wattr_off(view->window,
2470 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
2471 27a741e5 2019-09-11 stsp col = limit;
2472 b39d25c7 2018-07-10 stsp if (col > avail)
2473 b39d25c7 2018-07-10 stsp goto done;
2474 6570a66d 2019-11-08 stsp
2475 6570a66d 2019-11-08 stsp if (avail >= 120) {
2476 6570a66d 2019-11-08 stsp char *id_str;
2477 6570a66d 2019-11-08 stsp err = got_object_id_str(&id_str, id);
2478 6570a66d 2019-11-08 stsp if (err)
2479 6570a66d 2019-11-08 stsp goto done;
2480 8fdc79fe 2020-12-01 naddy tc = get_color(&s->colors, TOG_COLOR_COMMIT);
2481 11b20872 2019-11-08 stsp if (tc)
2482 11b20872 2019-11-08 stsp wattr_on(view->window,
2483 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
2484 6570a66d 2019-11-08 stsp wprintw(view->window, "%.8s ", id_str);
2485 11b20872 2019-11-08 stsp if (tc)
2486 11b20872 2019-11-08 stsp wattr_off(view->window,
2487 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
2488 6570a66d 2019-11-08 stsp free(id_str);
2489 6570a66d 2019-11-08 stsp col += 9;
2490 6570a66d 2019-11-08 stsp if (col > avail)
2491 6570a66d 2019-11-08 stsp goto done;
2492 6570a66d 2019-11-08 stsp }
2493 b39d25c7 2018-07-10 stsp
2494 f69c5a46 2022-07-19 thomas if (s->use_committer)
2495 f69c5a46 2022-07-19 thomas author = strdup(got_object_commit_get_committer(commit));
2496 f69c5a46 2022-07-19 thomas else
2497 f69c5a46 2022-07-19 thomas author = strdup(got_object_commit_get_author(commit));
2498 5813d178 2019-03-09 stsp if (author == NULL) {
2499 638f9024 2019-05-13 stsp err = got_error_from_errno("strdup");
2500 80ddbec8 2018-04-29 stsp goto done;
2501 80ddbec8 2018-04-29 stsp }
2502 27a741e5 2019-09-11 stsp err = format_author(&wauthor, &author_width, author, avail - col, col);
2503 bb737323 2018-05-20 stsp if (err)
2504 bb737323 2018-05-20 stsp goto done;
2505 8fdc79fe 2020-12-01 naddy tc = get_color(&s->colors, TOG_COLOR_AUTHOR);
2506 11b20872 2019-11-08 stsp if (tc)
2507 11b20872 2019-11-08 stsp wattr_on(view->window,
2508 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
2509 2814baeb 2018-08-01 stsp waddwstr(view->window, wauthor);
2510 bb737323 2018-05-20 stsp col += author_width;
2511 27a741e5 2019-09-11 stsp while (col < avail && author_width < author_display_cols + 2) {
2512 92845f09 2023-07-26 thomas if (tog_base_commit.marker != GOT_WORKTREE_STATE_UNKNOWN &&
2513 349dfd1e 2023-07-23 thomas author_width == marker_column &&
2514 9403b695 2023-08-23 thomas entry->idx == tog_base_commit.idx && !s->limit_view) {
2515 f517f81a 2023-07-23 thomas tc = get_color(&s->colors, TOG_COLOR_COMMIT);
2516 f517f81a 2023-07-23 thomas if (tc)
2517 f517f81a 2023-07-23 thomas wattr_on(view->window,
2518 f517f81a 2023-07-23 thomas COLOR_PAIR(tc->colorpair), NULL);
2519 349dfd1e 2023-07-23 thomas waddch(view->window, tog_base_commit.marker);
2520 f517f81a 2023-07-23 thomas if (tc)
2521 f517f81a 2023-07-23 thomas wattr_off(view->window,
2522 f517f81a 2023-07-23 thomas COLOR_PAIR(tc->colorpair), NULL);
2523 f517f81a 2023-07-23 thomas } else
2524 349dfd1e 2023-07-23 thomas waddch(view->window, ' ');
2525 bb737323 2018-05-20 stsp col++;
2526 bb737323 2018-05-20 stsp author_width++;
2527 bb737323 2018-05-20 stsp }
2528 f31d6c3b 2022-09-09 thomas if (tc)
2529 f31d6c3b 2022-09-09 thomas wattr_off(view->window,
2530 f31d6c3b 2022-09-09 thomas COLOR_PAIR(tc->colorpair), NULL);
2531 9c2eaf34 2018-05-20 stsp if (col > avail)
2532 9c2eaf34 2018-05-20 stsp goto done;
2533 80ddbec8 2018-04-29 stsp
2534 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
2535 5943eee2 2019-08-13 stsp if (err)
2536 6d9fbc00 2018-04-29 stsp goto done;
2537 bb737323 2018-05-20 stsp logmsg = logmsg0;
2538 bb737323 2018-05-20 stsp while (*logmsg == '\n')
2539 bb737323 2018-05-20 stsp logmsg++;
2540 bb737323 2018-05-20 stsp newline = strchr(logmsg, '\n');
2541 bb737323 2018-05-20 stsp if (newline)
2542 bb737323 2018-05-20 stsp *newline = '\0';
2543 9472af95 2023-05-15 thomas
2544 cabb4cfd 2023-06-01 thomas limit = avail - col;
2545 cabb4cfd 2023-06-01 thomas if (view->child && !view_is_hsplit_top(view) && limit > 0)
2546 cabb4cfd 2023-06-01 thomas limit--; /* for the border */
2547 cabb4cfd 2023-06-01 thomas
2548 9472af95 2023-05-15 thomas /* Prepend reference labels to log message if possible .*/
2549 9472af95 2023-05-15 thomas refs = got_reflist_object_id_map_lookup(tog_refs_idmap, id);
2550 00ddec2f 2023-05-17 thomas err = build_refs_str(&refs_str, refs, id, s->repo);
2551 61dc16bb 2023-05-17 thomas if (err)
2552 61dc16bb 2023-05-17 thomas goto done;
2553 61dc16bb 2023-05-17 thomas if (refs_str) {
2554 cabb4cfd 2023-06-01 thomas char *rs;
2555 fcfb26c3 2023-05-26 thomas
2556 cabb4cfd 2023-06-01 thomas if (asprintf(&rs, "[%s]", refs_str) == -1) {
2557 9472af95 2023-05-15 thomas err = got_error_from_errno("asprintf");
2558 9472af95 2023-05-15 thomas goto done;
2559 9472af95 2023-05-15 thomas }
2560 cabb4cfd 2023-06-01 thomas err = format_line(&wrefstr, &refstr_width,
2561 cabb4cfd 2023-06-01 thomas &scrollx, rs, view->x, limit, col, 1);
2562 cabb4cfd 2023-06-01 thomas free(rs);
2563 cabb4cfd 2023-06-01 thomas if (err)
2564 cabb4cfd 2023-06-01 thomas goto done;
2565 9472af95 2023-05-15 thomas tc = get_color(&s->colors, TOG_COLOR_COMMIT);
2566 9472af95 2023-05-15 thomas if (tc)
2567 9472af95 2023-05-15 thomas wattr_on(view->window,
2568 9472af95 2023-05-15 thomas COLOR_PAIR(tc->colorpair), NULL);
2569 cabb4cfd 2023-06-01 thomas waddwstr(view->window, &wrefstr[scrollx]);
2570 9472af95 2023-05-15 thomas if (tc)
2571 9472af95 2023-05-15 thomas wattr_off(view->window,
2572 9472af95 2023-05-15 thomas COLOR_PAIR(tc->colorpair), NULL);
2573 cabb4cfd 2023-06-01 thomas col += MAX(refstr_width, 0);
2574 cabb4cfd 2023-06-01 thomas if (col > avail)
2575 cabb4cfd 2023-06-01 thomas goto done;
2576 cabb4cfd 2023-06-01 thomas
2577 cabb4cfd 2023-06-01 thomas if (col < avail) {
2578 cabb4cfd 2023-06-01 thomas waddch(view->window, ' ');
2579 cabb4cfd 2023-06-01 thomas col++;
2580 cabb4cfd 2023-06-01 thomas }
2581 cabb4cfd 2023-06-01 thomas
2582 cabb4cfd 2023-06-01 thomas if (refstr_width > 0)
2583 cabb4cfd 2023-06-01 thomas logmsg_x = 0;
2584 cabb4cfd 2023-06-01 thomas else {
2585 cabb4cfd 2023-06-01 thomas int unscrolled_refstr_width;
2586 cabb4cfd 2023-06-01 thomas size_t len = wcslen(wrefstr);
2587 cabb4cfd 2023-06-01 thomas
2588 cabb4cfd 2023-06-01 thomas /*
2589 cabb4cfd 2023-06-01 thomas * No need to check for -1 return value here since
2590 cabb4cfd 2023-06-01 thomas * unprintables have been replaced by span_wline().
2591 cabb4cfd 2023-06-01 thomas */
2592 cabb4cfd 2023-06-01 thomas unscrolled_refstr_width = wcswidth(wrefstr, len);
2593 cabb4cfd 2023-06-01 thomas unscrolled_refstr_width += 1; /* trailing space */
2594 cabb4cfd 2023-06-01 thomas logmsg_x = view->x - unscrolled_refstr_width;
2595 cabb4cfd 2023-06-01 thomas }
2596 cabb4cfd 2023-06-01 thomas
2597 cabb4cfd 2023-06-01 thomas limit = avail - col;
2598 cabb4cfd 2023-06-01 thomas if (view->child && !view_is_hsplit_top(view) && limit > 0)
2599 cabb4cfd 2023-06-01 thomas limit--; /* for the border */
2600 9472af95 2023-05-15 thomas } else
2601 cabb4cfd 2023-06-01 thomas logmsg_x = view->x;
2602 cabb4cfd 2023-06-01 thomas
2603 cabb4cfd 2023-06-01 thomas err = format_line(&wlogmsg, &logmsg_width, &scrollx, logmsg, logmsg_x,
2604 cabb4cfd 2023-06-01 thomas limit, col, 1);
2605 cabb4cfd 2023-06-01 thomas if (err)
2606 cabb4cfd 2023-06-01 thomas goto done;
2607 cabb4cfd 2023-06-01 thomas waddwstr(view->window, &wlogmsg[scrollx]);
2608 331b1a16 2022-06-23 thomas col += MAX(logmsg_width, 0);
2609 27a741e5 2019-09-11 stsp while (col < avail) {
2610 2814baeb 2018-08-01 stsp waddch(view->window, ' ');
2611 bb737323 2018-05-20 stsp col++;
2612 881b2d3e 2018-04-30 stsp }
2613 80ddbec8 2018-04-29 stsp done:
2614 80ddbec8 2018-04-29 stsp free(logmsg0);
2615 bb737323 2018-05-20 stsp free(wlogmsg);
2616 cabb4cfd 2023-06-01 thomas free(wrefstr);
2617 61dc16bb 2023-05-17 thomas free(refs_str);
2618 5813d178 2019-03-09 stsp free(author);
2619 bb737323 2018-05-20 stsp free(wauthor);
2620 80ddbec8 2018-04-29 stsp free(line);
2621 80ddbec8 2018-04-29 stsp return err;
2622 80ddbec8 2018-04-29 stsp }
2623 26ed57b2 2018-05-19 stsp
2624 899d86c2 2018-05-10 stsp static struct commit_queue_entry *
2625 899d86c2 2018-05-10 stsp alloc_commit_queue_entry(struct got_commit_object *commit,
2626 899d86c2 2018-05-10 stsp struct got_object_id *id)
2627 80ddbec8 2018-04-29 stsp {
2628 80ddbec8 2018-04-29 stsp struct commit_queue_entry *entry;
2629 d68b9737 2022-09-05 thomas struct got_object_id *dup;
2630 80ddbec8 2018-04-29 stsp
2631 80ddbec8 2018-04-29 stsp entry = calloc(1, sizeof(*entry));
2632 80ddbec8 2018-04-29 stsp if (entry == NULL)
2633 899d86c2 2018-05-10 stsp return NULL;
2634 99db9666 2018-05-07 stsp
2635 d68b9737 2022-09-05 thomas dup = got_object_id_dup(id);
2636 d68b9737 2022-09-05 thomas if (dup == NULL) {
2637 d68b9737 2022-09-05 thomas free(entry);
2638 d68b9737 2022-09-05 thomas return NULL;
2639 d68b9737 2022-09-05 thomas }
2640 d68b9737 2022-09-05 thomas
2641 d68b9737 2022-09-05 thomas entry->id = dup;
2642 99db9666 2018-05-07 stsp entry->commit = commit;
2643 899d86c2 2018-05-10 stsp return entry;
2644 99db9666 2018-05-07 stsp }
2645 80ddbec8 2018-04-29 stsp
2646 99db9666 2018-05-07 stsp static void
2647 99db9666 2018-05-07 stsp pop_commit(struct commit_queue *commits)
2648 99db9666 2018-05-07 stsp {
2649 99db9666 2018-05-07 stsp struct commit_queue_entry *entry;
2650 99db9666 2018-05-07 stsp
2651 ecb28ae0 2018-07-16 stsp entry = TAILQ_FIRST(&commits->head);
2652 ecb28ae0 2018-07-16 stsp TAILQ_REMOVE(&commits->head, entry, entry);
2653 99db9666 2018-05-07 stsp got_object_commit_close(entry->commit);
2654 ecb28ae0 2018-07-16 stsp commits->ncommits--;
2655 d68b9737 2022-09-05 thomas free(entry->id);
2656 99db9666 2018-05-07 stsp free(entry);
2657 99db9666 2018-05-07 stsp }
2658 99db9666 2018-05-07 stsp
2659 99db9666 2018-05-07 stsp static void
2660 99db9666 2018-05-07 stsp free_commits(struct commit_queue *commits)
2661 99db9666 2018-05-07 stsp {
2662 ecb28ae0 2018-07-16 stsp while (!TAILQ_EMPTY(&commits->head))
2663 99db9666 2018-05-07 stsp pop_commit(commits);
2664 c4972b91 2018-05-07 stsp }
2665 c4972b91 2018-05-07 stsp
2666 c4972b91 2018-05-07 stsp static const struct got_error *
2667 13add988 2019-10-15 stsp match_commit(int *have_match, struct got_object_id *id,
2668 13add988 2019-10-15 stsp struct got_commit_object *commit, regex_t *regex)
2669 13add988 2019-10-15 stsp {
2670 13add988 2019-10-15 stsp const struct got_error *err = NULL;
2671 13add988 2019-10-15 stsp regmatch_t regmatch;
2672 13add988 2019-10-15 stsp char *id_str = NULL, *logmsg = NULL;
2673 13add988 2019-10-15 stsp
2674 13add988 2019-10-15 stsp *have_match = 0;
2675 13add988 2019-10-15 stsp
2676 13add988 2019-10-15 stsp err = got_object_id_str(&id_str, id);
2677 13add988 2019-10-15 stsp if (err)
2678 13add988 2019-10-15 stsp return err;
2679 13add988 2019-10-15 stsp
2680 13add988 2019-10-15 stsp err = got_object_commit_get_logmsg(&logmsg, commit);
2681 13add988 2019-10-15 stsp if (err)
2682 13add988 2019-10-15 stsp goto done;
2683 13add988 2019-10-15 stsp
2684 13add988 2019-10-15 stsp if (regexec(regex, got_object_commit_get_author(commit), 1,
2685 13add988 2019-10-15 stsp &regmatch, 0) == 0 ||
2686 13add988 2019-10-15 stsp regexec(regex, got_object_commit_get_committer(commit), 1,
2687 13add988 2019-10-15 stsp &regmatch, 0) == 0 ||
2688 13add988 2019-10-15 stsp regexec(regex, id_str, 1, &regmatch, 0) == 0 ||
2689 13add988 2019-10-15 stsp regexec(regex, logmsg, 1, &regmatch, 0) == 0)
2690 13add988 2019-10-15 stsp *have_match = 1;
2691 13add988 2019-10-15 stsp done:
2692 13add988 2019-10-15 stsp free(id_str);
2693 13add988 2019-10-15 stsp free(logmsg);
2694 13add988 2019-10-15 stsp return err;
2695 13add988 2019-10-15 stsp }
2696 13add988 2019-10-15 stsp
2697 13add988 2019-10-15 stsp static const struct got_error *
2698 4e0d2870 2020-12-07 naddy queue_commits(struct tog_log_thread_args *a)
2699 c4972b91 2018-05-07 stsp {
2700 899d86c2 2018-05-10 stsp const struct got_error *err = NULL;
2701 9ba79e04 2018-06-11 stsp
2702 1a76625f 2018-10-22 stsp /*
2703 1a76625f 2018-10-22 stsp * We keep all commits open throughout the lifetime of the log
2704 1a76625f 2018-10-22 stsp * view in order to avoid having to re-fetch commits from disk
2705 1a76625f 2018-10-22 stsp * while updating the display.
2706 1a76625f 2018-10-22 stsp */
2707 4e0d2870 2020-12-07 naddy do {
2708 7210b715 2022-09-11 thomas struct got_object_id id;
2709 9ba79e04 2018-06-11 stsp struct got_commit_object *commit;
2710 93e45b7c 2018-09-24 stsp struct commit_queue_entry *entry;
2711 7e8004ba 2022-09-11 thomas int limit_match = 0;
2712 1a76625f 2018-10-22 stsp int errcode;
2713 899d86c2 2018-05-10 stsp
2714 4e0d2870 2020-12-07 naddy err = got_commit_graph_iter_next(&id, a->graph, a->repo,
2715 4e0d2870 2020-12-07 naddy NULL, NULL);
2716 7210b715 2022-09-11 thomas if (err)
2717 ecb28ae0 2018-07-16 stsp break;
2718 899d86c2 2018-05-10 stsp
2719 7210b715 2022-09-11 thomas err = got_object_open_as_commit(&commit, a->repo, &id);
2720 9ba79e04 2018-06-11 stsp if (err)
2721 9ba79e04 2018-06-11 stsp break;
2722 7210b715 2022-09-11 thomas entry = alloc_commit_queue_entry(commit, &id);
2723 9ba79e04 2018-06-11 stsp if (entry == NULL) {
2724 638f9024 2019-05-13 stsp err = got_error_from_errno("alloc_commit_queue_entry");
2725 9ba79e04 2018-06-11 stsp break;
2726 9ba79e04 2018-06-11 stsp }
2727 93e45b7c 2018-09-24 stsp
2728 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
2729 1a76625f 2018-10-22 stsp if (errcode) {
2730 13add988 2019-10-15 stsp err = got_error_set_errno(errcode,
2731 13add988 2019-10-15 stsp "pthread_mutex_lock");
2732 1a76625f 2018-10-22 stsp break;
2733 1a76625f 2018-10-22 stsp }
2734 1a76625f 2018-10-22 stsp
2735 7e8004ba 2022-09-11 thomas entry->idx = a->real_commits->ncommits;
2736 7e8004ba 2022-09-11 thomas TAILQ_INSERT_TAIL(&a->real_commits->head, entry, entry);
2737 7e8004ba 2022-09-11 thomas a->real_commits->ncommits++;
2738 1a76625f 2018-10-22 stsp
2739 7e8004ba 2022-09-11 thomas if (*a->limiting) {
2740 7e8004ba 2022-09-11 thomas err = match_commit(&limit_match, &id, commit,
2741 7e8004ba 2022-09-11 thomas a->limit_regex);
2742 7e8004ba 2022-09-11 thomas if (err)
2743 7e8004ba 2022-09-11 thomas break;
2744 7e8004ba 2022-09-11 thomas
2745 7e8004ba 2022-09-11 thomas if (limit_match) {
2746 7e8004ba 2022-09-11 thomas struct commit_queue_entry *matched;
2747 7e8004ba 2022-09-11 thomas
2748 7e8004ba 2022-09-11 thomas matched = alloc_commit_queue_entry(
2749 7e8004ba 2022-09-11 thomas entry->commit, entry->id);
2750 7e8004ba 2022-09-11 thomas if (matched == NULL) {
2751 7e8004ba 2022-09-11 thomas err = got_error_from_errno(
2752 7e8004ba 2022-09-11 thomas "alloc_commit_queue_entry");
2753 7e8004ba 2022-09-11 thomas break;
2754 7e8004ba 2022-09-11 thomas }
2755 6f6c25d6 2022-09-18 thomas matched->commit = entry->commit;
2756 6f6c25d6 2022-09-18 thomas got_object_commit_retain(entry->commit);
2757 7e8004ba 2022-09-11 thomas
2758 7e8004ba 2022-09-11 thomas matched->idx = a->limit_commits->ncommits;
2759 7e8004ba 2022-09-11 thomas TAILQ_INSERT_TAIL(&a->limit_commits->head,
2760 7e8004ba 2022-09-11 thomas matched, entry);
2761 7e8004ba 2022-09-11 thomas a->limit_commits->ncommits++;
2762 7e8004ba 2022-09-11 thomas }
2763 7e8004ba 2022-09-11 thomas
2764 7e8004ba 2022-09-11 thomas /*
2765 7e8004ba 2022-09-11 thomas * This is how we signal log_thread() that we
2766 7e8004ba 2022-09-11 thomas * have found a match, and that it should be
2767 7e8004ba 2022-09-11 thomas * counted as a new entry for the view.
2768 7e8004ba 2022-09-11 thomas */
2769 7e8004ba 2022-09-11 thomas a->limit_match = limit_match;
2770 7e8004ba 2022-09-11 thomas }
2771 7e8004ba 2022-09-11 thomas
2772 4e0d2870 2020-12-07 naddy if (*a->searching == TOG_SEARCH_FORWARD &&
2773 4e0d2870 2020-12-07 naddy !*a->search_next_done) {
2774 7c1452c1 2020-03-26 stsp int have_match;
2775 7210b715 2022-09-11 thomas err = match_commit(&have_match, &id, commit, a->regex);
2776 7c1452c1 2020-03-26 stsp if (err)
2777 7c1452c1 2020-03-26 stsp break;
2778 7e8004ba 2022-09-11 thomas
2779 7e8004ba 2022-09-11 thomas if (*a->limiting) {
2780 7e8004ba 2022-09-11 thomas if (limit_match && have_match)
2781 7e8004ba 2022-09-11 thomas *a->search_next_done =
2782 7e8004ba 2022-09-11 thomas TOG_SEARCH_HAVE_MORE;
2783 7e8004ba 2022-09-11 thomas } else if (have_match)
2784 4e0d2870 2020-12-07 naddy *a->search_next_done = TOG_SEARCH_HAVE_MORE;
2785 13add988 2019-10-15 stsp }
2786 13add988 2019-10-15 stsp
2787 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
2788 1a76625f 2018-10-22 stsp if (errcode && err == NULL)
2789 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode,
2790 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
2791 7c1452c1 2020-03-26 stsp if (err)
2792 13add988 2019-10-15 stsp break;
2793 4e0d2870 2020-12-07 naddy } while (*a->searching == TOG_SEARCH_FORWARD && !*a->search_next_done);
2794 899d86c2 2018-05-10 stsp
2795 9ba79e04 2018-06-11 stsp return err;
2796 0553a4e3 2018-04-30 stsp }
2797 0553a4e3 2018-04-30 stsp
2798 2b779855 2020-12-05 naddy static void
2799 2b779855 2020-12-05 naddy select_commit(struct tog_log_view_state *s)
2800 2b779855 2020-12-05 naddy {
2801 2b779855 2020-12-05 naddy struct commit_queue_entry *entry;
2802 2b779855 2020-12-05 naddy int ncommits = 0;
2803 2b779855 2020-12-05 naddy
2804 2b779855 2020-12-05 naddy entry = s->first_displayed_entry;
2805 2b779855 2020-12-05 naddy while (entry) {
2806 2b779855 2020-12-05 naddy if (ncommits == s->selected) {
2807 2b779855 2020-12-05 naddy s->selected_entry = entry;
2808 2b779855 2020-12-05 naddy break;
2809 2b779855 2020-12-05 naddy }
2810 2b779855 2020-12-05 naddy entry = TAILQ_NEXT(entry, entry);
2811 2b779855 2020-12-05 naddy ncommits++;
2812 2b779855 2020-12-05 naddy }
2813 2b779855 2020-12-05 naddy }
2814 2b779855 2020-12-05 naddy
2815 0553a4e3 2018-04-30 stsp static const struct got_error *
2816 8fdc79fe 2020-12-01 naddy draw_commits(struct tog_view *view)
2817 0553a4e3 2018-04-30 stsp {
2818 0553a4e3 2018-04-30 stsp const struct got_error *err = NULL;
2819 52b5abe1 2019-08-13 stsp struct tog_log_view_state *s = &view->state.log;
2820 2b779855 2020-12-05 naddy struct commit_queue_entry *entry = s->selected_entry;
2821 bd3f8225 2022-08-12 thomas int limit = view->nlines;
2822 60493ae3 2019-06-20 stsp int width;
2823 cabb4cfd 2023-06-01 thomas int ncommits, author_cols = 4, refstr_cols;
2824 1a76625f 2018-10-22 stsp char *id_str = NULL, *header = NULL, *ncommits_str = NULL;
2825 8b473291 2019-02-21 stsp char *refs_str = NULL;
2826 ecb28ae0 2018-07-16 stsp wchar_t *wline;
2827 11b20872 2019-11-08 stsp struct tog_color *tc;
2828 6db9f7f6 2019-12-10 stsp static const size_t date_display_cols = 12;
2829 cabb4cfd 2023-06-01 thomas struct got_reflist_head *refs;
2830 bd3f8225 2022-08-12 thomas
2831 bd3f8225 2022-08-12 thomas if (view_is_hsplit_top(view))
2832 bd3f8225 2022-08-12 thomas --limit; /* account for border */
2833 0553a4e3 2018-04-30 stsp
2834 8fdc79fe 2020-12-01 naddy if (s->selected_entry &&
2835 8fdc79fe 2020-12-01 naddy !(view->searching && view->search_next_done == 0)) {
2836 8fdc79fe 2020-12-01 naddy err = got_object_id_str(&id_str, s->selected_entry->id);
2837 1a76625f 2018-10-22 stsp if (err)
2838 ecb28ae0 2018-07-16 stsp return err;
2839 51a10b52 2020-12-26 stsp refs = got_reflist_object_id_map_lookup(tog_refs_idmap,
2840 d2075bf3 2020-12-25 stsp s->selected_entry->id);
2841 00ddec2f 2023-05-17 thomas err = build_refs_str(&refs_str, refs, s->selected_entry->id,
2842 00ddec2f 2023-05-17 thomas s->repo);
2843 00ddec2f 2023-05-17 thomas if (err)
2844 00ddec2f 2023-05-17 thomas goto done;
2845 867c6645 2018-07-10 stsp }
2846 359bfafd 2019-02-22 stsp
2847 557d3365 2023-04-14 thomas if (s->thread_args.commits_needed == 0 && !using_mock_io)
2848 359bfafd 2019-02-22 stsp halfdelay(10); /* disable fast refresh */
2849 1a76625f 2018-10-22 stsp
2850 fb280deb 2021-08-30 stsp if (s->thread_args.commits_needed > 0 || s->thread_args.load_all) {
2851 8f4ed634 2020-03-26 stsp if (asprintf(&ncommits_str, " [%d/%d] %s",
2852 7e8004ba 2022-09-11 thomas entry ? entry->idx + 1 : 0, s->commits->ncommits,
2853 ba5cc5fa 2022-09-23 thomas (view->searching && !view->search_next_done) ?
2854 ba5cc5fa 2022-09-23 thomas "searching..." : "loading...") == -1) {
2855 8f4ed634 2020-03-26 stsp err = got_error_from_errno("asprintf");
2856 8f4ed634 2020-03-26 stsp goto done;
2857 8f4ed634 2020-03-26 stsp }
2858 8f4ed634 2020-03-26 stsp } else {
2859 f9686aa5 2020-03-27 stsp const char *search_str = NULL;
2860 7e8004ba 2022-09-11 thomas const char *limit_str = NULL;
2861 f9686aa5 2020-03-27 stsp
2862 f9686aa5 2020-03-27 stsp if (view->searching) {
2863 f9686aa5 2020-03-27 stsp if (view->search_next_done == TOG_SEARCH_NO_MORE)
2864 f9686aa5 2020-03-27 stsp search_str = "no more matches";
2865 f9686aa5 2020-03-27 stsp else if (view->search_next_done == TOG_SEARCH_HAVE_NONE)
2866 f9686aa5 2020-03-27 stsp search_str = "no matches found";
2867 f9686aa5 2020-03-27 stsp else if (!view->search_next_done)
2868 f9686aa5 2020-03-27 stsp search_str = "searching...";
2869 f9686aa5 2020-03-27 stsp }
2870 f9686aa5 2020-03-27 stsp
2871 7e8004ba 2022-09-11 thomas if (s->limit_view && s->commits->ncommits == 0)
2872 7e8004ba 2022-09-11 thomas limit_str = "no matches found";
2873 7e8004ba 2022-09-11 thomas
2874 7e8004ba 2022-09-11 thomas if (asprintf(&ncommits_str, " [%d/%d] %s %s",
2875 7e8004ba 2022-09-11 thomas entry ? entry->idx + 1 : 0, s->commits->ncommits,
2876 7e8004ba 2022-09-11 thomas search_str ? search_str : (refs_str ? refs_str : ""),
2877 7e8004ba 2022-09-11 thomas limit_str ? limit_str : "") == -1) {
2878 8f4ed634 2020-03-26 stsp err = got_error_from_errno("asprintf");
2879 8f4ed634 2020-03-26 stsp goto done;
2880 8f4ed634 2020-03-26 stsp }
2881 8b473291 2019-02-21 stsp }
2882 1a76625f 2018-10-22 stsp
2883 00580e07 2023-06-01 thomas free(refs_str);
2884 00580e07 2023-06-01 thomas refs_str = NULL;
2885 00580e07 2023-06-01 thomas
2886 8fdc79fe 2020-12-01 naddy if (s->in_repo_path && strcmp(s->in_repo_path, "/") != 0) {
2887 91198554 2022-06-23 thomas if (asprintf(&header, "commit %s %s%s", id_str ? id_str :
2888 91198554 2022-06-23 thomas "........................................",
2889 8fdc79fe 2020-12-01 naddy s->in_repo_path, ncommits_str) == -1) {
2890 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
2891 1a76625f 2018-10-22 stsp header = NULL;
2892 1a76625f 2018-10-22 stsp goto done;
2893 1a76625f 2018-10-22 stsp }
2894 c1124f18 2018-12-23 stsp } else if (asprintf(&header, "commit %s%s",
2895 1a76625f 2018-10-22 stsp id_str ? id_str : "........................................",
2896 1a76625f 2018-10-22 stsp ncommits_str) == -1) {
2897 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
2898 1a76625f 2018-10-22 stsp header = NULL;
2899 1a76625f 2018-10-22 stsp goto done;
2900 ecb28ae0 2018-07-16 stsp }
2901 f91a2b48 2022-06-23 thomas err = format_line(&wline, &width, NULL, header, 0, view->ncols, 0, 0);
2902 1a76625f 2018-10-22 stsp if (err)
2903 1a76625f 2018-10-22 stsp goto done;
2904 867c6645 2018-07-10 stsp
2905 2814baeb 2018-08-01 stsp werase(view->window);
2906 867c6645 2018-07-10 stsp
2907 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
2908 a3404814 2018-09-02 stsp wstandout(view->window);
2909 8fdc79fe 2020-12-01 naddy tc = get_color(&s->colors, TOG_COLOR_COMMIT);
2910 11b20872 2019-11-08 stsp if (tc)
2911 86f4aab9 2022-09-09 thomas wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL);
2912 2814baeb 2018-08-01 stsp waddwstr(view->window, wline);
2913 1a76625f 2018-10-22 stsp while (width < view->ncols) {
2914 1a76625f 2018-10-22 stsp waddch(view->window, ' ');
2915 1a76625f 2018-10-22 stsp width++;
2916 1a76625f 2018-10-22 stsp }
2917 86f4aab9 2022-09-09 thomas if (tc)
2918 86f4aab9 2022-09-09 thomas wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL);
2919 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
2920 a3404814 2018-09-02 stsp wstandend(view->window);
2921 ecb28ae0 2018-07-16 stsp free(wline);
2922 ecb28ae0 2018-07-16 stsp if (limit <= 1)
2923 1a76625f 2018-10-22 stsp goto done;
2924 0553a4e3 2018-04-30 stsp
2925 331b1a16 2022-06-23 thomas /* Grow author column size if necessary, and set view->maxx. */
2926 8fdc79fe 2020-12-01 naddy entry = s->first_displayed_entry;
2927 5813d178 2019-03-09 stsp ncommits = 0;
2928 05171be4 2022-06-23 thomas view->maxx = 0;
2929 5813d178 2019-03-09 stsp while (entry) {
2930 f69c5a46 2022-07-19 thomas struct got_commit_object *c = entry->commit;
2931 05171be4 2022-06-23 thomas char *author, *eol, *msg, *msg0;
2932 331b1a16 2022-06-23 thomas wchar_t *wauthor, *wmsg;
2933 5813d178 2019-03-09 stsp int width;
2934 5813d178 2019-03-09 stsp if (ncommits >= limit - 1)
2935 5813d178 2019-03-09 stsp break;
2936 f69c5a46 2022-07-19 thomas if (s->use_committer)
2937 f69c5a46 2022-07-19 thomas author = strdup(got_object_commit_get_committer(c));
2938 f69c5a46 2022-07-19 thomas else
2939 f69c5a46 2022-07-19 thomas author = strdup(got_object_commit_get_author(c));
2940 5813d178 2019-03-09 stsp if (author == NULL) {
2941 638f9024 2019-05-13 stsp err = got_error_from_errno("strdup");
2942 5813d178 2019-03-09 stsp goto done;
2943 5813d178 2019-03-09 stsp }
2944 27a741e5 2019-09-11 stsp err = format_author(&wauthor, &width, author, COLS,
2945 27a741e5 2019-09-11 stsp date_display_cols);
2946 5813d178 2019-03-09 stsp if (author_cols < width)
2947 5813d178 2019-03-09 stsp author_cols = width;
2948 5813d178 2019-03-09 stsp free(wauthor);
2949 5813d178 2019-03-09 stsp free(author);
2950 ef944b8b 2022-07-21 thomas if (err)
2951 ef944b8b 2022-07-21 thomas goto done;
2952 cabb4cfd 2023-06-01 thomas refs = got_reflist_object_id_map_lookup(tog_refs_idmap,
2953 cabb4cfd 2023-06-01 thomas entry->id);
2954 cabb4cfd 2023-06-01 thomas err = build_refs_str(&refs_str, refs, entry->id, s->repo);
2955 cabb4cfd 2023-06-01 thomas if (err)
2956 cabb4cfd 2023-06-01 thomas goto done;
2957 cabb4cfd 2023-06-01 thomas if (refs_str) {
2958 cabb4cfd 2023-06-01 thomas wchar_t *ws;
2959 cabb4cfd 2023-06-01 thomas err = format_line(&ws, &width, NULL, refs_str,
2960 cabb4cfd 2023-06-01 thomas 0, INT_MAX, date_display_cols + author_cols, 0);
2961 cabb4cfd 2023-06-01 thomas free(ws);
2962 00580e07 2023-06-01 thomas free(refs_str);
2963 00580e07 2023-06-01 thomas refs_str = NULL;
2964 cabb4cfd 2023-06-01 thomas if (err)
2965 cabb4cfd 2023-06-01 thomas goto done;
2966 cabb4cfd 2023-06-01 thomas refstr_cols = width + 3; /* account for [ ] + space */
2967 cabb4cfd 2023-06-01 thomas } else
2968 cabb4cfd 2023-06-01 thomas refstr_cols = 0;
2969 f69c5a46 2022-07-19 thomas err = got_object_commit_get_logmsg(&msg0, c);
2970 05171be4 2022-06-23 thomas if (err)
2971 05171be4 2022-06-23 thomas goto done;
2972 05171be4 2022-06-23 thomas msg = msg0;
2973 05171be4 2022-06-23 thomas while (*msg == '\n')
2974 05171be4 2022-06-23 thomas ++msg;
2975 05171be4 2022-06-23 thomas if ((eol = strchr(msg, '\n')))
2976 331b1a16 2022-06-23 thomas *eol = '\0';
2977 f91a2b48 2022-06-23 thomas err = format_line(&wmsg, &width, NULL, msg, 0, INT_MAX,
2978 cabb4cfd 2023-06-01 thomas date_display_cols + author_cols + refstr_cols, 0);
2979 331b1a16 2022-06-23 thomas if (err)
2980 331b1a16 2022-06-23 thomas goto done;
2981 cabb4cfd 2023-06-01 thomas view->maxx = MAX(view->maxx, width + refstr_cols);
2982