2 5aa81393 2020-01-06 stsp * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
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.
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.
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>
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>
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"
60 881b2d3e 2018-04-30 stsp #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
64 2bd27830 2018-10-22 stsp #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b))
67 a4292ac5 2019-05-12 jcs #define CTRL(x) ((x) & 0x1f)
69 9f7d7167 2018-04-29 stsp #ifndef nitems
70 9f7d7167 2018-04-29 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
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);
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);
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 *[]);
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 },
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,
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
114 9b058f45 2022-06-30 mark #define HSPLIT_SCALE 0.3 /* default horizontal split scale */
116 c3e9aa98 2019-05-13 jcs #define TOG_EOF_STRING "(END)"
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;
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;
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;
135 dbdddfee 2021-06-23 naddy STAILQ_HEAD(tog_colors, tog_color);
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;
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)
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;
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) {
154 cc488aa7 2022-01-23 stsp return NULL;
155 cc488aa7 2022-01-23 stsp } else if (isbackup1 && !isbackup2) {
157 cc488aa7 2022-01-23 stsp return NULL;
160 cc488aa7 2022-01-23 stsp *cmp = got_path_cmp(name1, name2, strlen(name1), strlen(name2));
161 cc488aa7 2022-01-23 stsp return NULL;
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)
167 51a10b52 2020-12-26 stsp const struct got_error *err;
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,
173 51a10b52 2020-12-26 stsp return err;
175 51a10b52 2020-12-26 stsp return got_reflist_object_id_map_create(&tog_refs_idmap, &tog_refs,
179 51a10b52 2020-12-26 stsp static void
180 51a10b52 2020-12-26 stsp tog_free_refs(void)
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;
186 51a10b52 2020-12-26 stsp got_ref_list_free(&tog_refs);
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)
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;
197 11b20872 2019-11-08 stsp if (idx < 1 || idx > COLOR_PAIRS - 1)
198 11b20872 2019-11-08 stsp return NULL;
200 11b20872 2019-11-08 stsp init_pair(idx, color, -1);
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);
216 11b20872 2019-11-08 stsp return err;
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;
223 11b20872 2019-11-08 stsp static void
224 11b20872 2019-11-08 stsp free_colors(struct tog_colors *colors)
226 11b20872 2019-11-08 stsp struct tog_color *tc;
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);
236 336075a4 2022-06-25 op static struct tog_color *
237 11b20872 2019-11-08 stsp get_color(struct tog_colors *colors, int colorpair)
239 11b20872 2019-11-08 stsp struct tog_color *tc = NULL;
241 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(tc, colors, entry) {
242 11b20872 2019-11-08 stsp if (tc->colorpair == colorpair)
246 11b20872 2019-11-08 stsp return NULL;
250 11b20872 2019-11-08 stsp default_color_value(const char *envvar)
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;
287 11b20872 2019-11-08 stsp get_color_value(const char *envvar)
289 11b20872 2019-11-08 stsp const char *val = getenv(envvar);
291 11b20872 2019-11-08 stsp if (val == NULL)
292 11b20872 2019-11-08 stsp return default_color_value(envvar);
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)
313 11b20872 2019-11-08 stsp return default_color_value(envvar);
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;
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;
335 15a087fe 2019-02-21 stsp /* passed from log view; may be NULL */
336 fb872ab2 2019-02-21 stsp struct tog_view *log_view;
339 1a76625f 2018-10-22 stsp pthread_mutex_t tog_mutex = PTHREAD_MUTEX_INITIALIZER;
341 1a76625f 2018-10-22 stsp struct tog_log_thread_args {
342 1a76625f 2018-10-22 stsp pthread_cond_t need_commits;
343 7c1452c1 2020-03-26 stsp pthread_cond_t commit_loaded;
344 1a76625f 2018-10-22 stsp int commits_needed;
345 fb280deb 2021-08-30 stsp int load_all;
346 b01e7d3b 2018-08-04 stsp struct got_commit_graph *graph;
347 1a76625f 2018-10-22 stsp struct commit_queue *commits;
348 1a76625f 2018-10-22 stsp const char *in_repo_path;
349 1a76625f 2018-10-22 stsp struct got_object_id *start_id;
350 1a76625f 2018-10-22 stsp struct got_repository *repo;
351 74467cc8 2022-06-15 stsp int *pack_fds;
352 1a76625f 2018-10-22 stsp int log_complete;
353 1a76625f 2018-10-22 stsp sig_atomic_t *quit;
354 1a76625f 2018-10-22 stsp struct commit_queue_entry **first_displayed_entry;
355 1a76625f 2018-10-22 stsp struct commit_queue_entry **selected_entry;
356 13add988 2019-10-15 stsp int *searching;
357 13add988 2019-10-15 stsp int *search_next_done;
358 13add988 2019-10-15 stsp regex_t *regex;
361 1a76625f 2018-10-22 stsp struct tog_log_view_state {
362 b01e7d3b 2018-08-04 stsp struct commit_queue commits;
363 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *first_displayed_entry;
364 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *last_displayed_entry;
365 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *selected_entry;
366 b01e7d3b 2018-08-04 stsp int selected;
367 b01e7d3b 2018-08-04 stsp char *in_repo_path;
368 9cd7cbd1 2020-12-07 stsp char *head_ref_name;
369 b672a97a 2020-01-27 stsp int log_branches;
370 b01e7d3b 2018-08-04 stsp struct got_repository *repo;
371 5036bf37 2018-09-24 stsp struct got_object_id *start_id;
372 1a76625f 2018-10-22 stsp sig_atomic_t quit;
373 1a76625f 2018-10-22 stsp pthread_t thread;
374 1a76625f 2018-10-22 stsp struct tog_log_thread_args thread_args;
375 60493ae3 2019-06-20 stsp struct commit_queue_entry *matched_entry;
376 96e2b566 2019-07-08 stsp struct commit_queue_entry *search_entry;
377 11b20872 2019-11-08 stsp struct tog_colors colors;
380 11b20872 2019-11-08 stsp #define TOG_COLOR_DIFF_MINUS 1
381 11b20872 2019-11-08 stsp #define TOG_COLOR_DIFF_PLUS 2
382 11b20872 2019-11-08 stsp #define TOG_COLOR_DIFF_CHUNK_HEADER 3
383 11b20872 2019-11-08 stsp #define TOG_COLOR_DIFF_META 4
384 11b20872 2019-11-08 stsp #define TOG_COLOR_TREE_SUBMODULE 5
385 11b20872 2019-11-08 stsp #define TOG_COLOR_TREE_SYMLINK 6
386 11b20872 2019-11-08 stsp #define TOG_COLOR_TREE_DIRECTORY 7
387 11b20872 2019-11-08 stsp #define TOG_COLOR_TREE_EXECUTABLE 8
388 11b20872 2019-11-08 stsp #define TOG_COLOR_COMMIT 9
389 11b20872 2019-11-08 stsp #define TOG_COLOR_AUTHOR 10
390 bf30f154 2020-12-07 naddy #define TOG_COLOR_DATE 11
391 6458efa5 2020-11-24 stsp #define TOG_COLOR_REFS_HEADS 12
392 6458efa5 2020-11-24 stsp #define TOG_COLOR_REFS_TAGS 13
393 6458efa5 2020-11-24 stsp #define TOG_COLOR_REFS_REMOTES 14
394 cc488aa7 2022-01-23 stsp #define TOG_COLOR_REFS_BACKUP 15
396 e9424729 2018-08-04 stsp struct tog_blame_cb_args {
397 e9424729 2018-08-04 stsp struct tog_blame_line *lines; /* one per line */
398 e9424729 2018-08-04 stsp int nlines;
400 e9424729 2018-08-04 stsp struct tog_view *view;
401 e9424729 2018-08-04 stsp struct got_object_id *commit_id;
405 e9424729 2018-08-04 stsp struct tog_blame_thread_args {
406 e9424729 2018-08-04 stsp const char *path;
407 e9424729 2018-08-04 stsp struct got_repository *repo;
408 e9424729 2018-08-04 stsp struct tog_blame_cb_args *cb_args;
409 e9424729 2018-08-04 stsp int *complete;
410 fc06ba56 2019-08-22 stsp got_cancel_cb cancel_cb;
411 fc06ba56 2019-08-22 stsp void *cancel_arg;
414 e9424729 2018-08-04 stsp struct tog_blame {
416 be659d10 2020-11-18 stsp off_t filesize;
417 e9424729 2018-08-04 stsp struct tog_blame_line *lines;
418 6fcac457 2018-11-19 stsp int nlines;
419 6c4c42e0 2019-06-24 stsp off_t *line_offsets;
420 e9424729 2018-08-04 stsp pthread_t thread;
421 e9424729 2018-08-04 stsp struct tog_blame_thread_args thread_args;
422 e9424729 2018-08-04 stsp struct tog_blame_cb_args cb_args;
423 e9424729 2018-08-04 stsp const char *path;
424 0ae84acc 2022-06-15 tracey int *pack_fds;
427 7cbe629d 2018-08-04 stsp struct tog_blame_view_state {
428 7cbe629d 2018-08-04 stsp int first_displayed_line;
429 7cbe629d 2018-08-04 stsp int last_displayed_line;
430 7cbe629d 2018-08-04 stsp int selected_line;
431 7cbe629d 2018-08-04 stsp int blame_complete;
434 7cbe629d 2018-08-04 stsp struct got_object_id_queue blamed_commits;
435 7cbe629d 2018-08-04 stsp struct got_object_qid *blamed_commit;
436 e5a0f69f 2018-08-18 stsp char *path;
437 7cbe629d 2018-08-04 stsp struct got_repository *repo;
438 ad80ab7b 2018-08-04 stsp struct got_object_id *commit_id;
439 e9424729 2018-08-04 stsp struct tog_blame blame;
440 6c4c42e0 2019-06-24 stsp int matched_line;
441 11b20872 2019-11-08 stsp struct tog_colors colors;
444 ad80ab7b 2018-08-04 stsp struct tog_parent_tree {
445 ad80ab7b 2018-08-04 stsp TAILQ_ENTRY(tog_parent_tree) entry;
446 ad80ab7b 2018-08-04 stsp struct got_tree_object *tree;
447 ad80ab7b 2018-08-04 stsp struct got_tree_entry *first_displayed_entry;
448 ad80ab7b 2018-08-04 stsp struct got_tree_entry *selected_entry;
449 ad80ab7b 2018-08-04 stsp int selected;
452 ad80ab7b 2018-08-04 stsp TAILQ_HEAD(tog_parent_trees, tog_parent_tree);
454 ad80ab7b 2018-08-04 stsp struct tog_tree_view_state {
455 ad80ab7b 2018-08-04 stsp char *tree_label;
456 bc573f3b 2021-07-10 stsp struct got_object_id *commit_id;/* commit which this tree belongs to */
457 bc573f3b 2021-07-10 stsp struct got_tree_object *root; /* the commit's root tree entry */
458 bc573f3b 2021-07-10 stsp struct got_tree_object *tree; /* currently displayed (sub-)tree */
459 ad80ab7b 2018-08-04 stsp struct got_tree_entry *first_displayed_entry;
460 ad80ab7b 2018-08-04 stsp struct got_tree_entry *last_displayed_entry;
461 ad80ab7b 2018-08-04 stsp struct got_tree_entry *selected_entry;
462 416a95c5 2019-01-24 stsp int ndisplayed, selected, show_ids;
463 bc573f3b 2021-07-10 stsp struct tog_parent_trees parents; /* parent trees of current sub-tree */
464 9cd7cbd1 2020-12-07 stsp char *head_ref_name;
465 ad80ab7b 2018-08-04 stsp struct got_repository *repo;
466 7c32bd05 2019-06-22 stsp struct got_tree_entry *matched_entry;
467 6458efa5 2020-11-24 stsp struct tog_colors colors;
470 6458efa5 2020-11-24 stsp struct tog_reflist_entry {
471 6458efa5 2020-11-24 stsp TAILQ_ENTRY(tog_reflist_entry) entry;
472 6458efa5 2020-11-24 stsp struct got_reference *ref;
476 6458efa5 2020-11-24 stsp TAILQ_HEAD(tog_reflist_head, tog_reflist_entry);
478 6458efa5 2020-11-24 stsp struct tog_ref_view_state {
479 dae613fa 2020-12-26 stsp struct tog_reflist_head refs;
480 6458efa5 2020-11-24 stsp struct tog_reflist_entry *first_displayed_entry;
481 6458efa5 2020-11-24 stsp struct tog_reflist_entry *last_displayed_entry;
482 6458efa5 2020-11-24 stsp struct tog_reflist_entry *selected_entry;
483 b4996bee 2022-06-16 stsp int nrefs, ndisplayed, selected, show_date, show_ids, sort_by_date;
484 6458efa5 2020-11-24 stsp struct got_repository *repo;
485 6458efa5 2020-11-24 stsp struct tog_reflist_entry *matched_entry;
486 bddb1296 2019-11-08 stsp struct tog_colors colors;
490 669b5ffa 2018-10-07 stsp * We implement two types of views: parent views and child views.
492 e78dc838 2020-12-04 stsp * The 'Tab' key switches focus between a parent view and its child view.
493 669b5ffa 2018-10-07 stsp * Child views are shown side-by-side to their parent view, provided
494 669b5ffa 2018-10-07 stsp * there is enough screen estate.
496 669b5ffa 2018-10-07 stsp * When a new view is opened from within a parent view, this new view
497 669b5ffa 2018-10-07 stsp * becomes a child view of the parent view, replacing any existing child.
499 669b5ffa 2018-10-07 stsp * When a new view is opened from within a child view, this new view
500 669b5ffa 2018-10-07 stsp * becomes a parent view which will obscure the views below until the
501 669b5ffa 2018-10-07 stsp * user quits the new parent view by typing 'q'.
503 669b5ffa 2018-10-07 stsp * This list of views contains parent views only.
504 669b5ffa 2018-10-07 stsp * Child views are only pointed to by their parent view.
506 bcbd79e2 2018-08-19 stsp TAILQ_HEAD(tog_view_list_head, tog_view);
508 cc3c9aac 2018-08-01 stsp struct tog_view {
509 e5a0f69f 2018-08-18 stsp TAILQ_ENTRY(tog_view) entry;
510 26ed57b2 2018-05-19 stsp WINDOW *window;
511 26ed57b2 2018-05-19 stsp PANEL *panel;
512 9b058f45 2022-06-30 mark int nlines, ncols, begin_y, begin_x; /* based on split height/width */
513 145b6838 2022-06-16 stsp int maxx, x; /* max column and current start column */
514 f7d12f7e 2018-08-01 stsp int lines, cols; /* copies of LINES and COLS */
515 9b058f45 2022-06-30 mark int nscrolled, offset; /* lines scrolled and hsplit line offset */
516 640cd7ff 2022-06-22 mark int ch, count; /* current keymap and count prefix */
517 e78dc838 2020-12-04 stsp int focussed; /* Only set on one parent or child view at a time. */
519 669b5ffa 2018-10-07 stsp struct tog_view *parent;
520 669b5ffa 2018-10-07 stsp struct tog_view *child;
523 e78dc838 2020-12-04 stsp * This flag is initially set on parent views when a new child view
524 e78dc838 2020-12-04 stsp * is created. It gets toggled when the 'Tab' key switches focus
525 e78dc838 2020-12-04 stsp * between parent and child.
526 e78dc838 2020-12-04 stsp * The flag indicates whether focus should be passed on to our child
527 e78dc838 2020-12-04 stsp * view if this parent view gets picked for focus after another parent
528 e78dc838 2020-12-04 stsp * view was closed. This prevents child views from losing focus in such
529 e78dc838 2020-12-04 stsp * situations.
531 e78dc838 2020-12-04 stsp int focus_child;
533 9b058f45 2022-06-30 mark enum tog_view_mode mode;
534 5dc9f4bc 2018-08-04 stsp /* type-specific state */
535 d6b05b5b 2018-08-04 stsp enum tog_view_type type;
537 b01e7d3b 2018-08-04 stsp struct tog_diff_view_state diff;
538 b01e7d3b 2018-08-04 stsp struct tog_log_view_state log;
539 7cbe629d 2018-08-04 stsp struct tog_blame_view_state blame;
540 ad80ab7b 2018-08-04 stsp struct tog_tree_view_state tree;
541 6458efa5 2020-11-24 stsp struct tog_ref_view_state ref;
544 e5a0f69f 2018-08-18 stsp const struct got_error *(*show)(struct tog_view *);
545 e5a0f69f 2018-08-18 stsp const struct got_error *(*input)(struct tog_view **,
546 e78dc838 2020-12-04 stsp struct tog_view *, int);
547 917d79a7 2022-07-01 stsp const struct got_error *(*reset)(struct tog_view *);
548 e5a0f69f 2018-08-18 stsp const struct got_error *(*close)(struct tog_view *);
550 60493ae3 2019-06-20 stsp const struct got_error *(*search_start)(struct tog_view *);
551 60493ae3 2019-06-20 stsp const struct got_error *(*search_next)(struct tog_view *);
552 c0c4acc8 2021-01-24 stsp int search_started;
553 60493ae3 2019-06-20 stsp int searching;
554 b1bf1435 2019-06-21 stsp #define TOG_SEARCH_FORWARD 1
555 b1bf1435 2019-06-21 stsp #define TOG_SEARCH_BACKWARD 2
556 60493ae3 2019-06-20 stsp int search_next_done;
557 8f4ed634 2020-03-26 stsp #define TOG_SEARCH_HAVE_MORE 1
558 8f4ed634 2020-03-26 stsp #define TOG_SEARCH_NO_MORE 2
559 f9967bca 2020-03-27 stsp #define TOG_SEARCH_HAVE_NONE 3
560 1803e47f 2019-06-22 stsp regex_t regex;
561 41605754 2020-11-12 stsp regmatch_t regmatch;
564 ba4f502b 2018-08-04 stsp static const struct got_error *open_diff_view(struct tog_view *,
565 3dbaef42 2020-11-24 stsp struct got_object_id *, struct got_object_id *,
566 3dbaef42 2020-11-24 stsp const char *, const char *, int, int, int, struct tog_view *,
567 78756c87 2020-11-24 stsp struct got_repository *);
568 5dc9f4bc 2018-08-04 stsp static const struct got_error *show_diff_view(struct tog_view *);
569 e5a0f69f 2018-08-18 stsp static const struct got_error *input_diff_view(struct tog_view **,
570 e78dc838 2020-12-04 stsp struct tog_view *, int);
571 917d79a7 2022-07-01 stsp static const struct got_error *reset_diff_view(struct tog_view *);
572 e5a0f69f 2018-08-18 stsp static const struct got_error* close_diff_view(struct tog_view *);
573 f44b1f58 2020-02-02 tracey static const struct got_error *search_start_diff_view(struct tog_view *);
574 f44b1f58 2020-02-02 tracey static const struct got_error *search_next_diff_view(struct tog_view *);
576 ba4f502b 2018-08-04 stsp static const struct got_error *open_log_view(struct tog_view *,
577 78756c87 2020-11-24 stsp struct got_object_id *, struct got_repository *,
578 78756c87 2020-11-24 stsp const char *, const char *, int);
579 ba4f502b 2018-08-04 stsp static const struct got_error * show_log_view(struct tog_view *);
580 e5a0f69f 2018-08-18 stsp static const struct got_error *input_log_view(struct tog_view **,
581 e78dc838 2020-12-04 stsp struct tog_view *, int);
582 e5a0f69f 2018-08-18 stsp static const struct got_error *close_log_view(struct tog_view *);
583 60493ae3 2019-06-20 stsp static const struct got_error *search_start_log_view(struct tog_view *);
584 60493ae3 2019-06-20 stsp static const struct got_error *search_next_log_view(struct tog_view *);
586 e5a0f69f 2018-08-18 stsp static const struct got_error *open_blame_view(struct tog_view *, char *,
587 78756c87 2020-11-24 stsp struct got_object_id *, struct got_repository *);
588 7cbe629d 2018-08-04 stsp static const struct got_error *show_blame_view(struct tog_view *);
589 e5a0f69f 2018-08-18 stsp static const struct got_error *input_blame_view(struct tog_view **,
590 e78dc838 2020-12-04 stsp struct tog_view *, int);
591 917d79a7 2022-07-01 stsp static const struct got_error *reset_blame_view(struct tog_view *);
592 e5a0f69f 2018-08-18 stsp static const struct got_error *close_blame_view(struct tog_view *);
593 6c4c42e0 2019-06-24 stsp static const struct got_error *search_start_blame_view(struct tog_view *);
594 6c4c42e0 2019-06-24 stsp static const struct got_error *search_next_blame_view(struct tog_view *);
596 ad80ab7b 2018-08-04 stsp static const struct got_error *open_tree_view(struct tog_view *,
597 bc573f3b 2021-07-10 stsp struct got_object_id *, const char *, struct got_repository *);
598 ad80ab7b 2018-08-04 stsp static const struct got_error *show_tree_view(struct tog_view *);
599 e5a0f69f 2018-08-18 stsp static const struct got_error *input_tree_view(struct tog_view **,
600 e78dc838 2020-12-04 stsp struct tog_view *, int);
601 e5a0f69f 2018-08-18 stsp static const struct got_error *close_tree_view(struct tog_view *);
602 7c32bd05 2019-06-22 stsp static const struct got_error *search_start_tree_view(struct tog_view *);
603 7c32bd05 2019-06-22 stsp static const struct got_error *search_next_tree_view(struct tog_view *);
605 6458efa5 2020-11-24 stsp static const struct got_error *open_ref_view(struct tog_view *,
606 6458efa5 2020-11-24 stsp struct got_repository *);
607 6458efa5 2020-11-24 stsp static const struct got_error *show_ref_view(struct tog_view *);
608 6458efa5 2020-11-24 stsp static const struct got_error *input_ref_view(struct tog_view **,
609 e78dc838 2020-12-04 stsp struct tog_view *, int);
610 6458efa5 2020-11-24 stsp static const struct got_error *close_ref_view(struct tog_view *);
611 6458efa5 2020-11-24 stsp static const struct got_error *search_start_ref_view(struct tog_view *);
612 6458efa5 2020-11-24 stsp static const struct got_error *search_next_ref_view(struct tog_view *);
614 25791caa 2018-10-24 stsp static volatile sig_atomic_t tog_sigwinch_received;
615 83baff54 2019-08-12 stsp static volatile sig_atomic_t tog_sigpipe_received;
616 61266923 2020-01-14 stsp static volatile sig_atomic_t tog_sigcont_received;
617 2497f032 2022-05-31 stsp static volatile sig_atomic_t tog_sigint_received;
618 2497f032 2022-05-31 stsp static volatile sig_atomic_t tog_sigterm_received;
620 25791caa 2018-10-24 stsp static void
621 25791caa 2018-10-24 stsp tog_sigwinch(int signo)
623 25791caa 2018-10-24 stsp tog_sigwinch_received = 1;
626 83baff54 2019-08-12 stsp static void
627 83baff54 2019-08-12 stsp tog_sigpipe(int signo)
629 83baff54 2019-08-12 stsp tog_sigpipe_received = 1;
632 61266923 2020-01-14 stsp static void
633 61266923 2020-01-14 stsp tog_sigcont(int signo)
635 61266923 2020-01-14 stsp tog_sigcont_received = 1;
638 2497f032 2022-05-31 stsp static void
639 2497f032 2022-05-31 stsp tog_sigint(int signo)
641 2497f032 2022-05-31 stsp tog_sigint_received = 1;
644 2497f032 2022-05-31 stsp static void
645 2497f032 2022-05-31 stsp tog_sigterm(int signo)
647 2497f032 2022-05-31 stsp tog_sigterm_received = 1;
651 dd6e31d7 2022-06-17 stsp tog_fatal_signal_received(void)
653 2497f032 2022-05-31 stsp return (tog_sigpipe_received ||
654 2497f032 2022-05-31 stsp tog_sigint_received || tog_sigint_received);
657 e5a0f69f 2018-08-18 stsp static const struct got_error *
658 96a765a8 2018-08-04 stsp view_close(struct tog_view *view)
660 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
662 669b5ffa 2018-10-07 stsp if (view->child) {
663 669b5ffa 2018-10-07 stsp view_close(view->child);
664 669b5ffa 2018-10-07 stsp view->child = NULL;
666 e5a0f69f 2018-08-18 stsp if (view->close)
667 e5a0f69f 2018-08-18 stsp err = view->close(view);
668 ea5e7bb5 2018-08-01 stsp if (view->panel)
669 ea5e7bb5 2018-08-01 stsp del_panel(view->panel);
670 ea5e7bb5 2018-08-01 stsp if (view->window)
671 ea5e7bb5 2018-08-01 stsp delwin(view->window);
672 ea5e7bb5 2018-08-01 stsp free(view);
673 e5a0f69f 2018-08-18 stsp return err;
676 ea5e7bb5 2018-08-01 stsp static struct tog_view *
677 b3665f43 2018-08-04 stsp view_open(int nlines, int ncols, int begin_y, int begin_x,
678 0cf4efb1 2018-09-29 stsp enum tog_view_type type)
680 ad80ab7b 2018-08-04 stsp struct tog_view *view = calloc(1, sizeof(*view));
682 ea5e7bb5 2018-08-01 stsp if (view == NULL)
683 ea5e7bb5 2018-08-01 stsp return NULL;
685 d6b05b5b 2018-08-04 stsp view->type = type;
686 f7d12f7e 2018-08-01 stsp view->lines = LINES;
687 f7d12f7e 2018-08-01 stsp view->cols = COLS;
688 207b9029 2018-08-01 stsp view->nlines = nlines ? nlines : LINES - begin_y;
689 207b9029 2018-08-01 stsp view->ncols = ncols ? ncols : COLS - begin_x;
690 97ddc146 2018-08-01 stsp view->begin_y = begin_y;
691 97ddc146 2018-08-01 stsp view->begin_x = begin_x;
692 842167bf 2018-08-01 stsp view->window = newwin(nlines, ncols, begin_y, begin_x);
693 ea5e7bb5 2018-08-01 stsp if (view->window == NULL) {
694 96a765a8 2018-08-04 stsp view_close(view);
695 ea5e7bb5 2018-08-01 stsp return NULL;
697 ea5e7bb5 2018-08-01 stsp view->panel = new_panel(view->window);
698 0cf4efb1 2018-09-29 stsp if (view->panel == NULL ||
699 0cf4efb1 2018-09-29 stsp set_panel_userptr(view->panel, view) != OK) {
700 96a765a8 2018-08-04 stsp view_close(view);
701 ea5e7bb5 2018-08-01 stsp return NULL;
704 ea5e7bb5 2018-08-01 stsp keypad(view->window, TRUE);
705 ea5e7bb5 2018-08-01 stsp return view;
709 0cf4efb1 2018-09-29 stsp view_split_begin_x(int begin_x)
711 2bd27830 2018-10-22 stsp if (begin_x > 0 || COLS < 120)
713 2bd27830 2018-10-22 stsp return (COLS - MAX(COLS / 2, 80));
716 9b058f45 2022-06-30 mark /* XXX Stub till we decide what to do. */
718 9b058f45 2022-06-30 mark view_split_begin_y(int lines)
720 9b058f45 2022-06-30 mark return lines * HSPLIT_SCALE;
723 5c60c32a 2018-10-18 stsp static const struct got_error *view_resize(struct tog_view *);
725 5c60c32a 2018-10-18 stsp static const struct got_error *
726 5c60c32a 2018-10-18 stsp view_splitscreen(struct tog_view *view)
728 5c60c32a 2018-10-18 stsp const struct got_error *err = NULL;
730 9b058f45 2022-06-30 mark if (view->mode == TOG_VIEW_SPLIT_HRZN) {
731 9b058f45 2022-06-30 mark view->begin_y = view_split_begin_y(view->nlines);
732 9b058f45 2022-06-30 mark view->begin_x = 0;
734 9b058f45 2022-06-30 mark view->begin_x = view_split_begin_x(0);
735 9b058f45 2022-06-30 mark view->begin_y = 0;
737 9b058f45 2022-06-30 mark view->nlines = LINES - view->begin_y;
738 5c60c32a 2018-10-18 stsp view->ncols = COLS - view->begin_x;
739 5c60c32a 2018-10-18 stsp view->lines = LINES;
740 5c60c32a 2018-10-18 stsp view->cols = COLS;
741 5c60c32a 2018-10-18 stsp err = view_resize(view);
743 5c60c32a 2018-10-18 stsp return err;
745 9b058f45 2022-06-30 mark if (view->parent && view->mode == TOG_VIEW_SPLIT_HRZN)
746 9b058f45 2022-06-30 mark view->parent->nlines = view->begin_y;
748 5c60c32a 2018-10-18 stsp if (mvwin(view->window, view->begin_y, view->begin_x) == ERR)
749 638f9024 2019-05-13 stsp return got_error_from_errno("mvwin");
751 5c60c32a 2018-10-18 stsp return NULL;
754 5c60c32a 2018-10-18 stsp static const struct got_error *
755 5c60c32a 2018-10-18 stsp view_fullscreen(struct tog_view *view)
757 5c60c32a 2018-10-18 stsp const struct got_error *err = NULL;
759 5c60c32a 2018-10-18 stsp view->begin_x = 0;
760 5c60c32a 2018-10-18 stsp view->begin_y = 0;
761 5c60c32a 2018-10-18 stsp view->nlines = LINES;
762 5c60c32a 2018-10-18 stsp view->ncols = COLS;
763 5c60c32a 2018-10-18 stsp view->lines = LINES;
764 5c60c32a 2018-10-18 stsp view->cols = COLS;
765 5c60c32a 2018-10-18 stsp err = view_resize(view);
767 5c60c32a 2018-10-18 stsp return err;
769 5c60c32a 2018-10-18 stsp if (mvwin(view->window, view->begin_y, view->begin_x) == ERR)
770 638f9024 2019-05-13 stsp return got_error_from_errno("mvwin");
772 5c60c32a 2018-10-18 stsp return NULL;
776 5c60c32a 2018-10-18 stsp view_is_parent_view(struct tog_view *view)
778 5c60c32a 2018-10-18 stsp return view->parent == NULL;
782 6131ff18 2022-06-20 mark view_is_splitscreen(struct tog_view *view)
784 9b058f45 2022-06-30 mark return view->begin_x > 0 || view->begin_y > 0;
788 24b9cfdc 2022-06-30 stsp view_is_fullscreen(struct tog_view *view)
790 24b9cfdc 2022-06-30 stsp return view->nlines == LINES && view->ncols == COLS;
794 49b24ee5 2022-07-03 mark view_is_hsplit_top(struct tog_view *view)
796 49b24ee5 2022-07-03 mark return view->mode == TOG_VIEW_SPLIT_HRZN && view->child &&
797 49b24ee5 2022-07-03 mark view_is_splitscreen(view->child);
800 9b058f45 2022-06-30 mark static void
801 9b058f45 2022-06-30 mark view_border(struct tog_view *view)
803 9b058f45 2022-06-30 mark PANEL *panel;
804 9b058f45 2022-06-30 mark const struct tog_view *view_above;
806 9b058f45 2022-06-30 mark if (view->parent)
807 9b058f45 2022-06-30 mark return view_border(view->parent);
809 9b058f45 2022-06-30 mark panel = panel_above(view->panel);
810 9b058f45 2022-06-30 mark if (panel == NULL)
813 9b058f45 2022-06-30 mark view_above = panel_userptr(panel);
814 9b058f45 2022-06-30 mark if (view->mode == TOG_VIEW_SPLIT_HRZN)
815 9b058f45 2022-06-30 mark mvwhline(view->window, view_above->begin_y - 1,
816 9b058f45 2022-06-30 mark view->begin_x, got_locale_is_utf8() ?
817 9b058f45 2022-06-30 mark ACS_HLINE : '-', view->ncols);
819 9b058f45 2022-06-30 mark mvwvline(view->window, view->begin_y, view_above->begin_x - 1,
820 9b058f45 2022-06-30 mark got_locale_is_utf8() ? ACS_VLINE : '|', view->nlines);
823 9b058f45 2022-06-30 mark static const struct got_error *request_log_commits(struct tog_view *);
824 9b058f45 2022-06-30 mark static const struct got_error *offset_selection_down(struct tog_view *);
825 9b058f45 2022-06-30 mark static void offset_selection_up(struct tog_view *);
827 4d8c2215 2018-08-19 stsp static const struct got_error *
828 f7d12f7e 2018-08-01 stsp view_resize(struct tog_view *view)
830 9b058f45 2022-06-30 mark const struct got_error *err = NULL;
831 9b058f45 2022-06-30 mark int dif, nlines, ncols;
833 9b058f45 2022-06-30 mark dif = LINES - view->lines; /* line difference */
835 0cf4efb1 2018-09-29 stsp if (view->lines > LINES)
836 0cf4efb1 2018-09-29 stsp nlines = view->nlines - (view->lines - LINES);
838 0cf4efb1 2018-09-29 stsp nlines = view->nlines + (LINES - view->lines);
839 0cf4efb1 2018-09-29 stsp if (view->cols > COLS)
840 0cf4efb1 2018-09-29 stsp ncols = view->ncols - (view->cols - COLS);
842 0cf4efb1 2018-09-29 stsp ncols = view->ncols + (COLS - view->cols);
844 4dd27a72 2022-06-29 stsp if (view->child) {
845 9b058f45 2022-06-30 mark int hs = view->child->begin_y;
847 24b9cfdc 2022-06-30 stsp if (!view_is_fullscreen(view))
848 c71ed39a 2022-06-29 stsp view->child->begin_x = view_split_begin_x(view->begin_x);
849 9b058f45 2022-06-30 mark if (view->mode == TOG_VIEW_SPLIT_HRZN ||
850 9b058f45 2022-06-30 mark view->child->begin_x == 0) {
851 0dbbbe90 2022-06-17 op ncols = COLS;
853 5c60c32a 2018-10-18 stsp view_fullscreen(view->child);
854 5c60c32a 2018-10-18 stsp if (view->child->focussed)
855 5c60c32a 2018-10-18 stsp show_panel(view->child->panel);
857 5c60c32a 2018-10-18 stsp show_panel(view->panel);
859 0dbbbe90 2022-06-17 op ncols = view->child->begin_x;
861 5c60c32a 2018-10-18 stsp view_splitscreen(view->child);
862 5c60c32a 2018-10-18 stsp show_panel(view->child->panel);
865 9b058f45 2022-06-30 mark * Request commits if terminal height was increased in a log
866 9b058f45 2022-06-30 mark * view so we have enough commits loaded to populate the view.
868 9b058f45 2022-06-30 mark if (view->type == TOG_VIEW_LOG && dif > 0) {
869 9b058f45 2022-06-30 mark struct tog_log_view_state *ts = &view->state.log;
871 9b058f45 2022-06-30 mark if (ts->commits.ncommits < ts->selected_entry->idx +
872 9b058f45 2022-06-30 mark view->lines - ts->selected) {
873 9b058f45 2022-06-30 mark view->nscrolled = ts->selected_entry->idx +
874 9b058f45 2022-06-30 mark view->lines - ts->selected -
875 9b058f45 2022-06-30 mark ts->commits.ncommits + dif;
876 9b058f45 2022-06-30 mark err = request_log_commits(view);
878 9b058f45 2022-06-30 mark return err;
883 9b058f45 2022-06-30 mark * XXX This is ugly and needs to be moved into the above
884 9b058f45 2022-06-30 mark * logic but "works" for now and my attempts at moving it
885 9b058f45 2022-06-30 mark * break either 'tab' or 'F' key maps in horizontal splits.
888 9b058f45 2022-06-30 mark err = view_splitscreen(view->child);
890 9b058f45 2022-06-30 mark return err;
891 9b058f45 2022-06-30 mark if (dif < 0) { /* top split decreased */
892 9b058f45 2022-06-30 mark err = offset_selection_down(view);
894 9b058f45 2022-06-30 mark return err;
896 9b058f45 2022-06-30 mark view_border(view);
897 9b058f45 2022-06-30 mark update_panels();
898 9b058f45 2022-06-30 mark doupdate();
899 9b058f45 2022-06-30 mark show_panel(view->child->panel);
900 9b058f45 2022-06-30 mark nlines = view->nlines;
902 0dbbbe90 2022-06-17 op } else if (view->parent == NULL)
903 0dbbbe90 2022-06-17 op ncols = COLS;
905 0dbbbe90 2022-06-17 op if (wresize(view->window, nlines, ncols) == ERR)
906 0dbbbe90 2022-06-17 op return got_error_from_errno("wresize");
907 0dbbbe90 2022-06-17 op if (replace_panel(view->panel, view->window) == ERR)
908 0dbbbe90 2022-06-17 op return got_error_from_errno("replace_panel");
909 0dbbbe90 2022-06-17 op wclear(view->window);
911 0dbbbe90 2022-06-17 op view->nlines = nlines;
912 0dbbbe90 2022-06-17 op view->ncols = ncols;
913 0dbbbe90 2022-06-17 op view->lines = LINES;
914 0dbbbe90 2022-06-17 op view->cols = COLS;
916 5c60c32a 2018-10-18 stsp return NULL;
919 669b5ffa 2018-10-07 stsp static const struct got_error *
920 669b5ffa 2018-10-07 stsp view_close_child(struct tog_view *view)
922 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
924 669b5ffa 2018-10-07 stsp if (view->child == NULL)
925 669b5ffa 2018-10-07 stsp return NULL;
927 669b5ffa 2018-10-07 stsp err = view_close(view->child);
928 669b5ffa 2018-10-07 stsp view->child = NULL;
929 669b5ffa 2018-10-07 stsp return err;
932 0dbbbe90 2022-06-17 op static const struct got_error *
933 669b5ffa 2018-10-07 stsp view_set_child(struct tog_view *view, struct tog_view *child)
935 669b5ffa 2018-10-07 stsp view->child = child;
936 669b5ffa 2018-10-07 stsp child->parent = view;
938 0dbbbe90 2022-06-17 op return view_resize(view);
941 34bc9ec9 2019-02-22 stsp static void
942 79fcf3e4 2018-11-04 stsp tog_resizeterm(void)
944 25791caa 2018-10-24 stsp int cols, lines;
945 25791caa 2018-10-24 stsp struct winsize size;
947 25791caa 2018-10-24 stsp if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0) {
948 25791caa 2018-10-24 stsp cols = 80; /* Default */
949 25791caa 2018-10-24 stsp lines = 24;
951 25791caa 2018-10-24 stsp cols = size.ws_col;
952 25791caa 2018-10-24 stsp lines = size.ws_row;
954 25791caa 2018-10-24 stsp resize_term(lines, cols);
957 2b49a8ae 2019-06-22 stsp static const struct got_error *
958 2b49a8ae 2019-06-22 stsp view_search_start(struct tog_view *view)
960 7c32bd05 2019-06-22 stsp const struct got_error *err = NULL;
961 9b058f45 2022-06-30 mark struct tog_view *v = view;
962 2b49a8ae 2019-06-22 stsp char pattern[1024];
965 c0c4acc8 2021-01-24 stsp if (view->search_started) {
966 c0c4acc8 2021-01-24 stsp regfree(&view->regex);
967 c0c4acc8 2021-01-24 stsp view->searching = 0;
968 c0c4acc8 2021-01-24 stsp memset(&view->regmatch, 0, sizeof(view->regmatch));
970 c0c4acc8 2021-01-24 stsp view->search_started = 0;
972 2b49a8ae 2019-06-22 stsp if (view->nlines < 1)
973 2b49a8ae 2019-06-22 stsp return NULL;
975 49b24ee5 2022-07-03 mark if (view_is_hsplit_top(view))
976 9b058f45 2022-06-30 mark v = view->child;
978 9b058f45 2022-06-30 mark mvwaddstr(v->window, v->nlines - 1, 0, "/");
979 9b058f45 2022-06-30 mark wclrtoeol(v->window);
981 a6d37fac 2022-07-03 mark nodelay(view->window, FALSE); /* block for search term input */
982 2b49a8ae 2019-06-22 stsp nocbreak();
984 9b058f45 2022-06-30 mark ret = wgetnstr(v->window, pattern, sizeof(pattern));
985 9b058f45 2022-06-30 mark wrefresh(v->window);
988 a6d37fac 2022-07-03 mark nodelay(view->window, TRUE);
989 2b49a8ae 2019-06-22 stsp if (ret == ERR)
990 2b49a8ae 2019-06-22 stsp return NULL;
992 41605754 2020-11-12 stsp if (regcomp(&view->regex, pattern, REG_EXTENDED | REG_NEWLINE) == 0) {
993 7c32bd05 2019-06-22 stsp err = view->search_start(view);
995 7c32bd05 2019-06-22 stsp regfree(&view->regex);
996 7c32bd05 2019-06-22 stsp return err;
998 c0c4acc8 2021-01-24 stsp view->search_started = 1;
999 2b49a8ae 2019-06-22 stsp view->searching = TOG_SEARCH_FORWARD;
1000 2b49a8ae 2019-06-22 stsp view->search_next_done = 0;
1001 2b49a8ae 2019-06-22 stsp view->search_next(view);
1004 2b49a8ae 2019-06-22 stsp return NULL;
1008 f0032ce6 2022-07-02 mark * Compute view->count from numeric input. Assign total to view->count and
1009 f0032ce6 2022-07-02 mark * return first non-numeric key entered.
1011 640cd7ff 2022-06-22 mark static int
1012 640cd7ff 2022-06-22 mark get_compound_key(struct tog_view *view, int c)
1014 9b058f45 2022-06-30 mark struct tog_view *v = view;
1015 9b058f45 2022-06-30 mark int x, n = 0;
1017 49b24ee5 2022-07-03 mark if (view_is_hsplit_top(view))
1018 9b058f45 2022-06-30 mark v = view->child;
1019 9b058f45 2022-06-30 mark else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent)
1020 9b058f45 2022-06-30 mark v = view->parent;
1022 640cd7ff 2022-06-22 mark view->count = 0;
1023 f0032ce6 2022-07-02 mark cbreak(); /* block for input */
1024 9b058f45 2022-06-30 mark wmove(v->window, v->nlines - 1, 0);
1025 9b058f45 2022-06-30 mark wclrtoeol(v->window);
1026 9b058f45 2022-06-30 mark waddch(v->window, ':');
1029 9b058f45 2022-06-30 mark x = getcurx(v->window);
1030 9b058f45 2022-06-30 mark if (x != ERR && x < view->ncols) {
1031 9b058f45 2022-06-30 mark waddch(v->window, c);
1032 9b058f45 2022-06-30 mark wrefresh(v->window);
1036 640cd7ff 2022-06-22 mark * Don't overflow. Max valid request should be the greatest
1037 640cd7ff 2022-06-22 mark * between the longest and total lines; cap at 10 million.
1039 640cd7ff 2022-06-22 mark if (n >= 9999999)
1040 640cd7ff 2022-06-22 mark n = 9999999;
1042 640cd7ff 2022-06-22 mark n = n * 10 + (c - '0');
1043 640cd7ff 2022-06-22 mark } while (((c = wgetch(view->window))) >= '0' && c <= '9' && c != ERR);
1045 640cd7ff 2022-06-22 mark /* Massage excessive or inapplicable values at the input handler. */
1046 640cd7ff 2022-06-22 mark view->count = n;
1051 0cf4efb1 2018-09-29 stsp static const struct got_error *
1052 e78dc838 2020-12-04 stsp view_input(struct tog_view **new, int *done, struct tog_view *view,
1053 e78dc838 2020-12-04 stsp struct tog_view_list_head *views)
1055 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
1056 669b5ffa 2018-10-07 stsp struct tog_view *v;
1057 1a76625f 2018-10-22 stsp int ch, errcode;
1059 e5a0f69f 2018-08-18 stsp *new = NULL;
1061 f9967bca 2020-03-27 stsp /* Clear "no matches" indicator. */
1062 f9967bca 2020-03-27 stsp if (view->search_next_done == TOG_SEARCH_NO_MORE ||
1063 640cd7ff 2022-06-22 mark view->search_next_done == TOG_SEARCH_HAVE_NONE) {
1064 8f4ed634 2020-03-26 stsp view->search_next_done = TOG_SEARCH_HAVE_MORE;
1065 640cd7ff 2022-06-22 mark view->count = 0;
1068 60493ae3 2019-06-20 stsp if (view->searching && !view->search_next_done) {
1069 82954512 2020-02-03 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1070 82954512 2020-02-03 stsp if (errcode)
1071 82954512 2020-02-03 stsp return got_error_set_errno(errcode,
1072 82954512 2020-02-03 stsp "pthread_mutex_unlock");
1073 3da8ef85 2021-09-21 stsp sched_yield();
1074 82954512 2020-02-03 stsp errcode = pthread_mutex_lock(&tog_mutex);
1075 82954512 2020-02-03 stsp if (errcode)
1076 82954512 2020-02-03 stsp return got_error_set_errno(errcode,
1077 82954512 2020-02-03 stsp "pthread_mutex_lock");
1078 60493ae3 2019-06-20 stsp view->search_next(view);
1079 60493ae3 2019-06-20 stsp return NULL;
1082 a6d37fac 2022-07-03 mark nodelay(view->window, FALSE);
1083 1a76625f 2018-10-22 stsp /* Allow threads to make progress while we are waiting for input. */
1084 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1085 1a76625f 2018-10-22 stsp if (errcode)
1086 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_unlock");
1087 a6d37fac 2022-07-03 mark /* If we have an unfinished count, let C-g or backspace abort. */
1088 a6d37fac 2022-07-03 mark if (view->count && --view->count) {
1090 a6d37fac 2022-07-03 mark nodelay(view->window, TRUE);
1091 640cd7ff 2022-06-22 mark ch = wgetch(view->window);
1092 a6d37fac 2022-07-03 mark if (ch == CTRL('g') || ch == KEY_BACKSPACE)
1093 a6d37fac 2022-07-03 mark view->count = 0;
1095 a6d37fac 2022-07-03 mark ch = view->ch;
1097 a6d37fac 2022-07-03 mark ch = wgetch(view->window);
1098 640cd7ff 2022-06-22 mark if (ch >= '1' && ch <= '9')
1099 640cd7ff 2022-06-22 mark view->ch = ch = get_compound_key(view, ch);
1101 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
1102 1a76625f 2018-10-22 stsp if (errcode)
1103 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_lock");
1104 a6d37fac 2022-07-03 mark nodelay(view->window, TRUE);
1106 61266923 2020-01-14 stsp if (tog_sigwinch_received || tog_sigcont_received) {
1107 25791caa 2018-10-24 stsp tog_resizeterm();
1108 25791caa 2018-10-24 stsp tog_sigwinch_received = 0;
1109 61266923 2020-01-14 stsp tog_sigcont_received = 0;
1110 25791caa 2018-10-24 stsp TAILQ_FOREACH(v, views, entry) {
1111 25791caa 2018-10-24 stsp err = view_resize(v);
1113 25791caa 2018-10-24 stsp return err;
1114 e78dc838 2020-12-04 stsp err = v->input(new, v, KEY_RESIZE);
1116 25791caa 2018-10-24 stsp return err;
1117 cdfcfb03 2020-12-06 stsp if (v->child) {
1118 cdfcfb03 2020-12-06 stsp err = view_resize(v->child);
1120 cdfcfb03 2020-12-06 stsp return err;
1121 cdfcfb03 2020-12-06 stsp err = v->child->input(new, v->child,
1122 cdfcfb03 2020-12-06 stsp KEY_RESIZE);
1124 cdfcfb03 2020-12-06 stsp return err;
1129 e5a0f69f 2018-08-18 stsp switch (ch) {
1131 640cd7ff 2022-06-22 mark view->count = 0;
1132 1e37a5c2 2019-05-12 jcs if (view->child) {
1133 e78dc838 2020-12-04 stsp view->focussed = 0;
1134 e78dc838 2020-12-04 stsp view->child->focussed = 1;
1135 e78dc838 2020-12-04 stsp view->focus_child = 1;
1136 1e37a5c2 2019-05-12 jcs } else if (view->parent) {
1137 e78dc838 2020-12-04 stsp view->focussed = 0;
1138 e78dc838 2020-12-04 stsp view->parent->focussed = 1;
1139 e78dc838 2020-12-04 stsp view->parent->focus_child = 0;
1140 9b058f45 2022-06-30 mark if (!view_is_splitscreen(view)) {
1141 9b058f45 2022-06-30 mark if (view->mode == TOG_VIEW_SPLIT_HRZN &&
1142 9b058f45 2022-06-30 mark view->parent->type == TOG_VIEW_LOG) {
1143 9b058f45 2022-06-30 mark err = request_log_commits(view->parent);
1145 9b058f45 2022-06-30 mark return err;
1147 9b058f45 2022-06-30 mark offset_selection_up(view->parent);
1148 6131ff18 2022-06-20 mark err = view_fullscreen(view->parent);
1150 9b058f45 2022-06-30 mark return err;
1155 9b058f45 2022-06-30 mark if (view->parent && view->mode == TOG_VIEW_SPLIT_HRZN) {
1156 9b058f45 2022-06-30 mark if (view->parent->type == TOG_VIEW_LOG) {
1157 9b058f45 2022-06-30 mark /* might need more commits to fill fullscreen */
1158 9b058f45 2022-06-30 mark err = request_log_commits(view->parent);
1162 9b058f45 2022-06-30 mark offset_selection_up(view->parent);
1163 9b058f45 2022-06-30 mark view->parent->mode = TOG_VIEW_SPLIT_NONE;
1165 e78dc838 2020-12-04 stsp err = view->input(new, view, ch);
1166 9970f7fc 2020-12-03 stsp view->dying = 1;
1172 640cd7ff 2022-06-22 mark view->count = 0;
1173 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view)) {
1174 1e37a5c2 2019-05-12 jcs if (view->child == NULL)
1176 1e37a5c2 2019-05-12 jcs if (view_is_splitscreen(view->child)) {
1177 e78dc838 2020-12-04 stsp view->focussed = 0;
1178 e78dc838 2020-12-04 stsp view->child->focussed = 1;
1179 1e37a5c2 2019-05-12 jcs err = view_fullscreen(view->child);
1181 1e37a5c2 2019-05-12 jcs err = view_splitscreen(view->child);
1184 e78dc838 2020-12-04 stsp err = view->child->input(new, view->child,
1185 9970f7fc 2020-12-03 stsp KEY_RESIZE);
1187 1e37a5c2 2019-05-12 jcs if (view_is_splitscreen(view)) {
1188 e78dc838 2020-12-04 stsp view->parent->focussed = 0;
1189 e78dc838 2020-12-04 stsp view->focussed = 1;
1190 1e37a5c2 2019-05-12 jcs err = view_fullscreen(view);
1192 1e37a5c2 2019-05-12 jcs err = view_splitscreen(view);
1193 9b058f45 2022-06-30 mark if (!err && view->mode != TOG_VIEW_SPLIT_HRZN)
1194 6131ff18 2022-06-20 mark err = view_resize(view->parent);
1198 e78dc838 2020-12-04 stsp err = view->input(new, view, KEY_RESIZE);
1202 9b058f45 2022-06-30 mark if (view->type == TOG_VIEW_LOG) {
1203 9b058f45 2022-06-30 mark err = request_log_commits(view);
1207 9b058f45 2022-06-30 mark if (view->parent)
1208 9b058f45 2022-06-30 mark err = offset_selection_down(view->parent);
1210 9b058f45 2022-06-30 mark err = offset_selection_down(view);
1212 1e37a5c2 2019-05-12 jcs case KEY_RESIZE:
1215 640cd7ff 2022-06-22 mark view->count = 0;
1216 60493ae3 2019-06-20 stsp if (view->search_start)
1217 2b49a8ae 2019-06-22 stsp view_search_start(view);
1219 e78dc838 2020-12-04 stsp err = view->input(new, view, ch);
1223 c0c4acc8 2021-01-24 stsp if (view->search_started && view->search_next) {
1224 b1bf1435 2019-06-21 stsp view->searching = (ch == 'n' ?
1225 b1bf1435 2019-06-21 stsp TOG_SEARCH_FORWARD : TOG_SEARCH_BACKWARD);
1226 60493ae3 2019-06-20 stsp view->search_next_done = 0;
1227 60493ae3 2019-06-20 stsp view->search_next(view);
1229 e78dc838 2020-12-04 stsp err = view->input(new, view, ch);
1232 917d79a7 2022-07-01 stsp if (tog_diff_algo == GOT_DIFF_ALGORITHM_MYERS)
1233 917d79a7 2022-07-01 stsp tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
1235 917d79a7 2022-07-01 stsp tog_diff_algo = GOT_DIFF_ALGORITHM_MYERS;
1236 917d79a7 2022-07-01 stsp TAILQ_FOREACH(v, views, entry) {
1237 917d79a7 2022-07-01 stsp if (v->reset) {
1238 917d79a7 2022-07-01 stsp err = v->reset(v);
1240 917d79a7 2022-07-01 stsp return err;
1242 917d79a7 2022-07-01 stsp if (v->child && v->child->reset) {
1243 917d79a7 2022-07-01 stsp err = v->child->reset(v->child);
1245 917d79a7 2022-07-01 stsp return err;
1250 e78dc838 2020-12-04 stsp err = view->input(new, view, ch);
1254 e5a0f69f 2018-08-18 stsp return err;
1258 a3404814 2018-09-02 stsp view_needs_focus_indication(struct tog_view *view)
1260 669b5ffa 2018-10-07 stsp if (view_is_parent_view(view)) {
1261 acdafe9c 2020-12-03 stsp if (view->child == NULL || view->child->focussed)
1263 669b5ffa 2018-10-07 stsp if (!view_is_splitscreen(view->child))
1265 669b5ffa 2018-10-07 stsp } else if (!view_is_splitscreen(view))
1268 669b5ffa 2018-10-07 stsp return view->focussed;
1271 bcbd79e2 2018-08-19 stsp static const struct got_error *
1272 e5a0f69f 2018-08-18 stsp view_loop(struct tog_view *view)
1274 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
1275 e5a0f69f 2018-08-18 stsp struct tog_view_list_head views;
1276 fb59748f 2020-12-05 stsp struct tog_view *new_view;
1277 fd823528 2018-10-22 stsp int fast_refresh = 10;
1278 1a76625f 2018-10-22 stsp int done = 0, errcode;
1280 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
1281 1a76625f 2018-10-22 stsp if (errcode)
1282 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_lock");
1284 e5a0f69f 2018-08-18 stsp TAILQ_INIT(&views);
1285 e5a0f69f 2018-08-18 stsp TAILQ_INSERT_HEAD(&views, view, entry);
1287 1004088d 2018-09-29 stsp view->focussed = 1;
1288 878940b7 2018-09-29 stsp err = view->show(view);
1290 0cf4efb1 2018-09-29 stsp return err;
1291 0cf4efb1 2018-09-29 stsp update_panels();
1292 0cf4efb1 2018-09-29 stsp doupdate();
1293 2497f032 2022-05-31 stsp while (!TAILQ_EMPTY(&views) && !done && !tog_fatal_signal_received()) {
1294 fd823528 2018-10-22 stsp /* Refresh fast during initialization, then become slower. */
1295 fd823528 2018-10-22 stsp if (fast_refresh && fast_refresh-- == 0)
1296 fd823528 2018-10-22 stsp halfdelay(10); /* switch to once per second */
1298 e78dc838 2020-12-04 stsp err = view_input(&new_view, &done, view, &views);
1301 9970f7fc 2020-12-03 stsp if (view->dying) {
1302 e78dc838 2020-12-04 stsp struct tog_view *v, *prev = NULL;
1304 9970f7fc 2020-12-03 stsp if (view_is_parent_view(view))
1305 9970f7fc 2020-12-03 stsp prev = TAILQ_PREV(view, tog_view_list_head,
1307 e78dc838 2020-12-04 stsp else if (view->parent)
1308 669b5ffa 2018-10-07 stsp prev = view->parent;
1310 e78dc838 2020-12-04 stsp if (view->parent) {
1311 9970f7fc 2020-12-03 stsp view->parent->child = NULL;
1312 e78dc838 2020-12-04 stsp view->parent->focus_child = 0;
1313 9b058f45 2022-06-30 mark /* Restore fullscreen line height. */
1314 9b058f45 2022-06-30 mark view->parent->nlines = view->parent->lines;
1315 0dbbbe90 2022-06-17 op err = view_resize(view->parent);
1319 9970f7fc 2020-12-03 stsp TAILQ_REMOVE(&views, view, entry);
1321 9970f7fc 2020-12-03 stsp err = view_close(view);
1323 e5a0f69f 2018-08-18 stsp goto done;
1325 e78dc838 2020-12-04 stsp view = NULL;
1326 e78dc838 2020-12-04 stsp TAILQ_FOREACH(v, &views, entry) {
1327 e78dc838 2020-12-04 stsp if (v->focussed)
1330 e78dc838 2020-12-04 stsp if (view == NULL && new_view == NULL) {
1331 e78dc838 2020-12-04 stsp /* No view has focus. Try to pick one. */
1333 e78dc838 2020-12-04 stsp view = prev;
1334 e78dc838 2020-12-04 stsp else if (!TAILQ_EMPTY(&views)) {
1335 e78dc838 2020-12-04 stsp view = TAILQ_LAST(&views,
1336 e78dc838 2020-12-04 stsp tog_view_list_head);
1338 e78dc838 2020-12-04 stsp if (view) {
1339 e78dc838 2020-12-04 stsp if (view->focus_child) {
1340 e78dc838 2020-12-04 stsp view->child->focussed = 1;
1341 e78dc838 2020-12-04 stsp view = view->child;
1343 e78dc838 2020-12-04 stsp view->focussed = 1;
1347 bcbd79e2 2018-08-19 stsp if (new_view) {
1348 86c66b02 2018-10-18 stsp struct tog_view *v, *t;
1349 86c66b02 2018-10-18 stsp /* Only allow one parent view per type. */
1350 86c66b02 2018-10-18 stsp TAILQ_FOREACH_SAFE(v, &views, entry, t) {
1351 86c66b02 2018-10-18 stsp if (v->type != new_view->type)
1353 86c66b02 2018-10-18 stsp TAILQ_REMOVE(&views, v, entry);
1354 86c66b02 2018-10-18 stsp err = view_close(v);
1356 86c66b02 2018-10-18 stsp goto done;
1359 bcbd79e2 2018-08-19 stsp TAILQ_INSERT_TAIL(&views, new_view, entry);
1360 fed7eaa8 2018-10-24 stsp view = new_view;
1362 669b5ffa 2018-10-07 stsp if (view) {
1363 e78dc838 2020-12-04 stsp if (view_is_parent_view(view)) {
1364 e78dc838 2020-12-04 stsp if (view->child && view->child->focussed)
1365 e78dc838 2020-12-04 stsp view = view->child;
1367 e78dc838 2020-12-04 stsp if (view->parent && view->parent->focussed)
1368 e78dc838 2020-12-04 stsp view = view->parent;
1370 e78dc838 2020-12-04 stsp show_panel(view->panel);
1371 e78dc838 2020-12-04 stsp if (view->child && view_is_splitscreen(view->child))
1372 e78dc838 2020-12-04 stsp show_panel(view->child->panel);
1373 e78dc838 2020-12-04 stsp if (view->parent && view_is_splitscreen(view)) {
1374 669b5ffa 2018-10-07 stsp err = view->parent->show(view->parent);
1376 1a76625f 2018-10-22 stsp goto done;
1378 669b5ffa 2018-10-07 stsp err = view->show(view);
1380 1a76625f 2018-10-22 stsp goto done;
1381 669b5ffa 2018-10-07 stsp if (view->child) {
1382 669b5ffa 2018-10-07 stsp err = view->child->show(view->child);
1384 1a76625f 2018-10-22 stsp goto done;
1386 1a76625f 2018-10-22 stsp update_panels();
1387 1a76625f 2018-10-22 stsp doupdate();
1391 e5a0f69f 2018-08-18 stsp while (!TAILQ_EMPTY(&views)) {
1392 e5a0f69f 2018-08-18 stsp view = TAILQ_FIRST(&views);
1393 e5a0f69f 2018-08-18 stsp TAILQ_REMOVE(&views, view, entry);
1394 e5a0f69f 2018-08-18 stsp view_close(view);
1397 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1398 963ecf2a 2019-08-12 stsp if (errcode && err == NULL)
1399 963ecf2a 2019-08-12 stsp err = got_error_set_errno(errcode, "pthread_mutex_unlock");
1401 e5a0f69f 2018-08-18 stsp return err;
1404 4ed7e80c 2018-05-20 stsp __dead static void
1405 9f7d7167 2018-04-29 stsp usage_log(void)
1408 c70c5802 2018-08-01 stsp fprintf(stderr,
1409 b672a97a 2020-01-27 stsp "usage: %s log [-b] [-c commit] [-r repository-path] [path]\n",
1410 9f7d7167 2018-04-29 stsp getprogname());
1414 963b370f 2018-05-20 stsp /* Create newly allocated wide-character string equivalent to a byte string. */
1415 80ddbec8 2018-04-29 stsp static const struct got_error *
1416 963b370f 2018-05-20 stsp mbs2ws(wchar_t **ws, size_t *wlen, const char *s)
1418 00dfcb92 2018-06-11 stsp char *vis = NULL;
1419 963b370f 2018-05-20 stsp const struct got_error *err = NULL;
1421 963b370f 2018-05-20 stsp *ws = NULL;
1422 963b370f 2018-05-20 stsp *wlen = mbstowcs(NULL, s, 0);
1423 00dfcb92 2018-06-11 stsp if (*wlen == (size_t)-1) {
1424 00dfcb92 2018-06-11 stsp int vislen;
1425 00dfcb92 2018-06-11 stsp if (errno != EILSEQ)
1426 638f9024 2019-05-13 stsp return got_error_from_errno("mbstowcs");
1428 00dfcb92 2018-06-11 stsp /* byte string invalid in current encoding; try to "fix" it */
1429 00dfcb92 2018-06-11 stsp err = got_mbsavis(&vis, &vislen, s);
1431 00dfcb92 2018-06-11 stsp return err;
1432 00dfcb92 2018-06-11 stsp *wlen = mbstowcs(NULL, vis, 0);
1433 a7f50699 2018-06-11 stsp if (*wlen == (size_t)-1) {
1434 638f9024 2019-05-13 stsp err = got_error_from_errno("mbstowcs"); /* give up */
1435 a7f50699 2018-06-11 stsp goto done;
1439 fd9f4a2d 2019-08-28 hiltjo *ws = calloc(*wlen + 1, sizeof(**ws));
1440 a7f50699 2018-06-11 stsp if (*ws == NULL) {
1441 638f9024 2019-05-13 stsp err = got_error_from_errno("calloc");
1442 a7f50699 2018-06-11 stsp goto done;
1445 00dfcb92 2018-06-11 stsp if (mbstowcs(*ws, vis ? vis : s, *wlen) != *wlen)
1446 638f9024 2019-05-13 stsp err = got_error_from_errno("mbstowcs");
1448 00dfcb92 2018-06-11 stsp free(vis);
1449 963b370f 2018-05-20 stsp if (err) {
1450 963b370f 2018-05-20 stsp free(*ws);
1451 963b370f 2018-05-20 stsp *ws = NULL;
1452 963b370f 2018-05-20 stsp *wlen = 0;
1454 963b370f 2018-05-20 stsp return err;
1457 145b6838 2022-06-16 stsp static const struct got_error *
1458 145b6838 2022-06-16 stsp expand_tab(char **ptr, const char *src)
1460 145b6838 2022-06-16 stsp char *dst;
1461 145b6838 2022-06-16 stsp size_t len, n, idx = 0, sz = 0;
1463 145b6838 2022-06-16 stsp *ptr = NULL;
1464 145b6838 2022-06-16 stsp n = len = strlen(src);
1465 6e1c41ad 2022-06-16 mark dst = malloc(n + 1);
1466 145b6838 2022-06-16 stsp if (dst == NULL)
1467 145b6838 2022-06-16 stsp return got_error_from_errno("malloc");
1469 145b6838 2022-06-16 stsp while (idx < len && src[idx]) {
1470 145b6838 2022-06-16 stsp const char c = src[idx];
1472 145b6838 2022-06-16 stsp if (c == '\t') {
1473 145b6838 2022-06-16 stsp size_t nb = TABSIZE - sz % TABSIZE;
1476 367ddf28 2022-06-16 mark p = realloc(dst, n + nb);
1477 6e1c41ad 2022-06-16 mark if (p == NULL) {
1478 6e1c41ad 2022-06-16 mark free(dst);
1479 6e1c41ad 2022-06-16 mark return got_error_from_errno("realloc");
1484 6e1c41ad 2022-06-16 mark memset(dst + sz, ' ', nb);
1487 145b6838 2022-06-16 stsp dst[sz++] = src[idx];
1491 145b6838 2022-06-16 stsp dst[sz] = '\0';
1492 145b6838 2022-06-16 stsp *ptr = dst;
1493 145b6838 2022-06-16 stsp return NULL;
1497 4e4a9ac8 2022-06-17 op * Advance at most n columns from wline starting at offset off.
1498 4e4a9ac8 2022-06-17 op * Return the index to the first character after the span operation.
1499 4e4a9ac8 2022-06-17 op * Return the combined column width of all spanned wide character in
1503 4e4a9ac8 2022-06-17 op span_wline(int *rcol, int off, wchar_t *wline, int n, int col_tab_align)
1505 4e4a9ac8 2022-06-17 op int width, i, cols = 0;
1507 4e4a9ac8 2022-06-17 op if (n == 0) {
1508 4e4a9ac8 2022-06-17 op *rcol = cols;
1512 4e4a9ac8 2022-06-17 op for (i = off; wline[i] != L'\0'; ++i) {
1513 4e4a9ac8 2022-06-17 op if (wline[i] == L'\t')
1514 4e4a9ac8 2022-06-17 op width = TABSIZE - ((cols + col_tab_align) % TABSIZE);
1516 4e4a9ac8 2022-06-17 op width = wcwidth(wline[i]);
1518 4e4a9ac8 2022-06-17 op if (width == -1) {
1520 4e4a9ac8 2022-06-17 op wline[i] = L'.';
1523 4e4a9ac8 2022-06-17 op if (cols + width > n)
1525 4e4a9ac8 2022-06-17 op cols += width;
1528 4e4a9ac8 2022-06-17 op *rcol = cols;
1533 ccda2f4d 2022-06-16 stsp * Format a line for display, ensuring that it won't overflow a width limit.
1534 ccda2f4d 2022-06-16 stsp * With scrolling, the width returned refers to the scrolled version of the
1535 ccda2f4d 2022-06-16 stsp * line, which starts at (*wlinep)[*scrollxp]. The caller must free *wlinep.
1537 ccda2f4d 2022-06-16 stsp static const struct got_error *
1538 ccda2f4d 2022-06-16 stsp format_line(wchar_t **wlinep, int *widthp, int *scrollxp,
1539 ccda2f4d 2022-06-16 stsp const char *line, int nscroll, int wlimit, int col_tab_align, int expand)
1541 963b370f 2018-05-20 stsp const struct got_error *err = NULL;
1543 963b370f 2018-05-20 stsp wchar_t *wline = NULL;
1544 145b6838 2022-06-16 stsp char *exstr = NULL;
1545 963b370f 2018-05-20 stsp size_t wlen;
1546 4e4a9ac8 2022-06-17 op int i, scrollx;
1548 963b370f 2018-05-20 stsp *wlinep = NULL;
1549 b700b5d6 2018-07-10 stsp *widthp = 0;
1551 145b6838 2022-06-16 stsp if (expand) {
1552 145b6838 2022-06-16 stsp err = expand_tab(&exstr, line);
1554 145b6838 2022-06-16 stsp return err;
1557 145b6838 2022-06-16 stsp err = mbs2ws(&wline, &wlen, expand ? exstr : line);
1558 145b6838 2022-06-16 stsp free(exstr);
1560 963b370f 2018-05-20 stsp return err;
1562 4e4a9ac8 2022-06-17 op scrollx = span_wline(&cols, 0, wline, nscroll, col_tab_align);
1564 3f670bfb 2020-12-10 stsp if (wlen > 0 && wline[wlen - 1] == L'\n') {
1565 3f670bfb 2020-12-10 stsp wline[wlen - 1] = L'\0';
1568 3f670bfb 2020-12-10 stsp if (wlen > 0 && wline[wlen - 1] == L'\r') {
1569 3f670bfb 2020-12-10 stsp wline[wlen - 1] = L'\0';
1573 4e4a9ac8 2022-06-17 op i = span_wline(&cols, scrollx, wline, wlimit, col_tab_align);
1574 4e4a9ac8 2022-06-17 op wline[i] = L'\0';
1576 b700b5d6 2018-07-10 stsp if (widthp)
1577 b700b5d6 2018-07-10 stsp *widthp = cols;
1578 ccda2f4d 2022-06-16 stsp if (scrollxp)
1579 ccda2f4d 2022-06-16 stsp *scrollxp = scrollx;
1581 963b370f 2018-05-20 stsp free(wline);
1583 963b370f 2018-05-20 stsp *wlinep = wline;
1584 963b370f 2018-05-20 stsp return err;
1587 8b473291 2019-02-21 stsp static const struct got_error*
1588 8b473291 2019-02-21 stsp build_refs_str(char **refs_str, struct got_reflist_head *refs,
1589 52b5abe1 2019-08-13 stsp struct got_object_id *id, struct got_repository *repo)
1591 8b473291 2019-02-21 stsp static const struct got_error *err = NULL;
1592 8b473291 2019-02-21 stsp struct got_reflist_entry *re;
1594 8b473291 2019-02-21 stsp const char *name;
1596 8b473291 2019-02-21 stsp *refs_str = NULL;
1598 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, refs, entry) {
1599 52b5abe1 2019-08-13 stsp struct got_tag_object *tag = NULL;
1600 48cae60d 2020-09-22 stsp struct got_object_id *ref_id;
1603 8b473291 2019-02-21 stsp name = got_ref_get_name(re->ref);
1604 8b473291 2019-02-21 stsp if (strcmp(name, GOT_REF_HEAD) == 0)
1606 8b473291 2019-02-21 stsp if (strncmp(name, "refs/", 5) == 0)
1607 8b473291 2019-02-21 stsp name += 5;
1608 cc488aa7 2022-01-23 stsp if (strncmp(name, "got/", 4) == 0 &&
1609 cc488aa7 2022-01-23 stsp strncmp(name, "got/backup/", 11) != 0)
1611 8b473291 2019-02-21 stsp if (strncmp(name, "heads/", 6) == 0)
1612 8b473291 2019-02-21 stsp name += 6;
1613 79cc719f 2020-04-24 stsp if (strncmp(name, "remotes/", 8) == 0) {
1614 8b473291 2019-02-21 stsp name += 8;
1615 79cc719f 2020-04-24 stsp s = strstr(name, "/" GOT_REF_HEAD);
1616 79cc719f 2020-04-24 stsp if (s != NULL && s[strlen(s)] == '\0')
1619 48cae60d 2020-09-22 stsp err = got_ref_resolve(&ref_id, repo, re->ref);
1622 52b5abe1 2019-08-13 stsp if (strncmp(name, "tags/", 5) == 0) {
1623 48cae60d 2020-09-22 stsp err = got_object_open_as_tag(&tag, repo, ref_id);
1624 5d844a1e 2019-08-13 stsp if (err) {
1625 48cae60d 2020-09-22 stsp if (err->code != GOT_ERR_OBJ_TYPE) {
1626 48cae60d 2020-09-22 stsp free(ref_id);
1629 5d844a1e 2019-08-13 stsp /* Ref points at something other than a tag. */
1630 5d844a1e 2019-08-13 stsp err = NULL;
1631 5d844a1e 2019-08-13 stsp tag = NULL;
1634 52b5abe1 2019-08-13 stsp cmp = got_object_id_cmp(tag ?
1635 48cae60d 2020-09-22 stsp got_object_tag_get_object_id(tag) : ref_id, id);
1636 48cae60d 2020-09-22 stsp free(ref_id);
1638 52b5abe1 2019-08-13 stsp got_object_tag_close(tag);
1639 52b5abe1 2019-08-13 stsp if (cmp != 0)
1641 8b473291 2019-02-21 stsp s = *refs_str;
1642 8b473291 2019-02-21 stsp if (asprintf(refs_str, "%s%s%s", s ? s : "",
1643 8b473291 2019-02-21 stsp s ? ", " : "", name) == -1) {
1644 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
1646 8b473291 2019-02-21 stsp *refs_str = NULL;
1652 8b473291 2019-02-21 stsp return err;
1655 963b370f 2018-05-20 stsp static const struct got_error *
1656 27a741e5 2019-09-11 stsp format_author(wchar_t **wauthor, int *author_width, char *author, int limit,
1657 27a741e5 2019-09-11 stsp int col_tab_align)
1659 e6b8b890 2020-12-29 naddy char *smallerthan;
1661 5813d178 2019-03-09 stsp smallerthan = strchr(author, '<');
1662 5813d178 2019-03-09 stsp if (smallerthan && smallerthan[1] != '\0')
1663 5813d178 2019-03-09 stsp author = smallerthan + 1;
1664 e6b8b890 2020-12-29 naddy author[strcspn(author, "@>")] = '\0';
1665 ccda2f4d 2022-06-16 stsp return format_line(wauthor, author_width, NULL, author, 0, limit,
1666 ccda2f4d 2022-06-16 stsp col_tab_align, 0);
1669 5813d178 2019-03-09 stsp static const struct got_error *
1670 2814baeb 2018-08-01 stsp draw_commit(struct tog_view *view, struct got_commit_object *commit,
1671 8fdc79fe 2020-12-01 naddy struct got_object_id *id, const size_t date_display_cols,
1672 8fdc79fe 2020-12-01 naddy int author_display_cols)
1674 8fdc79fe 2020-12-01 naddy struct tog_log_view_state *s = &view->state.log;
1675 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
1676 6db9f7f6 2019-12-10 stsp char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */
1677 80ddbec8 2018-04-29 stsp char *logmsg0 = NULL, *logmsg = NULL;
1678 5813d178 2019-03-09 stsp char *author = NULL;
1679 ccda2f4d 2022-06-16 stsp wchar_t *wlogmsg = NULL, *wauthor = NULL;
1680 bb737323 2018-05-20 stsp int author_width, logmsg_width;
1681 5813d178 2019-03-09 stsp char *newline, *line = NULL;
1682 ccda2f4d 2022-06-16 stsp int col, limit, scrollx;
1683 f7d12f7e 2018-08-01 stsp const int avail = view->ncols;
1684 ccb26ccd 2018-11-05 stsp struct tm tm;
1685 45d799e2 2018-12-23 stsp time_t committer_time;
1686 11b20872 2019-11-08 stsp struct tog_color *tc;
1688 45d799e2 2018-12-23 stsp committer_time = got_object_commit_get_committer_time(commit);
1689 e385fc42 2021-08-30 stsp if (gmtime_r(&committer_time, &tm) == NULL)
1690 e385fc42 2021-08-30 stsp return got_error_from_errno("gmtime_r");
1691 ec6d1a36 2021-03-21 jrick if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d ", &tm) == 0)
1692 b39d25c7 2018-07-10 stsp return got_error(GOT_ERR_NO_SPACE);
1694 27a741e5 2019-09-11 stsp if (avail <= date_display_cols)
1695 b39d25c7 2018-07-10 stsp limit = MIN(sizeof(datebuf) - 1, avail);
1697 b39d25c7 2018-07-10 stsp limit = MIN(date_display_cols, sizeof(datebuf) - 1);
1698 8fdc79fe 2020-12-01 naddy tc = get_color(&s->colors, TOG_COLOR_DATE);
1700 11b20872 2019-11-08 stsp wattr_on(view->window,
1701 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
1702 2814baeb 2018-08-01 stsp waddnstr(view->window, datebuf, limit);
1704 11b20872 2019-11-08 stsp wattr_off(view->window,
1705 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
1706 27a741e5 2019-09-11 stsp col = limit;
1707 b39d25c7 2018-07-10 stsp if (col > avail)
1708 b39d25c7 2018-07-10 stsp goto done;
1710 6570a66d 2019-11-08 stsp if (avail >= 120) {
1711 6570a66d 2019-11-08 stsp char *id_str;
1712 6570a66d 2019-11-08 stsp err = got_object_id_str(&id_str, id);
1714 6570a66d 2019-11-08 stsp goto done;
1715 8fdc79fe 2020-12-01 naddy tc = get_color(&s->colors, TOG_COLOR_COMMIT);
1717 11b20872 2019-11-08 stsp wattr_on(view->window,
1718 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
1719 6570a66d 2019-11-08 stsp wprintw(view->window, "%.8s ", id_str);
1721 11b20872 2019-11-08 stsp wattr_off(view->window,
1722 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
1723 6570a66d 2019-11-08 stsp free(id_str);
1725 6570a66d 2019-11-08 stsp if (col > avail)
1726 6570a66d 2019-11-08 stsp goto done;
1729 5813d178 2019-03-09 stsp author = strdup(got_object_commit_get_author(commit));
1730 5813d178 2019-03-09 stsp if (author == NULL) {
1731 638f9024 2019-05-13 stsp err = got_error_from_errno("strdup");
1732 80ddbec8 2018-04-29 stsp goto done;
1734 27a741e5 2019-09-11 stsp err = format_author(&wauthor, &author_width, author, avail - col, col);
1736 bb737323 2018-05-20 stsp goto done;
1737 8fdc79fe 2020-12-01 naddy tc = get_color(&s->colors, TOG_COLOR_AUTHOR);
1739 11b20872 2019-11-08 stsp wattr_on(view->window,
1740 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
1741 2814baeb 2018-08-01 stsp waddwstr(view->window, wauthor);
1743 11b20872 2019-11-08 stsp wattr_off(view->window,
1744 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
1745 bb737323 2018-05-20 stsp col += author_width;
1746 27a741e5 2019-09-11 stsp while (col < avail && author_width < author_display_cols + 2) {
1747 2814baeb 2018-08-01 stsp waddch(view->window, ' ');
1749 bb737323 2018-05-20 stsp author_width++;
1751 9c2eaf34 2018-05-20 stsp if (col > avail)
1752 9c2eaf34 2018-05-20 stsp goto done;
1754 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
1756 6d9fbc00 2018-04-29 stsp goto done;
1757 bb737323 2018-05-20 stsp logmsg = logmsg0;
1758 bb737323 2018-05-20 stsp while (*logmsg == '\n')
1760 bb737323 2018-05-20 stsp newline = strchr(logmsg, '\n');
1761 bb737323 2018-05-20 stsp if (newline)
1762 bb737323 2018-05-20 stsp *newline = '\0';
1763 ccda2f4d 2022-06-16 stsp limit = avail - col;
1764 49b24ee5 2022-07-03 mark if (view->child && !view_is_hsplit_top(view) && limit > 0)
1765 4d1f6af3 2022-06-17 op limit--; /* for the border */
1766 ccda2f4d 2022-06-16 stsp err = format_line(&wlogmsg, &logmsg_width, &scrollx, logmsg, view->x,
1767 ccda2f4d 2022-06-16 stsp limit, col, 1);
1769 29688b02 2022-06-16 stsp goto done;
1770 ccda2f4d 2022-06-16 stsp waddwstr(view->window, &wlogmsg[scrollx]);
1771 29688b02 2022-06-16 stsp col += MAX(logmsg_width, 0);
1772 27a741e5 2019-09-11 stsp while (col < avail) {
1773 2814baeb 2018-08-01 stsp waddch(view->window, ' ');
1777 80ddbec8 2018-04-29 stsp free(logmsg0);
1778 bb737323 2018-05-20 stsp free(wlogmsg);
1779 5813d178 2019-03-09 stsp free(author);
1780 bb737323 2018-05-20 stsp free(wauthor);
1781 80ddbec8 2018-04-29 stsp free(line);
1782 80ddbec8 2018-04-29 stsp return err;
1785 899d86c2 2018-05-10 stsp static struct commit_queue_entry *
1786 899d86c2 2018-05-10 stsp alloc_commit_queue_entry(struct got_commit_object *commit,
1787 899d86c2 2018-05-10 stsp struct got_object_id *id)
1789 80ddbec8 2018-04-29 stsp struct commit_queue_entry *entry;
1791 80ddbec8 2018-04-29 stsp entry = calloc(1, sizeof(*entry));
1792 80ddbec8 2018-04-29 stsp if (entry == NULL)
1793 899d86c2 2018-05-10 stsp return NULL;
1795 899d86c2 2018-05-10 stsp entry->id = id;
1796 99db9666 2018-05-07 stsp entry->commit = commit;
1797 899d86c2 2018-05-10 stsp return entry;
1800 99db9666 2018-05-07 stsp static void
1801 99db9666 2018-05-07 stsp pop_commit(struct commit_queue *commits)
1803 99db9666 2018-05-07 stsp struct commit_queue_entry *entry;
1805 ecb28ae0 2018-07-16 stsp entry = TAILQ_FIRST(&commits->head);
1806 ecb28ae0 2018-07-16 stsp TAILQ_REMOVE(&commits->head, entry, entry);
1807 99db9666 2018-05-07 stsp got_object_commit_close(entry->commit);
1808 ecb28ae0 2018-07-16 stsp commits->ncommits--;
1809 9ba79e04 2018-06-11 stsp /* Don't free entry->id! It is owned by the commit graph. */
1810 99db9666 2018-05-07 stsp free(entry);
1813 99db9666 2018-05-07 stsp static void
1814 99db9666 2018-05-07 stsp free_commits(struct commit_queue *commits)
1816 ecb28ae0 2018-07-16 stsp while (!TAILQ_EMPTY(&commits->head))
1817 99db9666 2018-05-07 stsp pop_commit(commits);
1820 c4972b91 2018-05-07 stsp static const struct got_error *
1821 13add988 2019-10-15 stsp match_commit(int *have_match, struct got_object_id *id,
1822 13add988 2019-10-15 stsp struct got_commit_object *commit, regex_t *regex)
1824 13add988 2019-10-15 stsp const struct got_error *err = NULL;
1825 13add988 2019-10-15 stsp regmatch_t regmatch;
1826 13add988 2019-10-15 stsp char *id_str = NULL, *logmsg = NULL;
1828 13add988 2019-10-15 stsp *have_match = 0;
1830 13add988 2019-10-15 stsp err = got_object_id_str(&id_str, id);
1832 13add988 2019-10-15 stsp return err;
1834 13add988 2019-10-15 stsp err = got_object_commit_get_logmsg(&logmsg, commit);
1836 13add988 2019-10-15 stsp goto done;
1838 13add988 2019-10-15 stsp if (regexec(regex, got_object_commit_get_author(commit), 1,
1839 13add988 2019-10-15 stsp ®match, 0) == 0 ||
1840 13add988 2019-10-15 stsp regexec(regex, got_object_commit_get_committer(commit), 1,
1841 13add988 2019-10-15 stsp ®match, 0) == 0 ||
1842 13add988 2019-10-15 stsp regexec(regex, id_str, 1, ®match, 0) == 0 ||
1843 13add988 2019-10-15 stsp regexec(regex, logmsg, 1, ®match, 0) == 0)
1844 13add988 2019-10-15 stsp *have_match = 1;
1846 13add988 2019-10-15 stsp free(id_str);
1847 13add988 2019-10-15 stsp free(logmsg);
1848 13add988 2019-10-15 stsp return err;
1851 13add988 2019-10-15 stsp static const struct got_error *
1852 4e0d2870 2020-12-07 naddy queue_commits(struct tog_log_thread_args *a)
1854 899d86c2 2018-05-10 stsp const struct got_error *err = NULL;
1857 1a76625f 2018-10-22 stsp * We keep all commits open throughout the lifetime of the log
1858 1a76625f 2018-10-22 stsp * view in order to avoid having to re-fetch commits from disk
1859 1a76625f 2018-10-22 stsp * while updating the display.
1862 93e45b7c 2018-09-24 stsp struct got_object_id *id;
1863 9ba79e04 2018-06-11 stsp struct got_commit_object *commit;
1864 93e45b7c 2018-09-24 stsp struct commit_queue_entry *entry;
1865 1a76625f 2018-10-22 stsp int errcode;
1867 4e0d2870 2020-12-07 naddy err = got_commit_graph_iter_next(&id, a->graph, a->repo,
1868 4e0d2870 2020-12-07 naddy NULL, NULL);
1869 ee780d5c 2020-01-04 stsp if (err || id == NULL)
1872 4e0d2870 2020-12-07 naddy err = got_object_open_as_commit(&commit, a->repo, id);
1875 9ba79e04 2018-06-11 stsp entry = alloc_commit_queue_entry(commit, id);
1876 9ba79e04 2018-06-11 stsp if (entry == NULL) {
1877 638f9024 2019-05-13 stsp err = got_error_from_errno("alloc_commit_queue_entry");
1881 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
1882 1a76625f 2018-10-22 stsp if (errcode) {
1883 13add988 2019-10-15 stsp err = got_error_set_errno(errcode,
1884 13add988 2019-10-15 stsp "pthread_mutex_lock");
1888 4e0d2870 2020-12-07 naddy entry->idx = a->commits->ncommits;
1889 4e0d2870 2020-12-07 naddy TAILQ_INSERT_TAIL(&a->commits->head, entry, entry);
1890 4e0d2870 2020-12-07 naddy a->commits->ncommits++;
1892 4e0d2870 2020-12-07 naddy if (*a->searching == TOG_SEARCH_FORWARD &&
1893 4e0d2870 2020-12-07 naddy !*a->search_next_done) {
1894 7c1452c1 2020-03-26 stsp int have_match;
1895 4e0d2870 2020-12-07 naddy err = match_commit(&have_match, id, commit, a->regex);
1898 7c1452c1 2020-03-26 stsp if (have_match)
1899 4e0d2870 2020-12-07 naddy *a->search_next_done = TOG_SEARCH_HAVE_MORE;
1902 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1903 1a76625f 2018-10-22 stsp if (errcode && err == NULL)
1904 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode,
1905 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
1908 4e0d2870 2020-12-07 naddy } while (*a->searching == TOG_SEARCH_FORWARD && !*a->search_next_done);
1910 9ba79e04 2018-06-11 stsp return err;
1913 2b779855 2020-12-05 naddy static void
1914 2b779855 2020-12-05 naddy select_commit(struct tog_log_view_state *s)
1916 2b779855 2020-12-05 naddy struct commit_queue_entry *entry;
1917 2b779855 2020-12-05 naddy int ncommits = 0;
1919 2b779855 2020-12-05 naddy entry = s->first_displayed_entry;
1920 2b779855 2020-12-05 naddy while (entry) {
1921 2b779855 2020-12-05 naddy if (ncommits == s->selected) {
1922 2b779855 2020-12-05 naddy s->selected_entry = entry;
1925 2b779855 2020-12-05 naddy entry = TAILQ_NEXT(entry, entry);
1926 2b779855 2020-12-05 naddy ncommits++;
1930 0553a4e3 2018-04-30 stsp static const struct got_error *
1931 8fdc79fe 2020-12-01 naddy draw_commits(struct tog_view *view)
1933 0553a4e3 2018-04-30 stsp const struct got_error *err = NULL;
1934 52b5abe1 2019-08-13 stsp struct tog_log_view_state *s = &view->state.log;
1935 2b779855 2020-12-05 naddy struct commit_queue_entry *entry = s->selected_entry;
1936 8fdc79fe 2020-12-01 naddy const int limit = view->nlines;
1937 60493ae3 2019-06-20 stsp int width;
1938 52e88aae 2019-11-08 stsp int ncommits, author_cols = 4;
1939 1a76625f 2018-10-22 stsp char *id_str = NULL, *header = NULL, *ncommits_str = NULL;
1940 8b473291 2019-02-21 stsp char *refs_str = NULL;
1941 ecb28ae0 2018-07-16 stsp wchar_t *wline;
1942 11b20872 2019-11-08 stsp struct tog_color *tc;
1943 6db9f7f6 2019-12-10 stsp static const size_t date_display_cols = 12;
1945 8fdc79fe 2020-12-01 naddy if (s->selected_entry &&
1946 8fdc79fe 2020-12-01 naddy !(view->searching && view->search_next_done == 0)) {
1947 d2075bf3 2020-12-25 stsp struct got_reflist_head *refs;
1948 8fdc79fe 2020-12-01 naddy err = got_object_id_str(&id_str, s->selected_entry->id);
1950 ecb28ae0 2018-07-16 stsp return err;
1951 51a10b52 2020-12-26 stsp refs = got_reflist_object_id_map_lookup(tog_refs_idmap,
1952 d2075bf3 2020-12-25 stsp s->selected_entry->id);
1953 d2075bf3 2020-12-25 stsp if (refs) {
1954 d2075bf3 2020-12-25 stsp err = build_refs_str(&refs_str, refs,
1955 d2075bf3 2020-12-25 stsp s->selected_entry->id, s->repo);
1957 d2075bf3 2020-12-25 stsp goto done;
1961 8fdc79fe 2020-12-01 naddy if (s->thread_args.commits_needed == 0)
1962 359bfafd 2019-02-22 stsp halfdelay(10); /* disable fast refresh */
1964 fb280deb 2021-08-30 stsp if (s->thread_args.commits_needed > 0 || s->thread_args.load_all) {
1965 8f4ed634 2020-03-26 stsp if (asprintf(&ncommits_str, " [%d/%d] %s",
1966 8fdc79fe 2020-12-01 naddy entry ? entry->idx + 1 : 0, s->commits.ncommits,
1967 d2ad595c 2020-04-09 stsp (view->searching && !view->search_next_done) ?
1968 d2ad595c 2020-04-09 stsp "searching..." : "loading...") == -1) {
1969 8f4ed634 2020-03-26 stsp err = got_error_from_errno("asprintf");
1970 8f4ed634 2020-03-26 stsp goto done;
1973 f9686aa5 2020-03-27 stsp const char *search_str = NULL;
1975 f9686aa5 2020-03-27 stsp if (view->searching) {
1976 f9686aa5 2020-03-27 stsp if (view->search_next_done == TOG_SEARCH_NO_MORE)
1977 f9686aa5 2020-03-27 stsp search_str = "no more matches";
1978 f9686aa5 2020-03-27 stsp else if (view->search_next_done == TOG_SEARCH_HAVE_NONE)
1979 f9686aa5 2020-03-27 stsp search_str = "no matches found";
1980 f9686aa5 2020-03-27 stsp else if (!view->search_next_done)
1981 f9686aa5 2020-03-27 stsp search_str = "searching...";
1984 8f4ed634 2020-03-26 stsp if (asprintf(&ncommits_str, " [%d/%d] %s",
1985 8fdc79fe 2020-12-01 naddy entry ? entry->idx + 1 : 0, s->commits.ncommits,
1986 f9686aa5 2020-03-27 stsp search_str ? search_str :
1987 f9686aa5 2020-03-27 stsp (refs_str ? refs_str : "")) == -1) {
1988 8f4ed634 2020-03-26 stsp err = got_error_from_errno("asprintf");
1989 8f4ed634 2020-03-26 stsp goto done;
1993 8fdc79fe 2020-12-01 naddy if (s->in_repo_path && strcmp(s->in_repo_path, "/") != 0) {
1994 87411fa9 2022-06-16 stsp if (asprintf(&header, "commit %s %s%s", id_str ? id_str :
1995 87411fa9 2022-06-16 stsp "........................................",
1996 8fdc79fe 2020-12-01 naddy s->in_repo_path, ncommits_str) == -1) {
1997 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
1998 1a76625f 2018-10-22 stsp header = NULL;
1999 1a76625f 2018-10-22 stsp goto done;
2001 c1124f18 2018-12-23 stsp } else if (asprintf(&header, "commit %s%s",
2002 1a76625f 2018-10-22 stsp id_str ? id_str : "........................................",
2003 1a76625f 2018-10-22 stsp ncommits_str) == -1) {
2004 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
2005 1a76625f 2018-10-22 stsp header = NULL;
2006 1a76625f 2018-10-22 stsp goto done;
2008 ccda2f4d 2022-06-16 stsp err = format_line(&wline, &width, NULL, header, 0, view->ncols, 0, 0);
2010 1a76625f 2018-10-22 stsp goto done;
2012 2814baeb 2018-08-01 stsp werase(view->window);
2014 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
2015 a3404814 2018-09-02 stsp wstandout(view->window);
2016 8fdc79fe 2020-12-01 naddy tc = get_color(&s->colors, TOG_COLOR_COMMIT);
2018 11b20872 2019-11-08 stsp wattr_on(view->window,
2019 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
2020 2814baeb 2018-08-01 stsp waddwstr(view->window, wline);
2022 11b20872 2019-11-08 stsp wattr_off(view->window,
2023 11b20872 2019-11-08 stsp COLOR_PAIR(tc->colorpair), NULL);
2024 1a76625f 2018-10-22 stsp while (width < view->ncols) {
2025 1a76625f 2018-10-22 stsp waddch(view->window, ' ');
2028 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
2029 a3404814 2018-09-02 stsp wstandend(view->window);
2030 ecb28ae0 2018-07-16 stsp free(wline);
2031 ecb28ae0 2018-07-16 stsp if (limit <= 1)
2032 1a76625f 2018-10-22 stsp goto done;
2034 29688b02 2022-06-16 stsp /* Grow author column size if necessary, and set view->maxx. */
2035 8fdc79fe 2020-12-01 naddy entry = s->first_displayed_entry;
2036 5813d178 2019-03-09 stsp ncommits = 0;
2037 145b6838 2022-06-16 stsp view->maxx = 0;
2038 5813d178 2019-03-09 stsp while (entry) {
2039 145b6838 2022-06-16 stsp char *author, *eol, *msg, *msg0;
2040 29688b02 2022-06-16 stsp wchar_t *wauthor, *wmsg;
2041 5813d178 2019-03-09 stsp int width;
2042 5813d178 2019-03-09 stsp if (ncommits >= limit - 1)
2044 5813d178 2019-03-09 stsp author = strdup(got_object_commit_get_author(entry->commit));
2045 5813d178 2019-03-09 stsp if (author == NULL) {
2046 638f9024 2019-05-13 stsp err = got_error_from_errno("strdup");
2047 5813d178 2019-03-09 stsp goto done;
2049 27a741e5 2019-09-11 stsp err = format_author(&wauthor, &width, author, COLS,
2050 27a741e5 2019-09-11 stsp date_display_cols);
2051 5813d178 2019-03-09 stsp if (author_cols < width)
2052 5813d178 2019-03-09 stsp author_cols = width;
2053 5813d178 2019-03-09 stsp free(wauthor);
2054 5813d178 2019-03-09 stsp free(author);
2055 145b6838 2022-06-16 stsp err = got_object_commit_get_logmsg(&msg0, entry->commit);
2057 145b6838 2022-06-16 stsp goto done;
2058 145b6838 2022-06-16 stsp msg = msg0;
2059 145b6838 2022-06-16 stsp while (*msg == '\n')
2061 145b6838 2022-06-16 stsp if ((eol = strchr(msg, '\n')))
2062 29688b02 2022-06-16 stsp *eol = '\0';
2063 ccda2f4d 2022-06-16 stsp err = format_line(&wmsg, &width, NULL, msg, 0, INT_MAX,
2064 29688b02 2022-06-16 stsp date_display_cols + author_cols, 0);
2066 29688b02 2022-06-16 stsp goto done;
2067 29688b02 2022-06-16 stsp view->maxx = MAX(view->maxx, width);
2068 145b6838 2022-06-16 stsp free(msg0);
2069 29688b02 2022-06-16 stsp free(wmsg);
2070 7ca04879 2019-10-19 stsp ncommits++;
2071 5813d178 2019-03-09 stsp entry = TAILQ_NEXT(entry, entry);
2074 8fdc79fe 2020-12-01 naddy entry = s->first_displayed_entry;
2075 8fdc79fe 2020-12-01 naddy s->last_displayed_entry = s->first_displayed_entry;
2076 867c6645 2018-07-10 stsp ncommits = 0;
2077 899d86c2 2018-05-10 stsp while (entry) {
2078 ecb28ae0 2018-07-16 stsp if (ncommits >= limit - 1)
2080 8fdc79fe 2020-12-01 naddy if (ncommits == s->selected)
2081 2814baeb 2018-08-01 stsp wstandout(view->window);
2082 8fdc79fe 2020-12-01 naddy err = draw_commit(view, entry->commit, entry->id,
2083 8fdc79fe 2020-12-01 naddy date_display_cols, author_cols);
2084 8fdc79fe 2020-12-01 naddy if (ncommits == s->selected)
2085 2814baeb 2018-08-01 stsp wstandend(view->window);
2087 60493ae3 2019-06-20 stsp goto done;
2088 0553a4e3 2018-04-30 stsp ncommits++;
2089 8fdc79fe 2020-12-01 naddy s->last_displayed_entry = entry;
2090 899d86c2 2018-05-10 stsp entry = TAILQ_NEXT(entry, entry);
2093 9b058f45 2022-06-30 mark view_border(view);
2095 1a76625f 2018-10-22 stsp free(id_str);
2096 8b473291 2019-02-21 stsp free(refs_str);
2097 1a76625f 2018-10-22 stsp free(ncommits_str);
2098 1a76625f 2018-10-22 stsp free(header);
2099 80ddbec8 2018-04-29 stsp return err;
2102 07b55e75 2018-05-10 stsp static void
2103 3e135950 2020-12-01 naddy log_scroll_up(struct tog_log_view_state *s, int maxscroll)
2105 07b55e75 2018-05-10 stsp struct commit_queue_entry *entry;
2106 07b55e75 2018-05-10 stsp int nscrolled = 0;
2108 ffe38506 2020-12-01 naddy entry = TAILQ_FIRST(&s->commits.head);
2109 ffe38506 2020-12-01 naddy if (s->first_displayed_entry == entry)
2112 ffe38506 2020-12-01 naddy entry = s->first_displayed_entry;
2113 16482c3b 2018-05-20 stsp while (entry && nscrolled < maxscroll) {
2114 ecb28ae0 2018-07-16 stsp entry = TAILQ_PREV(entry, commit_queue_head, entry);
2115 07b55e75 2018-05-10 stsp if (entry) {
2116 ffe38506 2020-12-01 naddy s->first_displayed_entry = entry;
2117 07b55e75 2018-05-10 stsp nscrolled++;
2122 aa075928 2018-05-10 stsp static const struct got_error *
2123 ffe38506 2020-12-01 naddy trigger_log_thread(struct tog_view *view, int wait)
2125 ffe38506 2020-12-01 naddy struct tog_log_thread_args *ta = &view->state.log.thread_args;
2126 5e224a3e 2019-02-22 stsp int errcode;
2128 8a42fca8 2019-02-22 stsp halfdelay(1); /* fast refresh while loading commits */
2130 fb280deb 2021-08-30 stsp while (ta->commits_needed > 0 || ta->load_all) {
2131 ffe38506 2020-12-01 naddy if (ta->log_complete)
2134 5e224a3e 2019-02-22 stsp /* Wake the log thread. */
2135 ffe38506 2020-12-01 naddy errcode = pthread_cond_signal(&ta->need_commits);
2136 7aafa0d1 2019-02-22 stsp if (errcode)
2137 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
2138 2af4a041 2019-05-11 jcs "pthread_cond_signal");
2141 7c1452c1 2020-03-26 stsp * The mutex will be released while the view loop waits
2142 7c1452c1 2020-03-26 stsp * in wgetch(), at which time the log thread will run.
2144 7c1452c1 2020-03-26 stsp if (!wait)
2147 7c1452c1 2020-03-26 stsp /* Display progress update in log view. */
2148 ffe38506 2020-12-01 naddy show_log_view(view);
2149 7c1452c1 2020-03-26 stsp update_panels();
2150 7c1452c1 2020-03-26 stsp doupdate();
2152 7c1452c1 2020-03-26 stsp /* Wait right here while next commit is being loaded. */
2153 ffe38506 2020-12-01 naddy errcode = pthread_cond_wait(&ta->commit_loaded, &tog_mutex);
2154 82954512 2020-02-03 stsp if (errcode)
2155 82954512 2020-02-03 stsp return got_error_set_errno(errcode,
2156 7c1452c1 2020-03-26 stsp "pthread_cond_wait");
2158 7c1452c1 2020-03-26 stsp /* Display progress update in log view. */
2159 ffe38506 2020-12-01 naddy show_log_view(view);
2160 7c1452c1 2020-03-26 stsp update_panels();
2161 7c1452c1 2020-03-26 stsp doupdate();
2164 5e224a3e 2019-02-22 stsp return NULL;
2167 5e224a3e 2019-02-22 stsp static const struct got_error *
2168 9b058f45 2022-06-30 mark request_log_commits(struct tog_view *view)
2170 9b058f45 2022-06-30 mark struct tog_log_view_state *state = &view->state.log;
2171 9b058f45 2022-06-30 mark const struct got_error *err = NULL;
2173 9b058f45 2022-06-30 mark state->thread_args.commits_needed = view->nscrolled;
2174 9b058f45 2022-06-30 mark err = trigger_log_thread(view, 1);
2175 9b058f45 2022-06-30 mark view->nscrolled = 0;
2177 9b058f45 2022-06-30 mark return err;
2180 9b058f45 2022-06-30 mark static const struct got_error *
2181 ffe38506 2020-12-01 naddy log_scroll_down(struct tog_view *view, int maxscroll)
2183 ffe38506 2020-12-01 naddy struct tog_log_view_state *s = &view->state.log;
2184 5e224a3e 2019-02-22 stsp const struct got_error *err = NULL;
2185 5e224a3e 2019-02-22 stsp struct commit_queue_entry *pentry;
2186 7c1452c1 2020-03-26 stsp int nscrolled = 0, ncommits_needed;
2188 ffe38506 2020-12-01 naddy if (s->last_displayed_entry == NULL)
2189 5e224a3e 2019-02-22 stsp return NULL;
2191 bf30f154 2020-12-07 naddy ncommits_needed = s->last_displayed_entry->idx + 1 + maxscroll;
2192 ffe38506 2020-12-01 naddy if (s->commits.ncommits < ncommits_needed &&
2193 ffe38506 2020-12-01 naddy !s->thread_args.log_complete) {
2195 7c1452c1 2020-03-26 stsp * Ask the log thread for required amount of commits.
2197 ffe38506 2020-12-01 naddy s->thread_args.commits_needed += maxscroll;
2198 ffe38506 2020-12-01 naddy err = trigger_log_thread(view, 1);
2200 5e224a3e 2019-02-22 stsp return err;
2204 ffe38506 2020-12-01 naddy pentry = TAILQ_NEXT(s->last_displayed_entry, entry);
2205 9b058f45 2022-06-30 mark if (pentry == NULL && view->mode != TOG_VIEW_SPLIT_HRZN)
2208 9b058f45 2022-06-30 mark s->last_displayed_entry = pentry ?
2209 9b058f45 2022-06-30 mark pentry : s->last_displayed_entry;;
2211 ffe38506 2020-12-01 naddy pentry = TAILQ_NEXT(s->first_displayed_entry, entry);
2212 dd0a52c1 2018-05-20 stsp if (pentry == NULL)
2214 ffe38506 2020-12-01 naddy s->first_displayed_entry = pentry;
2215 16482c3b 2018-05-20 stsp } while (++nscrolled < maxscroll);
2217 9b058f45 2022-06-30 mark if (view->mode == TOG_VIEW_SPLIT_HRZN)
2218 9b058f45 2022-06-30 mark view->nscrolled += nscrolled;
2220 9b058f45 2022-06-30 mark view->nscrolled = 0;
2222 dd0a52c1 2018-05-20 stsp return err;
2225 cd0acaa7 2018-05-20 stsp static const struct got_error *
2226 9b058f45 2022-06-30 mark open_diff_view_for_commit(struct tog_view **new_view, int begin_y, int begin_x,
2227 fb872ab2 2019-02-21 stsp struct got_commit_object *commit, struct got_object_id *commit_id,
2228 78756c87 2020-11-24 stsp struct tog_view *log_view, struct got_repository *repo)
2230 cd0acaa7 2018-05-20 stsp const struct got_error *err;
2231 9ba79e04 2018-06-11 stsp struct got_object_qid *parent_id;
2232 e5a0f69f 2018-08-18 stsp struct tog_view *diff_view;
2234 9b058f45 2022-06-30 mark diff_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_DIFF);
2235 15a94983 2018-12-23 stsp if (diff_view == NULL)
2236 638f9024 2019-05-13 stsp return got_error_from_errno("view_open");
2238 dbdddfee 2021-06-23 naddy parent_id = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
2239 d7b5a0e8 2022-04-20 stsp err = open_diff_view(diff_view, parent_id ? &parent_id->id : NULL,
2240 78756c87 2020-11-24 stsp commit_id, NULL, NULL, 3, 0, 0, log_view, repo);
2241 e5a0f69f 2018-08-18 stsp if (err == NULL)
2242 e5a0f69f 2018-08-18 stsp *new_view = diff_view;
2243 cd0acaa7 2018-05-20 stsp return err;
2246 80ddbec8 2018-04-29 stsp static const struct got_error *
2247 42a2230c 2020-12-01 naddy tree_view_visit_subtree(struct tog_tree_view_state *s,
2248 42a2230c 2020-12-01 naddy struct got_tree_object *subtree)
2250 941e9f74 2019-05-21 stsp struct tog_parent_tree *parent;
2252 941e9f74 2019-05-21 stsp parent = calloc(1, sizeof(*parent));
2253 941e9f74 2019-05-21 stsp if (parent == NULL)
2254 941e9f74 2019-05-21 stsp return got_error_from_errno("calloc");
2256 941e9f74 2019-05-21 stsp parent->tree = s->tree;
2257 941e9f74 2019-05-21 stsp parent->first_displayed_entry = s->first_displayed_entry;
2258 941e9f74 2019-05-21 stsp parent->selected_entry = s->selected_entry;
2259 941e9f74 2019-05-21 stsp parent->selected = s->selected;
2260 941e9f74 2019-05-21 stsp TAILQ_INSERT_HEAD(&s->parents, parent, entry);
2261 941e9f74 2019-05-21 stsp s->tree = subtree;
2262 941e9f74 2019-05-21 stsp s->selected = 0;
2263 941e9f74 2019-05-21 stsp s->first_displayed_entry = NULL;
2264 941e9f74 2019-05-21 stsp return NULL;
2267 941e9f74 2019-05-21 stsp static const struct got_error *
2268 55cccc34 2020-02-20 stsp tree_view_walk_path(struct tog_tree_view_state *s,
2269 a44927cc 2022-04-07 stsp struct got_commit_object *commit, const char *path)
2271 9343a5fb 2018-06-23 stsp const struct got_error *err = NULL;
2272 55cccc34 2020-02-20 stsp struct got_tree_object *tree = NULL;
2273 941e9f74 2019-05-21 stsp const char *p;
2274 55cccc34 2020-02-20 stsp char *slash, *subpath = NULL;
2276 941e9f74 2019-05-21 stsp /* Walk the path and open corresponding tree objects. */
2278 941e9f74 2019-05-21 stsp while (*p) {
2279 56e0773d 2019-11-28 stsp struct got_tree_entry *te;
2280 941e9f74 2019-05-21 stsp struct got_object_id *tree_id;
2281 56e0773d 2019-11-28 stsp char *te_name;
2283 33cbf02b 2020-01-12 stsp while (p[0] == '/')
2286 941e9f74 2019-05-21 stsp /* Ensure the correct subtree entry is selected. */
2287 941e9f74 2019-05-21 stsp slash = strchr(p, '/');
2288 941e9f74 2019-05-21 stsp if (slash == NULL)
2289 33cbf02b 2020-01-12 stsp te_name = strdup(p);
2291 33cbf02b 2020-01-12 stsp te_name = strndup(p, slash - p);
2292 56e0773d 2019-11-28 stsp if (te_name == NULL) {
2293 56e0773d 2019-11-28 stsp err = got_error_from_errno("strndup");
2296 56e0773d 2019-11-28 stsp te = got_object_tree_find_entry(s->tree, te_name);
2297 56e0773d 2019-11-28 stsp if (te == NULL) {
2298 56e0773d 2019-11-28 stsp err = got_error_path(te_name, GOT_ERR_NO_TREE_ENTRY);
2299 56e0773d 2019-11-28 stsp free(te_name);
2302 56e0773d 2019-11-28 stsp free(te_name);
2303 9a1d5146 2020-11-27 naddy s->first_displayed_entry = s->selected_entry = te;
2305 9a1d5146 2020-11-27 naddy if (!S_ISDIR(got_tree_entry_get_mode(s->selected_entry)))
2306 9a1d5146 2020-11-27 naddy break; /* jump to this file's entry */
2308 941e9f74 2019-05-21 stsp slash = strchr(p, '/');
2309 941e9f74 2019-05-21 stsp if (slash)
2310 941e9f74 2019-05-21 stsp subpath = strndup(path, slash - path);
2312 941e9f74 2019-05-21 stsp subpath = strdup(path);
2313 941e9f74 2019-05-21 stsp if (subpath == NULL) {
2314 941e9f74 2019-05-21 stsp err = got_error_from_errno("strdup");
2318 a44927cc 2022-04-07 stsp err = got_object_id_by_path(&tree_id, s->repo, commit,
2323 d91faf3b 2020-12-01 naddy err = got_object_open_as_tree(&tree, s->repo, tree_id);
2324 941e9f74 2019-05-21 stsp free(tree_id);
2328 42a2230c 2020-12-01 naddy err = tree_view_visit_subtree(s, tree);
2329 941e9f74 2019-05-21 stsp if (err) {
2330 941e9f74 2019-05-21 stsp got_object_tree_close(tree);
2333 941e9f74 2019-05-21 stsp if (slash == NULL)
2335 941e9f74 2019-05-21 stsp free(subpath);
2336 941e9f74 2019-05-21 stsp subpath = NULL;
2337 941e9f74 2019-05-21 stsp p = slash;
2340 941e9f74 2019-05-21 stsp free(subpath);
2341 1a76625f 2018-10-22 stsp return err;
2344 61266923 2020-01-14 stsp static const struct got_error *
2345 49b24ee5 2022-07-03 mark browse_commit_tree(struct tog_view **new_view, int begin_y, int begin_x,
2346 55cccc34 2020-02-20 stsp struct commit_queue_entry *entry, const char *path,
2347 4e97c21c 2020-12-06 stsp const char *head_ref_name, struct got_repository *repo)
2349 55cccc34 2020-02-20 stsp const struct got_error *err = NULL;
2350 55cccc34 2020-02-20 stsp struct tog_tree_view_state *s;
2351 55cccc34 2020-02-20 stsp struct tog_view *tree_view;
2353 49b24ee5 2022-07-03 mark tree_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_TREE);
2354 55cccc34 2020-02-20 stsp if (tree_view == NULL)
2355 55cccc34 2020-02-20 stsp return got_error_from_errno("view_open");
2357 bc573f3b 2021-07-10 stsp err = open_tree_view(tree_view, entry->id, head_ref_name, repo);
2359 55cccc34 2020-02-20 stsp return err;
2360 55cccc34 2020-02-20 stsp s = &tree_view->state.tree;
2362 55cccc34 2020-02-20 stsp *new_view = tree_view;
2364 55cccc34 2020-02-20 stsp if (got_path_is_root_dir(path))
2365 55cccc34 2020-02-20 stsp return NULL;
2367 a44927cc 2022-04-07 stsp return tree_view_walk_path(s, entry->commit, path);
2370 55cccc34 2020-02-20 stsp static const struct got_error *
2371 61266923 2020-01-14 stsp block_signals_used_by_main_thread(void)
2373 61266923 2020-01-14 stsp sigset_t sigset;
2374 61266923 2020-01-14 stsp int errcode;
2376 61266923 2020-01-14 stsp if (sigemptyset(&sigset) == -1)
2377 61266923 2020-01-14 stsp return got_error_from_errno("sigemptyset");
2379 2497f032 2022-05-31 stsp /* tog handles SIGWINCH, SIGCONT, SIGINT, SIGTERM */
2380 61266923 2020-01-14 stsp if (sigaddset(&sigset, SIGWINCH) == -1)
2381 61266923 2020-01-14 stsp return got_error_from_errno("sigaddset");
2382 61266923 2020-01-14 stsp if (sigaddset(&sigset, SIGCONT) == -1)
2383 2497f032 2022-05-31 stsp return got_error_from_errno("sigaddset");
2384 2497f032 2022-05-31 stsp if (sigaddset(&sigset, SIGINT) == -1)
2385 61266923 2020-01-14 stsp return got_error_from_errno("sigaddset");
2386 2497f032 2022-05-31 stsp if (sigaddset(&sigset, SIGTERM) == -1)
2387 2497f032 2022-05-31 stsp return got_error_from_errno("sigaddset");
2389 61266923 2020-01-14 stsp /* ncurses handles SIGTSTP */
2390 61266923 2020-01-14 stsp if (sigaddset(&sigset, SIGTSTP) == -1)
2391 61266923 2020-01-14 stsp return got_error_from_errno("sigaddset");
2393 61266923 2020-01-14 stsp errcode = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
2394 61266923 2020-01-14 stsp if (errcode)
2395 61266923 2020-01-14 stsp return got_error_set_errno(errcode, "pthread_sigmask");
2397 61266923 2020-01-14 stsp return NULL;
2400 1a76625f 2018-10-22 stsp static void *
2401 1a76625f 2018-10-22 stsp log_thread(void *arg)
2403 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
2404 1a76625f 2018-10-22 stsp int errcode = 0;
2405 1a76625f 2018-10-22 stsp struct tog_log_thread_args *a = arg;
2406 1a76625f 2018-10-22 stsp int done = 0;
2408 61266923 2020-01-14 stsp err = block_signals_used_by_main_thread();
2410 61266923 2020-01-14 stsp return (void *)err;
2412 2497f032 2022-05-31 stsp while (!done && !err && !tog_fatal_signal_received()) {
2413 4e0d2870 2020-12-07 naddy err = queue_commits(a);
2414 1a76625f 2018-10-22 stsp if (err) {
2415 1a76625f 2018-10-22 stsp if (err->code != GOT_ERR_ITER_COMPLETED)
2416 1a76625f 2018-10-22 stsp return (void *)err;
2417 1a76625f 2018-10-22 stsp err = NULL;
2419 fb280deb 2021-08-30 stsp } else if (a->commits_needed > 0 && !a->load_all)
2420 1a76625f 2018-10-22 stsp a->commits_needed--;
2422 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
2423 3abe8080 2019-04-10 stsp if (errcode) {
2424 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode,
2425 2af4a041 2019-05-11 jcs "pthread_mutex_lock");
2427 3abe8080 2019-04-10 stsp } else if (*a->quit)
2429 3abe8080 2019-04-10 stsp else if (*a->first_displayed_entry == NULL) {
2430 1a76625f 2018-10-22 stsp *a->first_displayed_entry =
2431 1a76625f 2018-10-22 stsp TAILQ_FIRST(&a->commits->head);
2432 1a76625f 2018-10-22 stsp *a->selected_entry = *a->first_displayed_entry;
2435 7c1452c1 2020-03-26 stsp errcode = pthread_cond_signal(&a->commit_loaded);
2436 7c1452c1 2020-03-26 stsp if (errcode) {
2437 7c1452c1 2020-03-26 stsp err = got_error_set_errno(errcode,
2438 7c1452c1 2020-03-26 stsp "pthread_cond_signal");
2439 7c1452c1 2020-03-26 stsp pthread_mutex_unlock(&tog_mutex);
2444 1a76625f 2018-10-22 stsp a->commits_needed = 0;
2446 fb280deb 2021-08-30 stsp if (a->commits_needed == 0 && !a->load_all) {
2447 7c1452c1 2020-03-26 stsp errcode = pthread_cond_wait(&a->need_commits,
2448 7c1452c1 2020-03-26 stsp &tog_mutex);
2449 7c1452c1 2020-03-26 stsp if (errcode)
2450 7c1452c1 2020-03-26 stsp err = got_error_set_errno(errcode,
2451 7c1452c1 2020-03-26 stsp "pthread_cond_wait");
2452 21355643 2020-12-06 stsp if (*a->quit)
2457 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
2458 1a76625f 2018-10-22 stsp if (errcode && err == NULL)
2459 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode,
2460 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
2462 3abe8080 2019-04-10 stsp a->log_complete = 1;
2463 1a76625f 2018-10-22 stsp return (void *)err;
2466 1a76625f 2018-10-22 stsp static const struct got_error *
2467 1a76625f 2018-10-22 stsp stop_log_thread(struct tog_log_view_state *s)
2469 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
2470 1a76625f 2018-10-22 stsp int errcode;
2472 1a76625f 2018-10-22 stsp if (s->thread) {
2473 1a76625f 2018-10-22 stsp s->quit = 1;
2474 1a76625f 2018-10-22 stsp errcode = pthread_cond_signal(&s->thread_args.need_commits);
2475 1a76625f 2018-10-22 stsp if (errcode)
2476 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
2477 2af4a041 2019-05-11 jcs "pthread_cond_signal");
2478 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
2479 1a76625f 2018-10-22 stsp if (errcode)
2480 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
2481 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
2482 1a76625f 2018-10-22 stsp errcode = pthread_join(s->thread, (void **)&err);
2483 1a76625f 2018-10-22 stsp if (errcode)
2484 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_join");
2485 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
2486 1a76625f 2018-10-22 stsp if (errcode)
2487 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
2488 2af4a041 2019-05-11 jcs "pthread_mutex_lock");
2489 1a76625f 2018-10-22 stsp s->thread = NULL;
2492 1a76625f 2018-10-22 stsp if (s->thread_args.repo) {
2493 1d0f4054 2021-06-17 stsp err = got_repo_close(s->thread_args.repo);
2494 1a76625f 2018-10-22 stsp s->thread_args.repo = NULL;
2497 74467cc8 2022-06-15 stsp if (s->thread_args.pack_fds) {
2498 74467cc8 2022-06-15 stsp const struct got_error *pack_err =
2499 74467cc8 2022-06-15 stsp got_repo_pack_fds_close(s->thread_args.pack_fds);
2500 74467cc8 2022-06-15 stsp if (err == NULL)
2501 74467cc8 2022-06-15 stsp err = pack_err;
2502 74467cc8 2022-06-15 stsp s->thread_args.pack_fds = NULL;
2505 1a76625f 2018-10-22 stsp if (s->thread_args.graph) {
2506 1a76625f 2018-10-22 stsp got_commit_graph_close(s->thread_args.graph);
2507 1a76625f 2018-10-22 stsp s->thread_args.graph = NULL;
2510 9343a5fb 2018-06-23 stsp return err;
2513 9343a5fb 2018-06-23 stsp static const struct got_error *
2514 1a76625f 2018-10-22 stsp close_log_view(struct tog_view *view)
2516 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
2517 1a76625f 2018-10-22 stsp struct tog_log_view_state *s = &view->state.log;
2518 276b94a1 2020-11-13 naddy int errcode;
2520 1a76625f 2018-10-22 stsp err = stop_log_thread(s);
2522 276b94a1 2020-11-13 naddy errcode = pthread_cond_destroy(&s->thread_args.need_commits);
2523 276b94a1 2020-11-13 naddy if (errcode && err == NULL)
2524 276b94a1 2020-11-13 naddy err = got_error_set_errno(errcode, "pthread_cond_destroy");
2526 276b94a1 2020-11-13 naddy errcode = pthread_cond_destroy(&s->thread_args.commit_loaded);
2527 276b94a1 2020-11-13 naddy if (errcode && err == NULL)
2528 276b94a1 2020-11-13 naddy err = got_error_set_errno(errcode, "pthread_cond_destroy");
2530 1a76625f 2018-10-22 stsp free_commits(&s->commits);
2531 1a76625f 2018-10-22 stsp free(s->in_repo_path);
2532 797bc7b9 2018-10-22 stsp s->in_repo_path = NULL;
2533 1a76625f 2018-10-22 stsp free(s->start_id);
2534 797bc7b9 2018-10-22 stsp s->start_id = NULL;
2535 9cd7cbd1 2020-12-07 stsp free(s->head_ref_name);
2536 9cd7cbd1 2020-12-07 stsp s->head_ref_name = NULL;
2537 1a76625f 2018-10-22 stsp return err;
2540 1a76625f 2018-10-22 stsp static const struct got_error *
2541 60493ae3 2019-06-20 stsp search_start_log_view(struct tog_view *view)
2543 60493ae3 2019-06-20 stsp struct tog_log_view_state *s = &view->state.log;
2545 60493ae3 2019-06-20 stsp s->matched_entry = NULL;
2546 96e2b566 2019-07-08 stsp s->search_entry = NULL;
2547 60493ae3 2019-06-20 stsp return NULL;
2550 60493ae3 2019-06-20 stsp static const struct got_error *
2551 60493ae3 2019-06-20 stsp search_next_log_view(struct tog_view *view)
2553 60493ae3 2019-06-20 stsp const struct got_error *err = NULL;
2554 60493ae3 2019-06-20 stsp struct tog_log_view_state *s = &view->state.log;
2555 60493ae3 2019-06-20 stsp struct commit_queue_entry *entry;
2557 f9686aa5 2020-03-27 stsp /* Display progress update in log view. */
2558 f9686aa5 2020-03-27 stsp show_log_view(view);
2559 f9686aa5 2020-03-27 stsp update_panels();
2560 f9686aa5 2020-03-27 stsp doupdate();
2562 96e2b566 2019-07-08 stsp if (s->search_entry) {
2563 13add988 2019-10-15 stsp int errcode, ch;
2564 13add988 2019-10-15 stsp errcode = pthread_mutex_unlock(&tog_mutex);
2565 13add988 2019-10-15 stsp if (errcode)
2566 13add988 2019-10-15 stsp return got_error_set_errno(errcode,
2567 13add988 2019-10-15 stsp "pthread_mutex_unlock");
2568 13add988 2019-10-15 stsp ch = wgetch(view->window);
2569 13add988 2019-10-15 stsp errcode = pthread_mutex_lock(&tog_mutex);
2570 13add988 2019-10-15 stsp if (errcode)
2571 13add988 2019-10-15 stsp return got_error_set_errno(errcode,
2572 13add988 2019-10-15 stsp "pthread_mutex_lock");
2573 a6d37fac 2022-07-03 mark if (ch == CTRL('g') || ch == KEY_BACKSPACE) {
2574 8f4ed634 2020-03-26 stsp view->search_next_done = TOG_SEARCH_HAVE_MORE;
2575 678cbce5 2019-07-28 stsp return NULL;
2577 96e2b566 2019-07-08 stsp if (view->searching == TOG_SEARCH_FORWARD)
2578 96e2b566 2019-07-08 stsp entry = TAILQ_NEXT(s->search_entry, entry);
2580 96e2b566 2019-07-08 stsp entry = TAILQ_PREV(s->search_entry,
2581 96e2b566 2019-07-08 stsp commit_queue_head, entry);
2582 96e2b566 2019-07-08 stsp } else if (s->matched_entry) {
2583 364ac6fd 2022-06-18 stsp int matched_idx = s->matched_entry->idx;
2584 364ac6fd 2022-06-18 stsp int selected_idx = s->selected_entry->idx;
2587 f704b35c 2022-06-18 stsp * If the user has moved the cursor after we hit a match,
2588 f704b35c 2022-06-18 stsp * the position from where we should continue searching
2589 f704b35c 2022-06-18 stsp * might have changed.
2591 4bfe9f0a 2022-06-18 stsp if (view->searching == TOG_SEARCH_FORWARD) {
2592 364ac6fd 2022-06-18 stsp if (matched_idx > selected_idx)
2593 364ac6fd 2022-06-18 stsp entry = TAILQ_NEXT(s->selected_entry, entry);
2595 364ac6fd 2022-06-18 stsp entry = TAILQ_NEXT(s->matched_entry, entry);
2597 364ac6fd 2022-06-18 stsp if (matched_idx < selected_idx)
2598 364ac6fd 2022-06-18 stsp entry = TAILQ_PREV(s->selected_entry,
2599 364ac6fd 2022-06-18 stsp commit_queue_head, entry);
2601 364ac6fd 2022-06-18 stsp entry = TAILQ_PREV(s->matched_entry,
2602 364ac6fd 2022-06-18 stsp commit_queue_head, entry);
2605 5a5ede53 2021-12-09 stsp entry = s->selected_entry;
2608 60493ae3 2019-06-20 stsp while (1) {
2609 13add988 2019-10-15 stsp int have_match = 0;
2611 60493ae3 2019-06-20 stsp if (entry == NULL) {
2612 f801134a 2019-06-25 stsp if (s->thread_args.log_complete ||
2613 f801134a 2019-06-25 stsp view->searching == TOG_SEARCH_BACKWARD) {
2614 f9967bca 2020-03-27 stsp view->search_next_done =
2615 f9967bca 2020-03-27 stsp (s->matched_entry == NULL ?
2616 f9967bca 2020-03-27 stsp TOG_SEARCH_HAVE_NONE : TOG_SEARCH_NO_MORE);
2617 8f4ed634 2020-03-26 stsp s->search_entry = NULL;
2618 f801134a 2019-06-25 stsp return NULL;
2621 96e2b566 2019-07-08 stsp * Poke the log thread for more commits and return,
2622 96e2b566 2019-07-08 stsp * allowing the main loop to make progress. Search
2623 96e2b566 2019-07-08 stsp * will resume at s->search_entry once we come back.
2625 57b33b64 2019-07-08 stsp s->thread_args.commits_needed++;
2626 ffe38506 2020-12-01 naddy return trigger_log_thread(view, 0);
2629 13add988 2019-10-15 stsp err = match_commit(&have_match, entry->id, entry->commit,
2630 13add988 2019-10-15 stsp &view->regex);
2633 13add988 2019-10-15 stsp if (have_match) {
2634 8f4ed634 2020-03-26 stsp view->search_next_done = TOG_SEARCH_HAVE_MORE;
2635 bcf2df4d 2019-06-21 stsp s->matched_entry = entry;
2639 96e2b566 2019-07-08 stsp s->search_entry = entry;
2640 b1bf1435 2019-06-21 stsp if (view->searching == TOG_SEARCH_FORWARD)
2641 b1bf1435 2019-06-21 stsp entry = TAILQ_NEXT(entry, entry);
2643 b1bf1435 2019-06-21 stsp entry = TAILQ_PREV(entry, commit_queue_head, entry);
2646 bcf2df4d 2019-06-21 stsp if (s->matched_entry) {
2647 ead14cbe 2019-06-21 stsp int cur = s->selected_entry->idx;
2648 ead14cbe 2019-06-21 stsp while (cur < s->matched_entry->idx) {
2649 e78dc838 2020-12-04 stsp err = input_log_view(NULL, view, KEY_DOWN);
2651 60493ae3 2019-06-20 stsp return err;
2654 ead14cbe 2019-06-21 stsp while (cur > s->matched_entry->idx) {
2655 e78dc838 2020-12-04 stsp err = input_log_view(NULL, view, KEY_UP);
2657 60493ae3 2019-06-20 stsp return err;
2662 96e2b566 2019-07-08 stsp s->search_entry = NULL;
2664 60493ae3 2019-06-20 stsp return NULL;
2667 60493ae3 2019-06-20 stsp static const struct got_error *
2668 ba4f502b 2018-08-04 stsp open_log_view(struct tog_view *view, struct got_object_id *start_id,
2669 78756c87 2020-11-24 stsp struct got_repository *repo, const char *head_ref_name,
2670 78756c87 2020-11-24 stsp const char *in_repo_path, int log_branches)
2672 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
2673 fb2756b9 2018-08-04 stsp struct tog_log_view_state *s = &view->state.log;
2674 1a76625f 2018-10-22 stsp struct got_repository *thread_repo = NULL;
2675 1a76625f 2018-10-22 stsp struct got_commit_graph *thread_graph = NULL;
2676 1a76625f 2018-10-22 stsp int errcode;
2678 f135c941 2020-02-20 stsp if (in_repo_path != s->in_repo_path) {
2679 f135c941 2020-02-20 stsp free(s->in_repo_path);
2680 f135c941 2020-02-20 stsp s->in_repo_path = strdup(in_repo_path);
2681 f135c941 2020-02-20 stsp if (s->in_repo_path == NULL)
2682 f135c941 2020-02-20 stsp return got_error_from_errno("strdup");
2685 93e45b7c 2018-09-24 stsp /* The commit queue only contains commits being displayed. */
2686 fb2756b9 2018-08-04 stsp TAILQ_INIT(&s->commits.head);
2687 fb2756b9 2018-08-04 stsp s->commits.ncommits = 0;
2689 fb2756b9 2018-08-04 stsp s->repo = repo;
2690 9cd7cbd1 2020-12-07 stsp if (head_ref_name) {
2691 9cd7cbd1 2020-12-07 stsp s->head_ref_name = strdup(head_ref_name);
2692 9cd7cbd1 2020-12-07 stsp if (s->head_ref_name == NULL) {
2693 9cd7cbd1 2020-12-07 stsp err = got_error_from_errno("strdup");
2694 9cd7cbd1 2020-12-07 stsp goto done;
2697 5036bf37 2018-09-24 stsp s->start_id = got_object_id_dup(start_id);
2698 5036bf37 2018-09-24 stsp if (s->start_id == NULL) {
2699 638f9024 2019-05-13 stsp err = got_error_from_errno("got_object_id_dup");
2700 5036bf37 2018-09-24 stsp goto done;
2702 b672a97a 2020-01-27 stsp s->log_branches = log_branches;
2704 dbdddfee 2021-06-23 naddy STAILQ_INIT(&s->colors);
2705 11b20872 2019-11-08 stsp if (has_colors() && getenv("TOG_COLORS") != NULL) {
2706 11b20872 2019-11-08 stsp err = add_color(&s->colors, "^$", TOG_COLOR_COMMIT,
2707 11b20872 2019-11-08 stsp get_color_value("TOG_COLOR_COMMIT"));
2709 11b20872 2019-11-08 stsp goto done;
2710 11b20872 2019-11-08 stsp err = add_color(&s->colors, "^$", TOG_COLOR_AUTHOR,
2711 11b20872 2019-11-08 stsp get_color_value("TOG_COLOR_AUTHOR"));
2712 11b20872 2019-11-08 stsp if (err) {
2713 11b20872 2019-11-08 stsp free_colors(&s->colors);
2714 11b20872 2019-11-08 stsp goto done;
2716 11b20872 2019-11-08 stsp err = add_color(&s->colors, "^$", TOG_COLOR_DATE,
2717 11b20872 2019-11-08 stsp get_color_value("TOG_COLOR_DATE"));
2718 11b20872 2019-11-08 stsp if (err) {
2719 11b20872 2019-11-08 stsp free_colors(&s->colors);
2720 11b20872 2019-11-08 stsp goto done;
2724 e5a0f69f 2018-08-18 stsp view->show = show_log_view;
2725 e5a0f69f 2018-08-18 stsp view->input = input_log_view;
2726 e5a0f69f 2018-08-18 stsp view->close = close_log_view;
2727 60493ae3 2019-06-20 stsp view->search_start = search_start_log_view;
2728 60493ae3 2019-06-20 stsp view->search_next = search_next_log_view;
2730 74467cc8 2022-06-15 stsp if (s->thread_args.pack_fds == NULL) {
2731 74467cc8 2022-06-15 stsp err = got_repo_pack_fds_open(&s->thread_args.pack_fds);
2733 74467cc8 2022-06-15 stsp goto done;
2735 0ae84acc 2022-06-15 tracey err = got_repo_open(&thread_repo, got_repo_get_path(repo), NULL,
2736 74467cc8 2022-06-15 stsp s->thread_args.pack_fds);
2737 0ae84acc 2022-06-15 tracey if (err)
2738 0ae84acc 2022-06-15 tracey goto done;
2739 b672a97a 2020-01-27 stsp err = got_commit_graph_open(&thread_graph, s->in_repo_path,
2740 b672a97a 2020-01-27 stsp !s->log_branches);
2742 1a76625f 2018-10-22 stsp goto done;
2743 62d463ca 2020-10-20 naddy err = got_commit_graph_iter_start(thread_graph, s->start_id,
2744 62d463ca 2020-10-20 naddy s->repo, NULL, NULL);
2746 c5b78334 2020-01-12 stsp goto done;
2748 1a76625f 2018-10-22 stsp errcode = pthread_cond_init(&s->thread_args.need_commits, NULL);
2749 1a76625f 2018-10-22 stsp if (errcode) {
2750 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode, "pthread_cond_init");
2751 1a76625f 2018-10-22 stsp goto done;
2753 7c1452c1 2020-03-26 stsp errcode = pthread_cond_init(&s->thread_args.commit_loaded, NULL);
2754 7c1452c1 2020-03-26 stsp if (errcode) {
2755 7c1452c1 2020-03-26 stsp err = got_error_set_errno(errcode, "pthread_cond_init");
2756 7c1452c1 2020-03-26 stsp goto done;
2759 1a76625f 2018-10-22 stsp s->thread_args.commits_needed = view->nlines;
2760 1a76625f 2018-10-22 stsp s->thread_args.graph = thread_graph;
2761 1a76625f 2018-10-22 stsp s->thread_args.commits = &s->commits;
2762 1a76625f 2018-10-22 stsp s->thread_args.in_repo_path = s->in_repo_path;
2763 1a76625f 2018-10-22 stsp s->thread_args.start_id = s->start_id;
2764 1a76625f 2018-10-22 stsp s->thread_args.repo = thread_repo;
2765 1a76625f 2018-10-22 stsp s->thread_args.log_complete = 0;
2766 1a76625f 2018-10-22 stsp s->thread_args.quit = &s->quit;
2767 1a76625f 2018-10-22 stsp s->thread_args.first_displayed_entry = &s->first_displayed_entry;
2768 1a76625f 2018-10-22 stsp s->thread_args.selected_entry = &s->selected_entry;
2769 13add988 2019-10-15 stsp s->thread_args.searching = &view->searching;
2770 13add988 2019-10-15 stsp s->thread_args.search_next_done = &view->search_next_done;
2771 13add988 2019-10-15 stsp s->thread_args.regex = &view->regex;
2774 1a76625f 2018-10-22 stsp close_log_view(view);
2775 ba4f502b 2018-08-04 stsp return err;
2778 e5a0f69f 2018-08-18 stsp static const struct got_error *
2779 ba4f502b 2018-08-04 stsp show_log_view(struct tog_view *view)
2781 f2f6d207 2020-11-24 stsp const struct got_error *err;
2782 fb2756b9 2018-08-04 stsp struct tog_log_view_state *s = &view->state.log;
2784 2b380cc8 2018-10-24 stsp if (s->thread == NULL) {
2785 2b380cc8 2018-10-24 stsp int errcode = pthread_create(&s->thread, NULL, log_thread,
2786 2b380cc8 2018-10-24 stsp &s->thread_args);
2787 2b380cc8 2018-10-24 stsp if (errcode)
2788 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_create");
2789 f2f6d207 2020-11-24 stsp if (s->thread_args.commits_needed > 0) {
2790 ffe38506 2020-12-01 naddy err = trigger_log_thread(view, 1);
2792 f2f6d207 2020-11-24 stsp return err;
2796 8fdc79fe 2020-12-01 naddy return draw_commits(view);
2799 b880cc75 2022-06-30 mark static void
2800 b880cc75 2022-06-30 mark log_move_cursor_up(struct tog_view *view, int page, int home)
2802 b880cc75 2022-06-30 mark struct tog_log_view_state *s = &view->state.log;
2804 b880cc75 2022-06-30 mark if (s->selected_entry->idx == 0)
2805 b880cc75 2022-06-30 mark view->count = 0;
2806 b880cc75 2022-06-30 mark if (s->first_displayed_entry == NULL)
2809 b880cc75 2022-06-30 mark if ((page && TAILQ_FIRST(&s->commits.head) == s->first_displayed_entry)
2811 b880cc75 2022-06-30 mark s->selected = home ? 0 : MAX(0, s->selected - page - 1);
2813 b880cc75 2022-06-30 mark if (!page && !home && s->selected > 0)
2814 b880cc75 2022-06-30 mark --s->selected;
2816 b880cc75 2022-06-30 mark log_scroll_up(s, home ? s->commits.ncommits : MAX(page, 1));
2818 b880cc75 2022-06-30 mark select_commit(s);
2822 b880cc75 2022-06-30 mark static const struct got_error *
2823 b880cc75 2022-06-30 mark log_move_cursor_down(struct tog_view *view, int page)
2825 b880cc75 2022-06-30 mark struct tog_log_view_state *s = &view->state.log;
2826 b880cc75 2022-06-30 mark struct commit_queue_entry *first;
2827 b880cc75 2022-06-30 mark const struct got_error *err = NULL;
2829 b880cc75 2022-06-30 mark first = s->first_displayed_entry;
2830 b880cc75 2022-06-30 mark if (first == NULL) {
2831 b880cc75 2022-06-30 mark view->count = 0;
2832 b880cc75 2022-06-30 mark return NULL;
2835 b880cc75 2022-06-30 mark if (s->thread_args.log_complete &&
2836 b880cc75 2022-06-30 mark s->selected_entry->idx >= s->commits.ncommits - 1)
2837 b880cc75 2022-06-30 mark return NULL;
2839 b880cc75 2022-06-30 mark if (!page) {
2840 b880cc75 2022-06-30 mark int eos = view->nlines - 2;
2842 49b24ee5 2022-07-03 mark if (view_is_hsplit_top(view))
2843 9b058f45 2022-06-30 mark --eos; /* border consumes the last line */
2844 b880cc75 2022-06-30 mark if (s->selected < MIN(eos, s->commits.ncommits - 1))
2845 b880cc75 2022-06-30 mark ++s->selected;
2847 b880cc75 2022-06-30 mark err = log_scroll_down(view, 1);
2848 0dca135e 2022-06-30 mark } else if (s->thread_args.load_all) {
2849 b880cc75 2022-06-30 mark if (s->last_displayed_entry->idx == s->commits.ncommits - 1)
2850 b880cc75 2022-06-30 mark s->selected += MIN(s->last_displayed_entry->idx -
2851 b880cc75 2022-06-30 mark s->selected_entry->idx, page + 1);
2853 b880cc75 2022-06-30 mark err = log_scroll_down(view, MIN(page,
2854 b880cc75 2022-06-30 mark s->commits.ncommits - s->selected_entry->idx - 1));
2855 b880cc75 2022-06-30 mark s->selected = MIN(view->nlines - 2, s->commits.ncommits - 1);
2857 b880cc75 2022-06-30 mark err = log_scroll_down(view, page);
2859 b880cc75 2022-06-30 mark return err;
2860 b880cc75 2022-06-30 mark if (first == s->first_displayed_entry && s->selected <
2861 b880cc75 2022-06-30 mark MIN(view->nlines - 2, s->commits.ncommits - 1)) {
2862 b880cc75 2022-06-30 mark s->selected = MIN(s->commits.ncommits - 1, page);
2866 b880cc75 2022-06-30 mark return err;
2869 9b058f45 2022-06-30 mark * We might necessarily overshoot in horizontal
2870 9b058f45 2022-06-30 mark * splits; if so, select the last displayed commit.
2872 9b058f45 2022-06-30 mark s->selected = MIN(s->selected,
2873 9b058f45 2022-06-30 mark s->last_displayed_entry->idx - s->first_displayed_entry->idx);
2875 b880cc75 2022-06-30 mark select_commit(s);
2877 b880cc75 2022-06-30 mark if (s->thread_args.log_complete &&
2878 b880cc75 2022-06-30 mark s->selected_entry->idx == s->commits.ncommits - 1)
2879 b880cc75 2022-06-30 mark view->count = 0;
2881 b880cc75 2022-06-30 mark return NULL;
2885 9b058f45 2022-06-30 mark * Get splitscreen dimensions based on TOG_VIEW_SPLIT_MODE:
2886 9b058f45 2022-06-30 mark * TOG_VIEW_SPLIT_VERT vertical split if COLS > 119 (default)
2887 9b058f45 2022-06-30 mark * TOG_VIEW_SPLIT_HRZN horizontal split
2888 9b058f45 2022-06-30 mark * Assign start column and line of the new split to *x and *y, respectively,
2889 9b058f45 2022-06-30 mark * and assign view mode to view->mode.
2891 9b058f45 2022-06-30 mark static void
2892 9b058f45 2022-06-30 mark view_get_split(struct tog_view *view, int *y, int *x)
2894 9b058f45 2022-06-30 mark char *mode;
2899 9b058f45 2022-06-30 mark mode = getenv("TOG_VIEW_SPLIT_MODE");
2901 9b058f45 2022-06-30 mark if (!mode || mode[0] != 'h') {
2902 9b058f45 2022-06-30 mark view->mode = TOG_VIEW_SPLIT_VERT;
2903 9b058f45 2022-06-30 mark *x = view_split_begin_x(view->begin_x);
2904 9b058f45 2022-06-30 mark } else if (mode && mode[0] == 'h') {
2905 9b058f45 2022-06-30 mark view->mode = TOG_VIEW_SPLIT_HRZN;
2906 9b058f45 2022-06-30 mark *y = view_split_begin_y(view->lines);
2910 9b058f45 2022-06-30 mark /* Split view horizontally at y and offset view->state->selected line. */
2911 e5a0f69f 2018-08-18 stsp static const struct got_error *
2912 9b058f45 2022-06-30 mark view_init_hsplit(struct tog_view *view, int y)
2914 9b058f45 2022-06-30 mark const struct got_error *err = NULL;
2916 9b058f45 2022-06-30 mark view->nlines = y;
2917 9b058f45 2022-06-30 mark err = view_resize(view);
2919 9b058f45 2022-06-30 mark return err;
2921 9b058f45 2022-06-30 mark err = offset_selection_down(view);
2923 9b058f45 2022-06-30 mark return err;
2926 9b058f45 2022-06-30 mark static const struct got_error *
2927 e78dc838 2020-12-04 stsp input_log_view(struct tog_view **new_view, struct tog_view *view, int ch)
2929 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
2930 e5a0f69f 2018-08-18 stsp struct tog_log_view_state *s = &view->state.log;
2931 21355643 2020-12-06 stsp struct tog_view *diff_view = NULL, *tree_view = NULL;
2932 6458efa5 2020-11-24 stsp struct tog_view *ref_view = NULL;
2933 f3bc9f1d 2021-09-05 naddy struct commit_queue_entry *entry;
2934 0dca135e 2022-06-30 mark int begin_x = 0, begin_y = 0, eos, n, nscroll;
2936 528dedf3 2021-08-30 stsp if (s->thread_args.load_all) {
2937 a6d37fac 2022-07-03 mark if (ch == CTRL('g') || ch == KEY_BACKSPACE)
2938 fb280deb 2021-08-30 stsp s->thread_args.load_all = 0;
2939 528dedf3 2021-08-30 stsp else if (s->thread_args.log_complete) {
2940 b880cc75 2022-06-30 mark err = log_move_cursor_down(view, s->commits.ncommits);
2941 0dca135e 2022-06-30 mark s->thread_args.load_all = 0;
2943 b880cc75 2022-06-30 mark return err;
2946 0dca135e 2022-06-30 mark eos = nscroll = view->nlines - 1;
2947 49b24ee5 2022-07-03 mark if (view_is_hsplit_top(view))
2948 0dca135e 2022-06-30 mark --eos; /* border */
2950 528dedf3 2021-08-30 stsp switch (ch) {
2952 1e37a5c2 2019-05-12 jcs s->quit = 1;
2955 145b6838 2022-06-16 stsp view->x = 0;
2958 145b6838 2022-06-16 stsp view->x = MAX(view->maxx - view->ncols / 2, 0);
2959 640cd7ff 2022-06-22 mark view->count = 0;
2961 145b6838 2022-06-16 stsp case KEY_RIGHT:
2963 145b6838 2022-06-16 stsp if (view->x + view->ncols / 2 < view->maxx)
2964 145b6838 2022-06-16 stsp view->x += 2; /* move two columns right */
2966 640cd7ff 2022-06-22 mark view->count = 0;
2968 145b6838 2022-06-16 stsp case KEY_LEFT:
2970 145b6838 2022-06-16 stsp view->x -= MIN(view->x, 2); /* move two columns back */
2971 640cd7ff 2022-06-22 mark if (view->x <= 0)
2972 640cd7ff 2022-06-22 mark view->count = 0;
2975 1e37a5c2 2019-05-12 jcs case KEY_UP:
2978 02ffd0d5 2021-10-17 stsp case CTRL('p'):
2979 b880cc75 2022-06-30 mark log_move_cursor_up(view, 0, 0);
2982 912a3f79 2021-08-30 j case KEY_HOME:
2983 b880cc75 2022-06-30 mark log_move_cursor_up(view, 0, 1);
2984 640cd7ff 2022-06-22 mark view->count = 0;
2986 83cc4199 2022-06-13 stsp case CTRL('u'):
2988 83cc4199 2022-06-13 stsp nscroll /= 2;
2989 83cc4199 2022-06-13 stsp /* FALL THROUGH */
2990 1e37a5c2 2019-05-12 jcs case KEY_PPAGE:
2991 a4292ac5 2019-05-12 jcs case CTRL('b'):
2993 b880cc75 2022-06-30 mark log_move_cursor_up(view, nscroll, 0);
2996 1e37a5c2 2019-05-12 jcs case KEY_DOWN:
2999 02ffd0d5 2021-10-17 stsp case CTRL('n'):
3000 b880cc75 2022-06-30 mark err = log_move_cursor_down(view, 0);
3003 912a3f79 2021-08-30 j case KEY_END: {
3004 912a3f79 2021-08-30 j /* We don't know yet how many commits, so we're forced to
3005 912a3f79 2021-08-30 j * traverse them all. */
3006 640cd7ff 2022-06-22 mark view->count = 0;
3007 fb280deb 2021-08-30 stsp if (!s->thread_args.log_complete) {
3008 fb280deb 2021-08-30 stsp s->thread_args.load_all = 1;
3009 fb280deb 2021-08-30 stsp return trigger_log_thread(view, 0);
3012 f3bc9f1d 2021-09-05 naddy s->selected = 0;
3013 f3bc9f1d 2021-09-05 naddy entry = TAILQ_LAST(&s->commits.head, commit_queue_head);
3014 0dca135e 2022-06-30 mark for (n = 0; n < eos; n++) {
3015 f3bc9f1d 2021-09-05 naddy if (entry == NULL)
3017 f3bc9f1d 2021-09-05 naddy s->first_displayed_entry = entry;
3018 f3bc9f1d 2021-09-05 naddy entry = TAILQ_PREV(entry, commit_queue_head, entry);
3020 f3bc9f1d 2021-09-05 naddy if (n > 0)
3021 f3bc9f1d 2021-09-05 naddy s->selected = n - 1;
3022 2b779855 2020-12-05 naddy select_commit(s);
3025 80b7e8da 2022-06-11 stsp case CTRL('d'):
3027 83cc4199 2022-06-13 stsp nscroll /= 2;
3028 83cc4199 2022-06-13 stsp /* FALL THROUGH */
3029 83cc4199 2022-06-13 stsp case KEY_NPAGE:
3030 61417565 2022-06-20 mark case CTRL('f'):
3031 48bb96f0 2022-06-20 naddy case 'f':
3033 b880cc75 2022-06-30 mark err = log_move_cursor_down(view, nscroll);
3035 1e37a5c2 2019-05-12 jcs case KEY_RESIZE:
3036 1e37a5c2 2019-05-12 jcs if (s->selected > view->nlines - 2)
3037 1e37a5c2 2019-05-12 jcs s->selected = view->nlines - 2;
3038 1e37a5c2 2019-05-12 jcs if (s->selected > s->commits.ncommits - 1)
3039 1e37a5c2 2019-05-12 jcs s->selected = s->commits.ncommits - 1;
3040 2b779855 2020-12-05 naddy select_commit(s);
3041 0bf7f153 2020-12-02 naddy if (s->commits.ncommits < view->nlines - 1 &&
3042 0bf7f153 2020-12-02 naddy !s->thread_args.log_complete) {
3043 0bf7f153 2020-12-02 naddy s->thread_args.commits_needed += (view->nlines - 1) -
3044 0bf7f153 2020-12-02 naddy s->commits.ncommits;
3045 0bf7f153 2020-12-02 naddy err = trigger_log_thread(view, 1);
3048 1e37a5c2 2019-05-12 jcs case KEY_ENTER:
3049 49b24ee5 2022-07-03 mark case '\r':
3050 640cd7ff 2022-06-22 mark view->count = 0;
3051 1e37a5c2 2019-05-12 jcs if (s->selected_entry == NULL)
3054 9b058f45 2022-06-30 mark /* get dimensions--don't split till initialisation succeeds */
3055 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view))
3056 9b058f45 2022-06-30 mark view_get_split(view, &begin_y, &begin_x);
3058 9b058f45 2022-06-30 mark err = open_diff_view_for_commit(&diff_view, begin_y, begin_x,
3059 1e37a5c2 2019-05-12 jcs s->selected_entry->commit, s->selected_entry->id,
3060 78756c87 2020-11-24 stsp view, s->repo);
3064 49b24ee5 2022-07-03 mark if (view_is_parent_view(view) &&
3065 49b24ee5 2022-07-03 mark view->mode == TOG_VIEW_SPLIT_HRZN) { /* safe to split */
3066 9b058f45 2022-06-30 mark err = view_init_hsplit(view, begin_y);
3071 e78dc838 2020-12-04 stsp view->focussed = 0;
3072 e78dc838 2020-12-04 stsp diff_view->focussed = 1;
3073 9b058f45 2022-06-30 mark diff_view->mode = view->mode;
3074 9b058f45 2022-06-30 mark diff_view->nlines = view->lines - begin_y;
3076 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view)) {
3077 1e37a5c2 2019-05-12 jcs err = view_close_child(view);
3079 1e37a5c2 2019-05-12 jcs return err;
3080 0dbbbe90 2022-06-17 op err = view_set_child(view, diff_view);
3083 e78dc838 2020-12-04 stsp view->focus_child = 1;
3085 1e37a5c2 2019-05-12 jcs *new_view = diff_view;
3088 640cd7ff 2022-06-22 mark view->count = 0;
3089 1e37a5c2 2019-05-12 jcs if (s->selected_entry == NULL)
3090