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