Blame


1 9f7d7167 2018-04-29 stsp /*
2 5d56da81 2019-01-13 stsp * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
3 9f7d7167 2018-04-29 stsp *
4 9f7d7167 2018-04-29 stsp * Permission to use, copy, modify, and distribute this software for any
5 9f7d7167 2018-04-29 stsp * purpose with or without fee is hereby granted, provided that the above
6 9f7d7167 2018-04-29 stsp * copyright notice and this permission notice appear in all copies.
7 9f7d7167 2018-04-29 stsp *
8 9f7d7167 2018-04-29 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 9f7d7167 2018-04-29 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 9f7d7167 2018-04-29 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 9f7d7167 2018-04-29 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 9f7d7167 2018-04-29 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 9f7d7167 2018-04-29 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 9f7d7167 2018-04-29 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 9f7d7167 2018-04-29 stsp */
16 9f7d7167 2018-04-29 stsp
17 80ddbec8 2018-04-29 stsp #include <sys/queue.h>
18 ffd1d5e5 2018-06-23 stsp #include <sys/stat.h>
19 25791caa 2018-10-24 stsp #include <sys/ioctl.h>
20 80ddbec8 2018-04-29 stsp
21 31120ada 2018-04-30 stsp #include <errno.h>
22 61e69b96 2018-05-20 stsp #define _XOPEN_SOURCE_EXTENDED
23 9f7d7167 2018-04-29 stsp #include <curses.h>
24 61e69b96 2018-05-20 stsp #undef _XOPEN_SOURCE_EXTENDED
25 9f7d7167 2018-04-29 stsp #include <panel.h>
26 9f7d7167 2018-04-29 stsp #include <locale.h>
27 9f7d7167 2018-04-29 stsp #include <stdlib.h>
28 26ed57b2 2018-05-19 stsp #include <stdio.h>
29 9f7d7167 2018-04-29 stsp #include <getopt.h>
30 9f7d7167 2018-04-29 stsp #include <string.h>
31 9f7d7167 2018-04-29 stsp #include <err.h>
32 80ddbec8 2018-04-29 stsp #include <unistd.h>
33 26ed57b2 2018-05-19 stsp #include <util.h>
34 26ed57b2 2018-05-19 stsp #include <limits.h>
35 61e69b96 2018-05-20 stsp #include <wchar.h>
36 788c352e 2018-06-16 stsp #include <time.h>
37 84451b3e 2018-07-10 stsp #include <pthread.h>
38 5036bf37 2018-09-24 stsp #include <libgen.h>
39 60493ae3 2019-06-20 stsp #include <regex.h>
40 9f7d7167 2018-04-29 stsp
41 53ccebc2 2019-07-30 stsp #include "got_version.h"
42 9f7d7167 2018-04-29 stsp #include "got_error.h"
43 80ddbec8 2018-04-29 stsp #include "got_object.h"
44 80ddbec8 2018-04-29 stsp #include "got_reference.h"
45 80ddbec8 2018-04-29 stsp #include "got_repository.h"
46 80ddbec8 2018-04-29 stsp #include "got_diff.h"
47 511a516b 2018-05-19 stsp #include "got_opentemp.h"
48 9ba79e04 2018-06-11 stsp #include "got_commit_graph.h"
49 00dfcb92 2018-06-11 stsp #include "got_utf8.h"
50 a70480e0 2018-06-23 stsp #include "got_blame.h"
51 c2db6724 2019-01-04 stsp #include "got_privsep.h"
52 1dd54920 2019-05-11 stsp #include "got_path.h"
53 b7165be3 2019-02-05 stsp #include "got_worktree.h"
54 9f7d7167 2018-04-29 stsp
55 881b2d3e 2018-04-30 stsp #ifndef MIN
56 881b2d3e 2018-04-30 stsp #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
57 881b2d3e 2018-04-30 stsp #endif
58 881b2d3e 2018-04-30 stsp
59 2bd27830 2018-10-22 stsp #ifndef MAX
60 2bd27830 2018-10-22 stsp #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b))
61 2bd27830 2018-10-22 stsp #endif
62 2bd27830 2018-10-22 stsp
63 a4292ac5 2019-05-12 jcs #define CTRL(x) ((x) & 0x1f)
64 2bd27830 2018-10-22 stsp
65 9f7d7167 2018-04-29 stsp #ifndef nitems
66 9f7d7167 2018-04-29 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
67 9f7d7167 2018-04-29 stsp #endif
68 9f7d7167 2018-04-29 stsp
69 9f7d7167 2018-04-29 stsp struct tog_cmd {
70 c2301be8 2018-04-30 stsp const char *name;
71 9f7d7167 2018-04-29 stsp const struct got_error *(*cmd_main)(int, char *[]);
72 9f7d7167 2018-04-29 stsp void (*cmd_usage)(void);
73 9f7d7167 2018-04-29 stsp };
74 9f7d7167 2018-04-29 stsp
75 ce5b7c56 2019-07-09 stsp __dead static void usage(int);
76 4ed7e80c 2018-05-20 stsp __dead static void usage_log(void);
77 4ed7e80c 2018-05-20 stsp __dead static void usage_diff(void);
78 4ed7e80c 2018-05-20 stsp __dead static void usage_blame(void);
79 ffd1d5e5 2018-06-23 stsp __dead static void usage_tree(void);
80 9f7d7167 2018-04-29 stsp
81 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_log(int, char *[]);
82 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_diff(int, char *[]);
83 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_blame(int, char *[]);
84 ffd1d5e5 2018-06-23 stsp static const struct got_error* cmd_tree(int, char *[]);
85 9f7d7167 2018-04-29 stsp
86 4ed7e80c 2018-05-20 stsp static struct tog_cmd tog_commands[] = {
87 5e070240 2019-06-22 stsp { "log", cmd_log, usage_log },
88 5e070240 2019-06-22 stsp { "diff", cmd_diff, usage_diff },
89 5e070240 2019-06-22 stsp { "blame", cmd_blame, usage_blame },
90 5e070240 2019-06-22 stsp { "tree", cmd_tree, usage_tree },
91 9f7d7167 2018-04-29 stsp };
92 9f7d7167 2018-04-29 stsp
93 d6b05b5b 2018-08-04 stsp enum tog_view_type {
94 d6b05b5b 2018-08-04 stsp TOG_VIEW_DIFF,
95 d6b05b5b 2018-08-04 stsp TOG_VIEW_LOG,
96 ad80ab7b 2018-08-04 stsp TOG_VIEW_BLAME,
97 ad80ab7b 2018-08-04 stsp TOG_VIEW_TREE
98 d6b05b5b 2018-08-04 stsp };
99 c3e9aa98 2019-05-13 jcs
100 c3e9aa98 2019-05-13 jcs #define TOG_EOF_STRING "(END)"
101 d6b05b5b 2018-08-04 stsp
102 ba4f502b 2018-08-04 stsp struct commit_queue_entry {
103 ba4f502b 2018-08-04 stsp TAILQ_ENTRY(commit_queue_entry) entry;
104 ba4f502b 2018-08-04 stsp struct got_object_id *id;
105 ba4f502b 2018-08-04 stsp struct got_commit_object *commit;
106 1a76625f 2018-10-22 stsp int idx;
107 ba4f502b 2018-08-04 stsp };
108 ba4f502b 2018-08-04 stsp TAILQ_HEAD(commit_queue_head, commit_queue_entry);
109 ba4f502b 2018-08-04 stsp struct commit_queue {
110 ba4f502b 2018-08-04 stsp int ncommits;
111 ba4f502b 2018-08-04 stsp struct commit_queue_head head;
112 15a087fe 2019-02-21 stsp };
113 15a087fe 2019-02-21 stsp
114 15a087fe 2019-02-21 stsp struct tog_diff_view_state {
115 15a087fe 2019-02-21 stsp struct got_object_id *id1, *id2;
116 15a087fe 2019-02-21 stsp FILE *f;
117 15a087fe 2019-02-21 stsp int first_displayed_line;
118 15a087fe 2019-02-21 stsp int last_displayed_line;
119 15a087fe 2019-02-21 stsp int eof;
120 15a087fe 2019-02-21 stsp int diff_context;
121 15a087fe 2019-02-21 stsp struct got_repository *repo;
122 8b473291 2019-02-21 stsp struct got_reflist_head *refs;
123 15a087fe 2019-02-21 stsp
124 15a087fe 2019-02-21 stsp /* passed from log view; may be NULL */
125 fb872ab2 2019-02-21 stsp struct tog_view *log_view;
126 b01e7d3b 2018-08-04 stsp };
127 b01e7d3b 2018-08-04 stsp
128 1a76625f 2018-10-22 stsp pthread_mutex_t tog_mutex = PTHREAD_MUTEX_INITIALIZER;
129 1a76625f 2018-10-22 stsp
130 1a76625f 2018-10-22 stsp struct tog_log_thread_args {
131 1a76625f 2018-10-22 stsp pthread_cond_t need_commits;
132 1a76625f 2018-10-22 stsp int commits_needed;
133 b01e7d3b 2018-08-04 stsp struct got_commit_graph *graph;
134 1a76625f 2018-10-22 stsp struct commit_queue *commits;
135 1a76625f 2018-10-22 stsp const char *in_repo_path;
136 1a76625f 2018-10-22 stsp struct got_object_id *start_id;
137 1a76625f 2018-10-22 stsp struct got_repository *repo;
138 1a76625f 2018-10-22 stsp int log_complete;
139 1a76625f 2018-10-22 stsp sig_atomic_t *quit;
140 1a76625f 2018-10-22 stsp struct tog_view *view;
141 1a76625f 2018-10-22 stsp struct commit_queue_entry **first_displayed_entry;
142 1a76625f 2018-10-22 stsp struct commit_queue_entry **selected_entry;
143 1a76625f 2018-10-22 stsp };
144 1a76625f 2018-10-22 stsp
145 1a76625f 2018-10-22 stsp struct tog_log_view_state {
146 b01e7d3b 2018-08-04 stsp struct commit_queue commits;
147 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *first_displayed_entry;
148 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *last_displayed_entry;
149 b01e7d3b 2018-08-04 stsp struct commit_queue_entry *selected_entry;
150 b01e7d3b 2018-08-04 stsp int selected;
151 b01e7d3b 2018-08-04 stsp char *in_repo_path;
152 d01904d4 2019-06-25 stsp const char *head_ref_name;
153 b01e7d3b 2018-08-04 stsp struct got_repository *repo;
154 8b473291 2019-02-21 stsp struct got_reflist_head *refs;
155 5036bf37 2018-09-24 stsp struct got_object_id *start_id;
156 1a76625f 2018-10-22 stsp sig_atomic_t quit;
157 1a76625f 2018-10-22 stsp pthread_t thread;
158 1a76625f 2018-10-22 stsp struct tog_log_thread_args thread_args;
159 60493ae3 2019-06-20 stsp struct commit_queue_entry *matched_entry;
160 96e2b566 2019-07-08 stsp struct commit_queue_entry *search_entry;
161 ba4f502b 2018-08-04 stsp };
162 ba4f502b 2018-08-04 stsp
163 e9424729 2018-08-04 stsp struct tog_blame_cb_args {
164 e9424729 2018-08-04 stsp struct tog_blame_line *lines; /* one per line */
165 e9424729 2018-08-04 stsp int nlines;
166 e9424729 2018-08-04 stsp
167 e9424729 2018-08-04 stsp struct tog_view *view;
168 e9424729 2018-08-04 stsp struct got_object_id *commit_id;
169 e9424729 2018-08-04 stsp int *quit;
170 e9424729 2018-08-04 stsp };
171 e9424729 2018-08-04 stsp
172 e9424729 2018-08-04 stsp struct tog_blame_thread_args {
173 e9424729 2018-08-04 stsp const char *path;
174 e9424729 2018-08-04 stsp struct got_repository *repo;
175 e9424729 2018-08-04 stsp struct tog_blame_cb_args *cb_args;
176 e9424729 2018-08-04 stsp int *complete;
177 e9424729 2018-08-04 stsp };
178 e9424729 2018-08-04 stsp
179 e9424729 2018-08-04 stsp struct tog_blame {
180 e9424729 2018-08-04 stsp FILE *f;
181 e9424729 2018-08-04 stsp size_t filesize;
182 e9424729 2018-08-04 stsp struct tog_blame_line *lines;
183 6fcac457 2018-11-19 stsp int nlines;
184 6c4c42e0 2019-06-24 stsp off_t *line_offsets;
185 e9424729 2018-08-04 stsp pthread_t thread;
186 e9424729 2018-08-04 stsp struct tog_blame_thread_args thread_args;
187 e9424729 2018-08-04 stsp struct tog_blame_cb_args cb_args;
188 e9424729 2018-08-04 stsp const char *path;
189 e9424729 2018-08-04 stsp };
190 e9424729 2018-08-04 stsp
191 7cbe629d 2018-08-04 stsp struct tog_blame_view_state {
192 7cbe629d 2018-08-04 stsp int first_displayed_line;
193 7cbe629d 2018-08-04 stsp int last_displayed_line;
194 7cbe629d 2018-08-04 stsp int selected_line;
195 7cbe629d 2018-08-04 stsp int blame_complete;
196 e5a0f69f 2018-08-18 stsp int eof;
197 e5a0f69f 2018-08-18 stsp int done;
198 7cbe629d 2018-08-04 stsp struct got_object_id_queue blamed_commits;
199 7cbe629d 2018-08-04 stsp struct got_object_qid *blamed_commit;
200 e5a0f69f 2018-08-18 stsp char *path;
201 7cbe629d 2018-08-04 stsp struct got_repository *repo;
202 8b473291 2019-02-21 stsp struct got_reflist_head *refs;
203 ad80ab7b 2018-08-04 stsp struct got_object_id *commit_id;
204 e9424729 2018-08-04 stsp struct tog_blame blame;
205 6c4c42e0 2019-06-24 stsp int matched_line;
206 ad80ab7b 2018-08-04 stsp };
207 ad80ab7b 2018-08-04 stsp
208 ad80ab7b 2018-08-04 stsp struct tog_parent_tree {
209 ad80ab7b 2018-08-04 stsp TAILQ_ENTRY(tog_parent_tree) entry;
210 ad80ab7b 2018-08-04 stsp struct got_tree_object *tree;
211 ad80ab7b 2018-08-04 stsp struct got_tree_entry *first_displayed_entry;
212 ad80ab7b 2018-08-04 stsp struct got_tree_entry *selected_entry;
213 ad80ab7b 2018-08-04 stsp int selected;
214 ad80ab7b 2018-08-04 stsp };
215 ad80ab7b 2018-08-04 stsp
216 ad80ab7b 2018-08-04 stsp TAILQ_HEAD(tog_parent_trees, tog_parent_tree);
217 ad80ab7b 2018-08-04 stsp
218 ad80ab7b 2018-08-04 stsp struct tog_tree_view_state {
219 ad80ab7b 2018-08-04 stsp char *tree_label;
220 ad80ab7b 2018-08-04 stsp struct got_tree_object *root;
221 ad80ab7b 2018-08-04 stsp struct got_tree_object *tree;
222 ad80ab7b 2018-08-04 stsp const struct got_tree_entries *entries;
223 ad80ab7b 2018-08-04 stsp struct got_tree_entry *first_displayed_entry;
224 ad80ab7b 2018-08-04 stsp struct got_tree_entry *last_displayed_entry;
225 ad80ab7b 2018-08-04 stsp struct got_tree_entry *selected_entry;
226 416a95c5 2019-01-24 stsp int ndisplayed, selected, show_ids;
227 ad80ab7b 2018-08-04 stsp struct tog_parent_trees parents;
228 7cbe629d 2018-08-04 stsp struct got_object_id *commit_id;
229 ad80ab7b 2018-08-04 stsp struct got_repository *repo;
230 8b473291 2019-02-21 stsp struct got_reflist_head *refs;
231 7c32bd05 2019-06-22 stsp struct got_tree_entry *matched_entry;
232 7cbe629d 2018-08-04 stsp };
233 7cbe629d 2018-08-04 stsp
234 669b5ffa 2018-10-07 stsp /*
235 669b5ffa 2018-10-07 stsp * We implement two types of views: parent views and child views.
236 669b5ffa 2018-10-07 stsp *
237 669b5ffa 2018-10-07 stsp * The 'Tab' key switches between a parent view and its child view.
238 669b5ffa 2018-10-07 stsp * Child views are shown side-by-side to their parent view, provided
239 669b5ffa 2018-10-07 stsp * there is enough screen estate.
240 669b5ffa 2018-10-07 stsp *
241 669b5ffa 2018-10-07 stsp * When a new view is opened from within a parent view, this new view
242 669b5ffa 2018-10-07 stsp * becomes a child view of the parent view, replacing any existing child.
243 669b5ffa 2018-10-07 stsp *
244 669b5ffa 2018-10-07 stsp * When a new view is opened from within a child view, this new view
245 669b5ffa 2018-10-07 stsp * becomes a parent view which will obscure the views below until the
246 669b5ffa 2018-10-07 stsp * user quits the new parent view by typing 'q'.
247 669b5ffa 2018-10-07 stsp *
248 669b5ffa 2018-10-07 stsp * This list of views contains parent views only.
249 669b5ffa 2018-10-07 stsp * Child views are only pointed to by their parent view.
250 669b5ffa 2018-10-07 stsp */
251 bcbd79e2 2018-08-19 stsp TAILQ_HEAD(tog_view_list_head, tog_view);
252 669b5ffa 2018-10-07 stsp
253 cc3c9aac 2018-08-01 stsp struct tog_view {
254 e5a0f69f 2018-08-18 stsp TAILQ_ENTRY(tog_view) entry;
255 26ed57b2 2018-05-19 stsp WINDOW *window;
256 26ed57b2 2018-05-19 stsp PANEL *panel;
257 97ddc146 2018-08-01 stsp int nlines, ncols, begin_y, begin_x;
258 f7d12f7e 2018-08-01 stsp int lines, cols; /* copies of LINES and COLS */
259 1004088d 2018-09-29 stsp int focussed;
260 669b5ffa 2018-10-07 stsp struct tog_view *parent;
261 669b5ffa 2018-10-07 stsp struct tog_view *child;
262 669b5ffa 2018-10-07 stsp int child_focussed;
263 5dc9f4bc 2018-08-04 stsp
264 5dc9f4bc 2018-08-04 stsp /* type-specific state */
265 d6b05b5b 2018-08-04 stsp enum tog_view_type type;
266 5dc9f4bc 2018-08-04 stsp union {
267 b01e7d3b 2018-08-04 stsp struct tog_diff_view_state diff;
268 b01e7d3b 2018-08-04 stsp struct tog_log_view_state log;
269 7cbe629d 2018-08-04 stsp struct tog_blame_view_state blame;
270 ad80ab7b 2018-08-04 stsp struct tog_tree_view_state tree;
271 5dc9f4bc 2018-08-04 stsp } state;
272 e5a0f69f 2018-08-18 stsp
273 e5a0f69f 2018-08-18 stsp const struct got_error *(*show)(struct tog_view *);
274 e5a0f69f 2018-08-18 stsp const struct got_error *(*input)(struct tog_view **,
275 878940b7 2018-09-29 stsp struct tog_view **, struct tog_view**, struct tog_view *, int);
276 e5a0f69f 2018-08-18 stsp const struct got_error *(*close)(struct tog_view *);
277 60493ae3 2019-06-20 stsp
278 60493ae3 2019-06-20 stsp const struct got_error *(*search_start)(struct tog_view *);
279 60493ae3 2019-06-20 stsp const struct got_error *(*search_next)(struct tog_view *);
280 60493ae3 2019-06-20 stsp int searching;
281 b1bf1435 2019-06-21 stsp #define TOG_SEARCH_FORWARD 1
282 b1bf1435 2019-06-21 stsp #define TOG_SEARCH_BACKWARD 2
283 60493ae3 2019-06-20 stsp int search_next_done;
284 1803e47f 2019-06-22 stsp regex_t regex;
285 cc3c9aac 2018-08-01 stsp };
286 cd0acaa7 2018-05-20 stsp
287 ba4f502b 2018-08-04 stsp static const struct got_error *open_diff_view(struct tog_view *,
288 fb872ab2 2019-02-21 stsp struct got_object_id *, struct got_object_id *, struct tog_view *,
289 8b473291 2019-02-21 stsp struct got_reflist_head *, struct got_repository *);
290 5dc9f4bc 2018-08-04 stsp static const struct got_error *show_diff_view(struct tog_view *);
291 e5a0f69f 2018-08-18 stsp static const struct got_error *input_diff_view(struct tog_view **,
292 878940b7 2018-09-29 stsp struct tog_view **, struct tog_view **, struct tog_view *, int);
293 e5a0f69f 2018-08-18 stsp static const struct got_error* close_diff_view(struct tog_view *);
294 e5a0f69f 2018-08-18 stsp
295 ba4f502b 2018-08-04 stsp static const struct got_error *open_log_view(struct tog_view *,
296 8b473291 2019-02-21 stsp struct got_object_id *, struct got_reflist_head *,
297 d01904d4 2019-06-25 stsp struct got_repository *, const char *, const char *, int);
298 ba4f502b 2018-08-04 stsp static const struct got_error * show_log_view(struct tog_view *);
299 e5a0f69f 2018-08-18 stsp static const struct got_error *input_log_view(struct tog_view **,
300 878940b7 2018-09-29 stsp struct tog_view **, struct tog_view **, struct tog_view *, int);
301 e5a0f69f 2018-08-18 stsp static const struct got_error *close_log_view(struct tog_view *);
302 60493ae3 2019-06-20 stsp static const struct got_error *search_start_log_view(struct tog_view *);
303 60493ae3 2019-06-20 stsp static const struct got_error *search_next_log_view(struct tog_view *);
304 e5a0f69f 2018-08-18 stsp
305 e5a0f69f 2018-08-18 stsp static const struct got_error *open_blame_view(struct tog_view *, char *,
306 8b473291 2019-02-21 stsp struct got_object_id *, struct got_reflist_head *, struct got_repository *);
307 7cbe629d 2018-08-04 stsp static const struct got_error *show_blame_view(struct tog_view *);
308 e5a0f69f 2018-08-18 stsp static const struct got_error *input_blame_view(struct tog_view **,
309 878940b7 2018-09-29 stsp struct tog_view **, struct tog_view **, struct tog_view *, int);
310 e5a0f69f 2018-08-18 stsp static const struct got_error *close_blame_view(struct tog_view *);
311 6c4c42e0 2019-06-24 stsp static const struct got_error *search_start_blame_view(struct tog_view *);
312 6c4c42e0 2019-06-24 stsp static const struct got_error *search_next_blame_view(struct tog_view *);
313 e5a0f69f 2018-08-18 stsp
314 ad80ab7b 2018-08-04 stsp static const struct got_error *open_tree_view(struct tog_view *,
315 8b473291 2019-02-21 stsp struct got_tree_object *, struct got_object_id *,
316 8b473291 2019-02-21 stsp struct got_reflist_head *, struct got_repository *);
317 ad80ab7b 2018-08-04 stsp static const struct got_error *show_tree_view(struct tog_view *);
318 e5a0f69f 2018-08-18 stsp static const struct got_error *input_tree_view(struct tog_view **,
319 878940b7 2018-09-29 stsp struct tog_view **, struct tog_view **, struct tog_view *, int);
320 e5a0f69f 2018-08-18 stsp static const struct got_error *close_tree_view(struct tog_view *);
321 7c32bd05 2019-06-22 stsp static const struct got_error *search_start_tree_view(struct tog_view *);
322 7c32bd05 2019-06-22 stsp static const struct got_error *search_next_tree_view(struct tog_view *);
323 25791caa 2018-10-24 stsp
324 25791caa 2018-10-24 stsp static volatile sig_atomic_t tog_sigwinch_received;
325 83baff54 2019-08-12 stsp static volatile sig_atomic_t tog_sigpipe_received;
326 25791caa 2018-10-24 stsp
327 25791caa 2018-10-24 stsp static void
328 25791caa 2018-10-24 stsp tog_sigwinch(int signo)
329 25791caa 2018-10-24 stsp {
330 25791caa 2018-10-24 stsp tog_sigwinch_received = 1;
331 83baff54 2019-08-12 stsp }
332 83baff54 2019-08-12 stsp
333 83baff54 2019-08-12 stsp static void
334 83baff54 2019-08-12 stsp tog_sigpipe(int signo)
335 83baff54 2019-08-12 stsp {
336 83baff54 2019-08-12 stsp tog_sigpipe_received = 1;
337 25791caa 2018-10-24 stsp }
338 26ed57b2 2018-05-19 stsp
339 e5a0f69f 2018-08-18 stsp static const struct got_error *
340 96a765a8 2018-08-04 stsp view_close(struct tog_view *view)
341 ea5e7bb5 2018-08-01 stsp {
342 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
343 e5a0f69f 2018-08-18 stsp
344 669b5ffa 2018-10-07 stsp if (view->child) {
345 669b5ffa 2018-10-07 stsp view_close(view->child);
346 669b5ffa 2018-10-07 stsp view->child = NULL;
347 669b5ffa 2018-10-07 stsp }
348 e5a0f69f 2018-08-18 stsp if (view->close)
349 e5a0f69f 2018-08-18 stsp err = view->close(view);
350 ea5e7bb5 2018-08-01 stsp if (view->panel)
351 ea5e7bb5 2018-08-01 stsp del_panel(view->panel);
352 ea5e7bb5 2018-08-01 stsp if (view->window)
353 ea5e7bb5 2018-08-01 stsp delwin(view->window);
354 ea5e7bb5 2018-08-01 stsp free(view);
355 e5a0f69f 2018-08-18 stsp return err;
356 ea5e7bb5 2018-08-01 stsp }
357 ea5e7bb5 2018-08-01 stsp
358 ea5e7bb5 2018-08-01 stsp static struct tog_view *
359 b3665f43 2018-08-04 stsp view_open(int nlines, int ncols, int begin_y, int begin_x,
360 0cf4efb1 2018-09-29 stsp enum tog_view_type type)
361 ea5e7bb5 2018-08-01 stsp {
362 ad80ab7b 2018-08-04 stsp struct tog_view *view = calloc(1, sizeof(*view));
363 ea5e7bb5 2018-08-01 stsp
364 ea5e7bb5 2018-08-01 stsp if (view == NULL)
365 ea5e7bb5 2018-08-01 stsp return NULL;
366 ea5e7bb5 2018-08-01 stsp
367 d6b05b5b 2018-08-04 stsp view->type = type;
368 f7d12f7e 2018-08-01 stsp view->lines = LINES;
369 f7d12f7e 2018-08-01 stsp view->cols = COLS;
370 207b9029 2018-08-01 stsp view->nlines = nlines ? nlines : LINES - begin_y;
371 207b9029 2018-08-01 stsp view->ncols = ncols ? ncols : COLS - begin_x;
372 97ddc146 2018-08-01 stsp view->begin_y = begin_y;
373 97ddc146 2018-08-01 stsp view->begin_x = begin_x;
374 842167bf 2018-08-01 stsp view->window = newwin(nlines, ncols, begin_y, begin_x);
375 ea5e7bb5 2018-08-01 stsp if (view->window == NULL) {
376 96a765a8 2018-08-04 stsp view_close(view);
377 ea5e7bb5 2018-08-01 stsp return NULL;
378 ea5e7bb5 2018-08-01 stsp }
379 ea5e7bb5 2018-08-01 stsp view->panel = new_panel(view->window);
380 0cf4efb1 2018-09-29 stsp if (view->panel == NULL ||
381 0cf4efb1 2018-09-29 stsp set_panel_userptr(view->panel, view) != OK) {
382 96a765a8 2018-08-04 stsp view_close(view);
383 ea5e7bb5 2018-08-01 stsp return NULL;
384 ea5e7bb5 2018-08-01 stsp }
385 ea5e7bb5 2018-08-01 stsp
386 ea5e7bb5 2018-08-01 stsp keypad(view->window, TRUE);
387 ea5e7bb5 2018-08-01 stsp return view;
388 cdf1ee82 2018-08-01 stsp }
389 cdf1ee82 2018-08-01 stsp
390 0cf4efb1 2018-09-29 stsp static int
391 0cf4efb1 2018-09-29 stsp view_split_begin_x(int begin_x)
392 0cf4efb1 2018-09-29 stsp {
393 2bd27830 2018-10-22 stsp if (begin_x > 0 || COLS < 120)
394 0cf4efb1 2018-09-29 stsp return 0;
395 2bd27830 2018-10-22 stsp return (COLS - MAX(COLS / 2, 80));
396 5c60c32a 2018-10-18 stsp }
397 5c60c32a 2018-10-18 stsp
398 5c60c32a 2018-10-18 stsp static const struct got_error *view_resize(struct tog_view *);
399 5c60c32a 2018-10-18 stsp
400 5c60c32a 2018-10-18 stsp static const struct got_error *
401 5c60c32a 2018-10-18 stsp view_splitscreen(struct tog_view *view)
402 5c60c32a 2018-10-18 stsp {
403 5c60c32a 2018-10-18 stsp const struct got_error *err = NULL;
404 5c60c32a 2018-10-18 stsp
405 5c60c32a 2018-10-18 stsp view->begin_y = 0;
406 5c60c32a 2018-10-18 stsp view->begin_x = view_split_begin_x(0);
407 5c60c32a 2018-10-18 stsp view->nlines = LINES;
408 5c60c32a 2018-10-18 stsp view->ncols = COLS - view->begin_x;
409 5c60c32a 2018-10-18 stsp view->lines = LINES;
410 5c60c32a 2018-10-18 stsp view->cols = COLS;
411 5c60c32a 2018-10-18 stsp err = view_resize(view);
412 5c60c32a 2018-10-18 stsp if (err)
413 5c60c32a 2018-10-18 stsp return err;
414 5c60c32a 2018-10-18 stsp
415 5c60c32a 2018-10-18 stsp if (mvwin(view->window, view->begin_y, view->begin_x) == ERR)
416 638f9024 2019-05-13 stsp return got_error_from_errno("mvwin");
417 5c60c32a 2018-10-18 stsp
418 5c60c32a 2018-10-18 stsp return NULL;
419 5c60c32a 2018-10-18 stsp }
420 5c60c32a 2018-10-18 stsp
421 5c60c32a 2018-10-18 stsp static const struct got_error *
422 5c60c32a 2018-10-18 stsp view_fullscreen(struct tog_view *view)
423 5c60c32a 2018-10-18 stsp {
424 5c60c32a 2018-10-18 stsp const struct got_error *err = NULL;
425 5c60c32a 2018-10-18 stsp
426 5c60c32a 2018-10-18 stsp view->begin_x = 0;
427 5c60c32a 2018-10-18 stsp view->begin_y = 0;
428 5c60c32a 2018-10-18 stsp view->nlines = LINES;
429 5c60c32a 2018-10-18 stsp view->ncols = COLS;
430 5c60c32a 2018-10-18 stsp view->lines = LINES;
431 5c60c32a 2018-10-18 stsp view->cols = COLS;
432 5c60c32a 2018-10-18 stsp err = view_resize(view);
433 5c60c32a 2018-10-18 stsp if (err)
434 5c60c32a 2018-10-18 stsp return err;
435 5c60c32a 2018-10-18 stsp
436 5c60c32a 2018-10-18 stsp if (mvwin(view->window, view->begin_y, view->begin_x) == ERR)
437 638f9024 2019-05-13 stsp return got_error_from_errno("mvwin");
438 5c60c32a 2018-10-18 stsp
439 5c60c32a 2018-10-18 stsp return NULL;
440 0cf4efb1 2018-09-29 stsp }
441 0cf4efb1 2018-09-29 stsp
442 5c60c32a 2018-10-18 stsp static int
443 5c60c32a 2018-10-18 stsp view_is_parent_view(struct tog_view *view)
444 5c60c32a 2018-10-18 stsp {
445 5c60c32a 2018-10-18 stsp return view->parent == NULL;
446 5c60c32a 2018-10-18 stsp }
447 5c60c32a 2018-10-18 stsp
448 4d8c2215 2018-08-19 stsp static const struct got_error *
449 f7d12f7e 2018-08-01 stsp view_resize(struct tog_view *view)
450 f7d12f7e 2018-08-01 stsp {
451 f7d12f7e 2018-08-01 stsp int nlines, ncols;
452 f7d12f7e 2018-08-01 stsp
453 0cf4efb1 2018-09-29 stsp if (view->lines > LINES)
454 0cf4efb1 2018-09-29 stsp nlines = view->nlines - (view->lines - LINES);
455 0cf4efb1 2018-09-29 stsp else
456 0cf4efb1 2018-09-29 stsp nlines = view->nlines + (LINES - view->lines);
457 f7d12f7e 2018-08-01 stsp
458 0cf4efb1 2018-09-29 stsp if (view->cols > COLS)
459 0cf4efb1 2018-09-29 stsp ncols = view->ncols - (view->cols - COLS);
460 0cf4efb1 2018-09-29 stsp else
461 0cf4efb1 2018-09-29 stsp ncols = view->ncols + (COLS - view->cols);
462 f7d12f7e 2018-08-01 stsp
463 0cf4efb1 2018-09-29 stsp if (wresize(view->window, nlines, ncols) == ERR)
464 638f9024 2019-05-13 stsp return got_error_from_errno("wresize");
465 a6d7eb8d 2018-10-24 stsp if (replace_panel(view->panel, view->window) == ERR)
466 638f9024 2019-05-13 stsp return got_error_from_errno("replace_panel");
467 25791caa 2018-10-24 stsp wclear(view->window);
468 f7d12f7e 2018-08-01 stsp
469 0cf4efb1 2018-09-29 stsp view->nlines = nlines;
470 0cf4efb1 2018-09-29 stsp view->ncols = ncols;
471 0cf4efb1 2018-09-29 stsp view->lines = LINES;
472 0cf4efb1 2018-09-29 stsp view->cols = COLS;
473 6d0fee91 2018-08-01 stsp
474 6e3e5d9c 2018-10-18 stsp if (view->child) {
475 5c60c32a 2018-10-18 stsp view->child->begin_x = view_split_begin_x(view->begin_x);
476 5c60c32a 2018-10-18 stsp if (view->child->begin_x == 0) {
477 5c60c32a 2018-10-18 stsp view_fullscreen(view->child);
478 5c60c32a 2018-10-18 stsp if (view->child->focussed)
479 5c60c32a 2018-10-18 stsp show_panel(view->child->panel);
480 5c60c32a 2018-10-18 stsp else
481 5c60c32a 2018-10-18 stsp show_panel(view->panel);
482 5c60c32a 2018-10-18 stsp } else {
483 5c60c32a 2018-10-18 stsp view_splitscreen(view->child);
484 5c60c32a 2018-10-18 stsp show_panel(view->child->panel);
485 5c60c32a 2018-10-18 stsp }
486 5c60c32a 2018-10-18 stsp }
487 669b5ffa 2018-10-07 stsp
488 5c60c32a 2018-10-18 stsp return NULL;
489 669b5ffa 2018-10-07 stsp }
490 669b5ffa 2018-10-07 stsp
491 669b5ffa 2018-10-07 stsp static const struct got_error *
492 669b5ffa 2018-10-07 stsp view_close_child(struct tog_view *view)
493 669b5ffa 2018-10-07 stsp {
494 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
495 669b5ffa 2018-10-07 stsp
496 669b5ffa 2018-10-07 stsp if (view->child == NULL)
497 669b5ffa 2018-10-07 stsp return NULL;
498 669b5ffa 2018-10-07 stsp
499 669b5ffa 2018-10-07 stsp err = view_close(view->child);
500 669b5ffa 2018-10-07 stsp view->child = NULL;
501 669b5ffa 2018-10-07 stsp return err;
502 669b5ffa 2018-10-07 stsp }
503 669b5ffa 2018-10-07 stsp
504 669b5ffa 2018-10-07 stsp static const struct got_error *
505 669b5ffa 2018-10-07 stsp view_set_child(struct tog_view *view, struct tog_view *child)
506 669b5ffa 2018-10-07 stsp {
507 669b5ffa 2018-10-07 stsp const struct got_error *err = NULL;
508 669b5ffa 2018-10-07 stsp
509 669b5ffa 2018-10-07 stsp view->child = child;
510 669b5ffa 2018-10-07 stsp child->parent = view;
511 669b5ffa 2018-10-07 stsp return err;
512 bfddd0d9 2018-09-29 stsp }
513 bfddd0d9 2018-09-29 stsp
514 bfddd0d9 2018-09-29 stsp static int
515 bfddd0d9 2018-09-29 stsp view_is_splitscreen(struct tog_view *view)
516 bfddd0d9 2018-09-29 stsp {
517 f5215bb9 2019-02-22 stsp return view->begin_x > 0;
518 34bc9ec9 2019-02-22 stsp }
519 34bc9ec9 2019-02-22 stsp
520 34bc9ec9 2019-02-22 stsp static void
521 79fcf3e4 2018-11-04 stsp tog_resizeterm(void)
522 25791caa 2018-10-24 stsp {
523 25791caa 2018-10-24 stsp int cols, lines;
524 25791caa 2018-10-24 stsp struct winsize size;
525 25791caa 2018-10-24 stsp
526 25791caa 2018-10-24 stsp if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0) {
527 25791caa 2018-10-24 stsp cols = 80; /* Default */
528 25791caa 2018-10-24 stsp lines = 24;
529 25791caa 2018-10-24 stsp } else {
530 25791caa 2018-10-24 stsp cols = size.ws_col;
531 25791caa 2018-10-24 stsp lines = size.ws_row;
532 25791caa 2018-10-24 stsp }
533 25791caa 2018-10-24 stsp resize_term(lines, cols);
534 2b49a8ae 2019-06-22 stsp }
535 2b49a8ae 2019-06-22 stsp
536 2b49a8ae 2019-06-22 stsp static const struct got_error *
537 2b49a8ae 2019-06-22 stsp view_search_start(struct tog_view *view)
538 2b49a8ae 2019-06-22 stsp {
539 7c32bd05 2019-06-22 stsp const struct got_error *err = NULL;
540 2b49a8ae 2019-06-22 stsp char pattern[1024];
541 2b49a8ae 2019-06-22 stsp int ret;
542 2b49a8ae 2019-06-22 stsp
543 2b49a8ae 2019-06-22 stsp if (view->nlines < 1)
544 2b49a8ae 2019-06-22 stsp return NULL;
545 2b49a8ae 2019-06-22 stsp
546 2b49a8ae 2019-06-22 stsp mvwaddstr(view->window, view->begin_y + view->nlines - 1,
547 2b49a8ae 2019-06-22 stsp view->begin_x, "/");
548 2b49a8ae 2019-06-22 stsp wclrtoeol(view->window);
549 2b49a8ae 2019-06-22 stsp
550 2b49a8ae 2019-06-22 stsp nocbreak();
551 2b49a8ae 2019-06-22 stsp echo();
552 2b49a8ae 2019-06-22 stsp ret = wgetnstr(view->window, pattern, sizeof(pattern));
553 2b49a8ae 2019-06-22 stsp cbreak();
554 2b49a8ae 2019-06-22 stsp noecho();
555 2b49a8ae 2019-06-22 stsp if (ret == ERR)
556 2b49a8ae 2019-06-22 stsp return NULL;
557 2b49a8ae 2019-06-22 stsp
558 2b49a8ae 2019-06-22 stsp if (view->searching) {
559 2b49a8ae 2019-06-22 stsp regfree(&view->regex);
560 2b49a8ae 2019-06-22 stsp view->searching = 0;
561 2b49a8ae 2019-06-22 stsp }
562 2b49a8ae 2019-06-22 stsp
563 2b49a8ae 2019-06-22 stsp if (regcomp(&view->regex, pattern,
564 f5daf9b1 2019-06-24 stsp REG_EXTENDED | REG_NOSUB | REG_NEWLINE) == 0) {
565 7c32bd05 2019-06-22 stsp err = view->search_start(view);
566 7c32bd05 2019-06-22 stsp if (err) {
567 7c32bd05 2019-06-22 stsp regfree(&view->regex);
568 7c32bd05 2019-06-22 stsp return err;
569 7c32bd05 2019-06-22 stsp }
570 2b49a8ae 2019-06-22 stsp view->searching = TOG_SEARCH_FORWARD;
571 2b49a8ae 2019-06-22 stsp view->search_next_done = 0;
572 2b49a8ae 2019-06-22 stsp view->search_next(view);
573 2b49a8ae 2019-06-22 stsp }
574 2b49a8ae 2019-06-22 stsp
575 2b49a8ae 2019-06-22 stsp return NULL;
576 0cf4efb1 2018-09-29 stsp }
577 6d0fee91 2018-08-01 stsp
578 0cf4efb1 2018-09-29 stsp static const struct got_error *
579 48fcc512 2018-08-18 stsp view_input(struct tog_view **new, struct tog_view **dead,
580 e4197bf9 2018-08-18 stsp struct tog_view **focus, int *done, struct tog_view *view,
581 48fcc512 2018-08-18 stsp struct tog_view_list_head *views)
582 e5a0f69f 2018-08-18 stsp {
583 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
584 669b5ffa 2018-10-07 stsp struct tog_view *v;
585 1a76625f 2018-10-22 stsp int ch, errcode;
586 e5a0f69f 2018-08-18 stsp
587 e5a0f69f 2018-08-18 stsp *new = NULL;
588 e5a0f69f 2018-08-18 stsp *dead = NULL;
589 0cf4efb1 2018-09-29 stsp *focus = NULL;
590 e5a0f69f 2018-08-18 stsp
591 60493ae3 2019-06-20 stsp if (view->searching && !view->search_next_done) {
592 60493ae3 2019-06-20 stsp errcode = pthread_mutex_unlock(&tog_mutex);
593 60493ae3 2019-06-20 stsp if (errcode)
594 60493ae3 2019-06-20 stsp return got_error_set_errno(errcode,
595 60493ae3 2019-06-20 stsp "pthread_mutex_unlock");
596 60493ae3 2019-06-20 stsp pthread_yield();
597 60493ae3 2019-06-20 stsp errcode = pthread_mutex_lock(&tog_mutex);
598 60493ae3 2019-06-20 stsp if (errcode)
599 60493ae3 2019-06-20 stsp return got_error_set_errno(errcode,
600 60493ae3 2019-06-20 stsp "pthread_mutex_lock");
601 60493ae3 2019-06-20 stsp view->search_next(view);
602 60493ae3 2019-06-20 stsp return NULL;
603 60493ae3 2019-06-20 stsp }
604 60493ae3 2019-06-20 stsp
605 e5a0f69f 2018-08-18 stsp nodelay(stdscr, FALSE);
606 1a76625f 2018-10-22 stsp /* Allow threads to make progress while we are waiting for input. */
607 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
608 1a76625f 2018-10-22 stsp if (errcode)
609 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_unlock");
610 cc5bac66 2018-10-22 stsp ch = wgetch(view->window);
611 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
612 1a76625f 2018-10-22 stsp if (errcode)
613 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_lock");
614 e5a0f69f 2018-08-18 stsp nodelay(stdscr, TRUE);
615 25791caa 2018-10-24 stsp
616 25791caa 2018-10-24 stsp if (tog_sigwinch_received) {
617 25791caa 2018-10-24 stsp tog_resizeterm();
618 25791caa 2018-10-24 stsp tog_sigwinch_received = 0;
619 25791caa 2018-10-24 stsp TAILQ_FOREACH(v, views, entry) {
620 25791caa 2018-10-24 stsp err = view_resize(v);
621 25791caa 2018-10-24 stsp if (err)
622 25791caa 2018-10-24 stsp return err;
623 25791caa 2018-10-24 stsp err = v->input(new, dead, focus, v, KEY_RESIZE);
624 25791caa 2018-10-24 stsp if (err)
625 25791caa 2018-10-24 stsp return err;
626 25791caa 2018-10-24 stsp }
627 25791caa 2018-10-24 stsp }
628 25791caa 2018-10-24 stsp
629 e5a0f69f 2018-08-18 stsp switch (ch) {
630 1e37a5c2 2019-05-12 jcs case ERR:
631 1e37a5c2 2019-05-12 jcs break;
632 1e37a5c2 2019-05-12 jcs case '\t':
633 1e37a5c2 2019-05-12 jcs if (view->child) {
634 1e37a5c2 2019-05-12 jcs *focus = view->child;
635 1e37a5c2 2019-05-12 jcs view->child_focussed = 1;
636 1e37a5c2 2019-05-12 jcs } else if (view->parent) {
637 1e37a5c2 2019-05-12 jcs *focus = view->parent;
638 1e37a5c2 2019-05-12 jcs view->parent->child_focussed = 0;
639 1e37a5c2 2019-05-12 jcs }
640 1e37a5c2 2019-05-12 jcs break;
641 1e37a5c2 2019-05-12 jcs case 'q':
642 1e37a5c2 2019-05-12 jcs err = view->input(new, dead, focus, view, ch);
643 1e37a5c2 2019-05-12 jcs *dead = view;
644 1e37a5c2 2019-05-12 jcs break;
645 1e37a5c2 2019-05-12 jcs case 'Q':
646 1e37a5c2 2019-05-12 jcs *done = 1;
647 1e37a5c2 2019-05-12 jcs break;
648 1e37a5c2 2019-05-12 jcs case 'f':
649 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view)) {
650 1e37a5c2 2019-05-12 jcs if (view->child == NULL)
651 1e37a5c2 2019-05-12 jcs break;
652 1e37a5c2 2019-05-12 jcs if (view_is_splitscreen(view->child)) {
653 669b5ffa 2018-10-07 stsp *focus = view->child;
654 669b5ffa 2018-10-07 stsp view->child_focussed = 1;
655 1e37a5c2 2019-05-12 jcs err = view_fullscreen(view->child);
656 1e37a5c2 2019-05-12 jcs } else
657 1e37a5c2 2019-05-12 jcs err = view_splitscreen(view->child);
658 1e37a5c2 2019-05-12 jcs if (err)
659 1e37a5c2 2019-05-12 jcs break;
660 1e37a5c2 2019-05-12 jcs err = view->child->input(new, dead, focus,
661 1e37a5c2 2019-05-12 jcs view->child, KEY_RESIZE);
662 1e37a5c2 2019-05-12 jcs } else {
663 1e37a5c2 2019-05-12 jcs if (view_is_splitscreen(view)) {
664 1e37a5c2 2019-05-12 jcs *focus = view;
665 1e37a5c2 2019-05-12 jcs view->parent->child_focussed = 1;
666 1e37a5c2 2019-05-12 jcs err = view_fullscreen(view);
667 1e37a5c2 2019-05-12 jcs } else {
668 1e37a5c2 2019-05-12 jcs err = view_splitscreen(view);
669 669b5ffa 2018-10-07 stsp }
670 1e37a5c2 2019-05-12 jcs if (err)
671 1e37a5c2 2019-05-12 jcs break;
672 1e37a5c2 2019-05-12 jcs err = view->input(new, dead, focus, view,
673 1e37a5c2 2019-05-12 jcs KEY_RESIZE);
674 1e37a5c2 2019-05-12 jcs }
675 1e37a5c2 2019-05-12 jcs break;
676 1e37a5c2 2019-05-12 jcs case KEY_RESIZE:
677 60493ae3 2019-06-20 stsp break;
678 60493ae3 2019-06-20 stsp case '/':
679 60493ae3 2019-06-20 stsp if (view->search_start)
680 2b49a8ae 2019-06-22 stsp view_search_start(view);
681 60493ae3 2019-06-20 stsp else
682 60493ae3 2019-06-20 stsp err = view->input(new, dead, focus, view, ch);
683 1e37a5c2 2019-05-12 jcs break;
684 b1bf1435 2019-06-21 stsp case 'N':
685 60493ae3 2019-06-20 stsp case 'n':
686 60493ae3 2019-06-20 stsp if (view->search_next && view->searching) {
687 b1bf1435 2019-06-21 stsp view->searching = (ch == 'n' ?
688 b1bf1435 2019-06-21 stsp TOG_SEARCH_FORWARD : TOG_SEARCH_BACKWARD);
689 60493ae3 2019-06-20 stsp view->search_next_done = 0;
690 60493ae3 2019-06-20 stsp view->search_next(view);
691 60493ae3 2019-06-20 stsp } else
692 60493ae3 2019-06-20 stsp err = view->input(new, dead, focus, view, ch);
693 60493ae3 2019-06-20 stsp break;
694 1e37a5c2 2019-05-12 jcs default:
695 1e37a5c2 2019-05-12 jcs err = view->input(new, dead, focus, view, ch);
696 1e37a5c2 2019-05-12 jcs break;
697 e5a0f69f 2018-08-18 stsp }
698 e5a0f69f 2018-08-18 stsp
699 e5a0f69f 2018-08-18 stsp return err;
700 e5a0f69f 2018-08-18 stsp }
701 e5a0f69f 2018-08-18 stsp
702 1a57306a 2018-09-02 stsp void
703 1a57306a 2018-09-02 stsp view_vborder(struct tog_view *view)
704 1a57306a 2018-09-02 stsp {
705 0cf4efb1 2018-09-29 stsp PANEL *panel;
706 0cf4efb1 2018-09-29 stsp struct tog_view *view_above;
707 0cf4efb1 2018-09-29 stsp
708 669b5ffa 2018-10-07 stsp if (view->parent)
709 669b5ffa 2018-10-07 stsp return view_vborder(view->parent);
710 669b5ffa 2018-10-07 stsp
711 0cf4efb1 2018-09-29 stsp panel = panel_above(view->panel);
712 0cf4efb1 2018-09-29 stsp if (panel == NULL)
713 1a57306a 2018-09-02 stsp return;
714 1a57306a 2018-09-02 stsp
715 0cf4efb1 2018-09-29 stsp view_above = panel_userptr(panel);
716 0cf4efb1 2018-09-29 stsp mvwvline(view->window, view->begin_y, view_above->begin_x - 1,
717 1a57306a 2018-09-02 stsp got_locale_is_utf8() ? ACS_VLINE : '|', view->nlines);
718 bcbd79e2 2018-08-19 stsp }
719 bcbd79e2 2018-08-19 stsp
720 a3404814 2018-09-02 stsp int
721 a3404814 2018-09-02 stsp view_needs_focus_indication(struct tog_view *view)
722 a3404814 2018-09-02 stsp {
723 669b5ffa 2018-10-07 stsp if (view_is_parent_view(view)) {
724 669b5ffa 2018-10-07 stsp if (view->child == NULL || view->child_focussed)
725 669b5ffa 2018-10-07 stsp return 0;
726 669b5ffa 2018-10-07 stsp if (!view_is_splitscreen(view->child))
727 669b5ffa 2018-10-07 stsp return 0;
728 669b5ffa 2018-10-07 stsp } else if (!view_is_splitscreen(view))
729 a3404814 2018-09-02 stsp return 0;
730 a3404814 2018-09-02 stsp
731 669b5ffa 2018-10-07 stsp return view->focussed;
732 a3404814 2018-09-02 stsp }
733 a3404814 2018-09-02 stsp
734 bcbd79e2 2018-08-19 stsp static const struct got_error *
735 e5a0f69f 2018-08-18 stsp view_loop(struct tog_view *view)
736 e5a0f69f 2018-08-18 stsp {
737 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
738 e5a0f69f 2018-08-18 stsp struct tog_view_list_head views;
739 669b5ffa 2018-10-07 stsp struct tog_view *new_view, *dead_view, *focus_view, *main_view;
740 fd823528 2018-10-22 stsp int fast_refresh = 10;
741 1a76625f 2018-10-22 stsp int done = 0, errcode;
742 e5a0f69f 2018-08-18 stsp
743 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
744 1a76625f 2018-10-22 stsp if (errcode)
745 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_lock");
746 1a76625f 2018-10-22 stsp
747 e5a0f69f 2018-08-18 stsp TAILQ_INIT(&views);
748 e5a0f69f 2018-08-18 stsp TAILQ_INSERT_HEAD(&views, view, entry);
749 e5a0f69f 2018-08-18 stsp
750 a81bf10d 2018-09-29 stsp main_view = view;
751 1004088d 2018-09-29 stsp view->focussed = 1;
752 878940b7 2018-09-29 stsp err = view->show(view);
753 0cf4efb1 2018-09-29 stsp if (err)
754 0cf4efb1 2018-09-29 stsp return err;
755 0cf4efb1 2018-09-29 stsp update_panels();
756 0cf4efb1 2018-09-29 stsp doupdate();
757 83baff54 2019-08-12 stsp while (!TAILQ_EMPTY(&views) && !done && !tog_sigpipe_received) {
758 fd823528 2018-10-22 stsp /* Refresh fast during initialization, then become slower. */
759 fd823528 2018-10-22 stsp if (fast_refresh && fast_refresh-- == 0)
760 fd823528 2018-10-22 stsp halfdelay(10); /* switch to once per second */
761 fd823528 2018-10-22 stsp
762 0cf4efb1 2018-09-29 stsp err = view_input(&new_view, &dead_view, &focus_view, &done,
763 e4197bf9 2018-08-18 stsp view, &views);
764 e5a0f69f 2018-08-18 stsp if (err)
765 e5a0f69f 2018-08-18 stsp break;
766 e5a0f69f 2018-08-18 stsp if (dead_view) {
767 669b5ffa 2018-10-07 stsp struct tog_view *prev = NULL;
768 669b5ffa 2018-10-07 stsp
769 669b5ffa 2018-10-07 stsp if (view_is_parent_view(dead_view))
770 669b5ffa 2018-10-07 stsp prev = TAILQ_PREV(dead_view,
771 669b5ffa 2018-10-07 stsp tog_view_list_head, entry);
772 f41eceb0 2018-10-24 stsp else if (view->parent != dead_view)
773 669b5ffa 2018-10-07 stsp prev = view->parent;
774 669b5ffa 2018-10-07 stsp
775 669b5ffa 2018-10-07 stsp if (dead_view->parent)
776 669b5ffa 2018-10-07 stsp dead_view->parent->child = NULL;
777 669b5ffa 2018-10-07 stsp else
778 669b5ffa 2018-10-07 stsp TAILQ_REMOVE(&views, dead_view, entry);
779 669b5ffa 2018-10-07 stsp
780 e5a0f69f 2018-08-18 stsp err = view_close(dead_view);
781 d01904d4 2019-06-25 stsp if (err || (dead_view == main_view && new_view == NULL))
782 e5a0f69f 2018-08-18 stsp goto done;
783 669b5ffa 2018-10-07 stsp
784 0cf4efb1 2018-09-29 stsp if (view == dead_view) {
785 0cf4efb1 2018-09-29 stsp if (focus_view)
786 0cf4efb1 2018-09-29 stsp view = focus_view;
787 669b5ffa 2018-10-07 stsp else if (prev)
788 669b5ffa 2018-10-07 stsp view = prev;
789 669b5ffa 2018-10-07 stsp else if (!TAILQ_EMPTY(&views))
790 0cf4efb1 2018-09-29 stsp view = TAILQ_LAST(&views,
791 0cf4efb1 2018-09-29 stsp tog_view_list_head);
792 669b5ffa 2018-10-07 stsp else
793 0cf4efb1 2018-09-29 stsp view = NULL;
794 669b5ffa 2018-10-07 stsp if (view) {
795 669b5ffa 2018-10-07 stsp if (view->child && view->child_focussed)
796 669b5ffa 2018-10-07 stsp focus_view = view->child;
797 669b5ffa 2018-10-07 stsp else
798 669b5ffa 2018-10-07 stsp focus_view = view;
799 669b5ffa 2018-10-07 stsp }
800 0cf4efb1 2018-09-29 stsp }
801 e5a0f69f 2018-08-18 stsp }
802 bcbd79e2 2018-08-19 stsp if (new_view) {
803 86c66b02 2018-10-18 stsp struct tog_view *v, *t;
804 86c66b02 2018-10-18 stsp /* Only allow one parent view per type. */
805 86c66b02 2018-10-18 stsp TAILQ_FOREACH_SAFE(v, &views, entry, t) {
806 86c66b02 2018-10-18 stsp if (v->type != new_view->type)
807 86c66b02 2018-10-18 stsp continue;
808 86c66b02 2018-10-18 stsp TAILQ_REMOVE(&views, v, entry);
809 86c66b02 2018-10-18 stsp err = view_close(v);
810 86c66b02 2018-10-18 stsp if (err)
811 86c66b02 2018-10-18 stsp goto done;
812 86c66b02 2018-10-18 stsp break;
813 86c66b02 2018-10-18 stsp }
814 bcbd79e2 2018-08-19 stsp TAILQ_INSERT_TAIL(&views, new_view, entry);
815 fed7eaa8 2018-10-24 stsp view = new_view;
816 878940b7 2018-09-29 stsp if (focus_view == NULL)
817 878940b7 2018-09-29 stsp focus_view = new_view;
818 1a76625f 2018-10-22 stsp }
819 0cf4efb1 2018-09-29 stsp if (focus_view) {
820 0cf4efb1 2018-09-29 stsp show_panel(focus_view->panel);
821 669b5ffa 2018-10-07 stsp if (view)
822 0cf4efb1 2018-09-29 stsp view->focussed = 0;
823 0cf4efb1 2018-09-29 stsp focus_view->focussed = 1;
824 0cf4efb1 2018-09-29 stsp view = focus_view;
825 878940b7 2018-09-29 stsp if (new_view)
826 878940b7 2018-09-29 stsp show_panel(new_view->panel);
827 669b5ffa 2018-10-07 stsp if (view->child && view_is_splitscreen(view->child))
828 669b5ffa 2018-10-07 stsp show_panel(view->child->panel);
829 bcbd79e2 2018-08-19 stsp }
830 669b5ffa 2018-10-07 stsp if (view) {
831 1a76625f 2018-10-22 stsp if (focus_view == NULL) {
832 758194b5 2018-10-24 stsp view->focussed = 1;
833 758194b5 2018-10-24 stsp show_panel(view->panel);
834 758194b5 2018-10-24 stsp if (view->child && view_is_splitscreen(view->child))
835 758194b5 2018-10-24 stsp show_panel(view->child->panel);
836 1a76625f 2018-10-22 stsp focus_view = view;
837 1a76625f 2018-10-22 stsp }
838 669b5ffa 2018-10-07 stsp if (view->parent) {
839 669b5ffa 2018-10-07 stsp err = view->parent->show(view->parent);
840 669b5ffa 2018-10-07 stsp if (err)
841 1a76625f 2018-10-22 stsp goto done;
842 669b5ffa 2018-10-07 stsp }
843 669b5ffa 2018-10-07 stsp err = view->show(view);
844 0cf4efb1 2018-09-29 stsp if (err)
845 1a76625f 2018-10-22 stsp goto done;
846 669b5ffa 2018-10-07 stsp if (view->child) {
847 669b5ffa 2018-10-07 stsp err = view->child->show(view->child);
848 669b5ffa 2018-10-07 stsp if (err)
849 1a76625f 2018-10-22 stsp goto done;
850 669b5ffa 2018-10-07 stsp }
851 1a76625f 2018-10-22 stsp update_panels();
852 1a76625f 2018-10-22 stsp doupdate();
853 0cf4efb1 2018-09-29 stsp }
854 e5a0f69f 2018-08-18 stsp }
855 e5a0f69f 2018-08-18 stsp done:
856 e5a0f69f 2018-08-18 stsp while (!TAILQ_EMPTY(&views)) {
857 e5a0f69f 2018-08-18 stsp view = TAILQ_FIRST(&views);
858 e5a0f69f 2018-08-18 stsp TAILQ_REMOVE(&views, view, entry);
859 e5a0f69f 2018-08-18 stsp view_close(view);
860 e5a0f69f 2018-08-18 stsp }
861 1a76625f 2018-10-22 stsp
862 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
863 963ecf2a 2019-08-12 stsp if (errcode && err == NULL)
864 963ecf2a 2019-08-12 stsp err = got_error_set_errno(errcode, "pthread_mutex_unlock");
865 1a76625f 2018-10-22 stsp
866 e5a0f69f 2018-08-18 stsp return err;
867 ea5e7bb5 2018-08-01 stsp }
868 ea5e7bb5 2018-08-01 stsp
869 4ed7e80c 2018-05-20 stsp __dead static void
870 9f7d7167 2018-04-29 stsp usage_log(void)
871 9f7d7167 2018-04-29 stsp {
872 80ddbec8 2018-04-29 stsp endwin();
873 c70c5802 2018-08-01 stsp fprintf(stderr,
874 c70c5802 2018-08-01 stsp "usage: %s log [-c commit] [-r repository-path] [path]\n",
875 9f7d7167 2018-04-29 stsp getprogname());
876 9f7d7167 2018-04-29 stsp exit(1);
877 80ddbec8 2018-04-29 stsp }
878 80ddbec8 2018-04-29 stsp
879 963b370f 2018-05-20 stsp /* Create newly allocated wide-character string equivalent to a byte string. */
880 80ddbec8 2018-04-29 stsp static const struct got_error *
881 963b370f 2018-05-20 stsp mbs2ws(wchar_t **ws, size_t *wlen, const char *s)
882 963b370f 2018-05-20 stsp {
883 00dfcb92 2018-06-11 stsp char *vis = NULL;
884 963b370f 2018-05-20 stsp const struct got_error *err = NULL;
885 963b370f 2018-05-20 stsp
886 963b370f 2018-05-20 stsp *ws = NULL;
887 963b370f 2018-05-20 stsp *wlen = mbstowcs(NULL, s, 0);
888 00dfcb92 2018-06-11 stsp if (*wlen == (size_t)-1) {
889 00dfcb92 2018-06-11 stsp int vislen;
890 00dfcb92 2018-06-11 stsp if (errno != EILSEQ)
891 638f9024 2019-05-13 stsp return got_error_from_errno("mbstowcs");
892 00dfcb92 2018-06-11 stsp
893 00dfcb92 2018-06-11 stsp /* byte string invalid in current encoding; try to "fix" it */
894 00dfcb92 2018-06-11 stsp err = got_mbsavis(&vis, &vislen, s);
895 00dfcb92 2018-06-11 stsp if (err)
896 00dfcb92 2018-06-11 stsp return err;
897 00dfcb92 2018-06-11 stsp *wlen = mbstowcs(NULL, vis, 0);
898 a7f50699 2018-06-11 stsp if (*wlen == (size_t)-1) {
899 638f9024 2019-05-13 stsp err = got_error_from_errno("mbstowcs"); /* give up */
900 a7f50699 2018-06-11 stsp goto done;
901 a7f50699 2018-06-11 stsp }
902 00dfcb92 2018-06-11 stsp }
903 963b370f 2018-05-20 stsp
904 963b370f 2018-05-20 stsp *ws = calloc(*wlen + 1, sizeof(*ws));
905 a7f50699 2018-06-11 stsp if (*ws == NULL) {
906 638f9024 2019-05-13 stsp err = got_error_from_errno("calloc");
907 a7f50699 2018-06-11 stsp goto done;
908 a7f50699 2018-06-11 stsp }
909 963b370f 2018-05-20 stsp
910 00dfcb92 2018-06-11 stsp if (mbstowcs(*ws, vis ? vis : s, *wlen) != *wlen)
911 638f9024 2019-05-13 stsp err = got_error_from_errno("mbstowcs");
912 a7f50699 2018-06-11 stsp done:
913 00dfcb92 2018-06-11 stsp free(vis);
914 963b370f 2018-05-20 stsp if (err) {
915 963b370f 2018-05-20 stsp free(*ws);
916 963b370f 2018-05-20 stsp *ws = NULL;
917 963b370f 2018-05-20 stsp *wlen = 0;
918 963b370f 2018-05-20 stsp }
919 963b370f 2018-05-20 stsp return err;
920 963b370f 2018-05-20 stsp }
921 963b370f 2018-05-20 stsp
922 963b370f 2018-05-20 stsp /* Format a line for display, ensuring that it won't overflow a width limit. */
923 963b370f 2018-05-20 stsp static const struct got_error *
924 ffd1d5e5 2018-06-23 stsp format_line(wchar_t **wlinep, int *widthp, const char *line, int wlimit)
925 963b370f 2018-05-20 stsp {
926 963b370f 2018-05-20 stsp const struct got_error *err = NULL;
927 963b370f 2018-05-20 stsp int cols = 0;
928 963b370f 2018-05-20 stsp wchar_t *wline = NULL;
929 963b370f 2018-05-20 stsp size_t wlen;
930 963b370f 2018-05-20 stsp int i;
931 963b370f 2018-05-20 stsp
932 963b370f 2018-05-20 stsp *wlinep = NULL;
933 b700b5d6 2018-07-10 stsp *widthp = 0;
934 963b370f 2018-05-20 stsp
935 963b370f 2018-05-20 stsp err = mbs2ws(&wline, &wlen, line);
936 963b370f 2018-05-20 stsp if (err)
937 963b370f 2018-05-20 stsp return err;
938 963b370f 2018-05-20 stsp
939 963b370f 2018-05-20 stsp i = 0;
940 b700b5d6 2018-07-10 stsp while (i < wlen && cols < wlimit) {
941 963b370f 2018-05-20 stsp int width = wcwidth(wline[i]);
942 963b370f 2018-05-20 stsp switch (width) {
943 963b370f 2018-05-20 stsp case 0:
944 b700b5d6 2018-07-10 stsp i++;
945 963b370f 2018-05-20 stsp break;
946 963b370f 2018-05-20 stsp case 1:
947 963b370f 2018-05-20 stsp case 2:
948 3c1f04f1 2018-09-13 stsp if (cols + width <= wlimit)
949 b700b5d6 2018-07-10 stsp cols += width;
950 3c1f04f1 2018-09-13 stsp i++;
951 963b370f 2018-05-20 stsp break;
952 963b370f 2018-05-20 stsp case -1:
953 963b370f 2018-05-20 stsp if (wline[i] == L'\t')
954 67ceb59d 2019-03-03 stsp cols += TABSIZE - ((cols + 1) % TABSIZE);
955 b700b5d6 2018-07-10 stsp i++;
956 963b370f 2018-05-20 stsp break;
957 963b370f 2018-05-20 stsp default:
958 638f9024 2019-05-13 stsp err = got_error_from_errno("wcwidth");
959 963b370f 2018-05-20 stsp goto done;
960 963b370f 2018-05-20 stsp }
961 963b370f 2018-05-20 stsp }
962 963b370f 2018-05-20 stsp wline[i] = L'\0';
963 b700b5d6 2018-07-10 stsp if (widthp)
964 b700b5d6 2018-07-10 stsp *widthp = cols;
965 963b370f 2018-05-20 stsp done:
966 963b370f 2018-05-20 stsp if (err)
967 963b370f 2018-05-20 stsp free(wline);
968 963b370f 2018-05-20 stsp else
969 963b370f 2018-05-20 stsp *wlinep = wline;
970 963b370f 2018-05-20 stsp return err;
971 963b370f 2018-05-20 stsp }
972 963b370f 2018-05-20 stsp
973 8b473291 2019-02-21 stsp static const struct got_error*
974 8b473291 2019-02-21 stsp build_refs_str(char **refs_str, struct got_reflist_head *refs,
975 52b5abe1 2019-08-13 stsp struct got_object_id *id, struct got_repository *repo)
976 8b473291 2019-02-21 stsp {
977 8b473291 2019-02-21 stsp static const struct got_error *err = NULL;
978 8b473291 2019-02-21 stsp struct got_reflist_entry *re;
979 8b473291 2019-02-21 stsp char *s;
980 8b473291 2019-02-21 stsp const char *name;
981 8b473291 2019-02-21 stsp
982 8b473291 2019-02-21 stsp *refs_str = NULL;
983 8b473291 2019-02-21 stsp
984 8b473291 2019-02-21 stsp SIMPLEQ_FOREACH(re, refs, entry) {
985 52b5abe1 2019-08-13 stsp struct got_tag_object *tag = NULL;
986 52b5abe1 2019-08-13 stsp int cmp;
987 52b5abe1 2019-08-13 stsp
988 8b473291 2019-02-21 stsp name = got_ref_get_name(re->ref);
989 8b473291 2019-02-21 stsp if (strcmp(name, GOT_REF_HEAD) == 0)
990 8b473291 2019-02-21 stsp continue;
991 8b473291 2019-02-21 stsp if (strncmp(name, "refs/", 5) == 0)
992 8b473291 2019-02-21 stsp name += 5;
993 7143d404 2019-03-12 stsp if (strncmp(name, "got/", 4) == 0)
994 7143d404 2019-03-12 stsp continue;
995 8b473291 2019-02-21 stsp if (strncmp(name, "heads/", 6) == 0)
996 8b473291 2019-02-21 stsp name += 6;
997 8b473291 2019-02-21 stsp if (strncmp(name, "remotes/", 8) == 0)
998 8b473291 2019-02-21 stsp name += 8;
999 52b5abe1 2019-08-13 stsp if (strncmp(name, "tags/", 5) == 0) {
1000 52b5abe1 2019-08-13 stsp err = got_object_open_as_tag(&tag, repo, re->id);
1001 5d844a1e 2019-08-13 stsp if (err) {
1002 5d844a1e 2019-08-13 stsp if (err->code != GOT_ERR_OBJ_TYPE)
1003 5d844a1e 2019-08-13 stsp break;
1004 5d844a1e 2019-08-13 stsp /* Ref points at something other than a tag. */
1005 5d844a1e 2019-08-13 stsp err = NULL;
1006 5d844a1e 2019-08-13 stsp tag = NULL;
1007 5d844a1e 2019-08-13 stsp }
1008 52b5abe1 2019-08-13 stsp }
1009 52b5abe1 2019-08-13 stsp cmp = got_object_id_cmp(tag ?
1010 52b5abe1 2019-08-13 stsp got_object_tag_get_object_id(tag) : re->id, id);
1011 52b5abe1 2019-08-13 stsp if (tag)
1012 52b5abe1 2019-08-13 stsp got_object_tag_close(tag);
1013 52b5abe1 2019-08-13 stsp if (cmp != 0)
1014 52b5abe1 2019-08-13 stsp continue;
1015 8b473291 2019-02-21 stsp s = *refs_str;
1016 8b473291 2019-02-21 stsp if (asprintf(refs_str, "%s%s%s", s ? s : "",
1017 8b473291 2019-02-21 stsp s ? ", " : "", name) == -1) {
1018 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
1019 8b473291 2019-02-21 stsp free(s);
1020 8b473291 2019-02-21 stsp *refs_str = NULL;
1021 8b473291 2019-02-21 stsp break;
1022 8b473291 2019-02-21 stsp }
1023 8b473291 2019-02-21 stsp free(s);
1024 8b473291 2019-02-21 stsp }
1025 8b473291 2019-02-21 stsp
1026 8b473291 2019-02-21 stsp return err;
1027 8b473291 2019-02-21 stsp }
1028 8b473291 2019-02-21 stsp
1029 963b370f 2018-05-20 stsp static const struct got_error *
1030 5813d178 2019-03-09 stsp format_author(wchar_t **wauthor, int *author_width, char *author, int limit)
1031 5813d178 2019-03-09 stsp {
1032 5813d178 2019-03-09 stsp char *smallerthan, *at;
1033 5813d178 2019-03-09 stsp
1034 5813d178 2019-03-09 stsp smallerthan = strchr(author, '<');
1035 5813d178 2019-03-09 stsp if (smallerthan && smallerthan[1] != '\0')
1036 5813d178 2019-03-09 stsp author = smallerthan + 1;
1037 5813d178 2019-03-09 stsp at = strchr(author, '@');
1038 5813d178 2019-03-09 stsp if (at)
1039 5813d178 2019-03-09 stsp *at = '\0';
1040 5813d178 2019-03-09 stsp return format_line(wauthor, author_width, author, limit);
1041 5813d178 2019-03-09 stsp }
1042 5813d178 2019-03-09 stsp
1043 5813d178 2019-03-09 stsp static const struct got_error *
1044 2814baeb 2018-08-01 stsp draw_commit(struct tog_view *view, struct got_commit_object *commit,
1045 5813d178 2019-03-09 stsp struct got_object_id *id, struct got_reflist_head *refs,
1046 5813d178 2019-03-09 stsp int author_display_cols)
1047 80ddbec8 2018-04-29 stsp {
1048 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
1049 b39d25c7 2018-07-10 stsp char datebuf[10]; /* YY-MM-DD + SPACE + NUL */
1050 80ddbec8 2018-04-29 stsp char *logmsg0 = NULL, *logmsg = NULL;
1051 5813d178 2019-03-09 stsp char *author = NULL;
1052 bb737323 2018-05-20 stsp wchar_t *wlogmsg = NULL, *wauthor = NULL;
1053 bb737323 2018-05-20 stsp int author_width, logmsg_width;
1054 5813d178 2019-03-09 stsp char *newline, *line = NULL;
1055 bb737323 2018-05-20 stsp int col, limit;
1056 b39d25c7 2018-07-10 stsp static const size_t date_display_cols = 9;
1057 f7d12f7e 2018-08-01 stsp const int avail = view->ncols;
1058 ccb26ccd 2018-11-05 stsp struct tm tm;
1059 45d799e2 2018-12-23 stsp time_t committer_time;
1060 80ddbec8 2018-04-29 stsp
1061 45d799e2 2018-12-23 stsp committer_time = got_object_commit_get_committer_time(commit);
1062 45d799e2 2018-12-23 stsp if (localtime_r(&committer_time, &tm) == NULL)
1063 638f9024 2019-05-13 stsp return got_error_from_errno("localtime_r");
1064 ccb26ccd 2018-11-05 stsp if (strftime(datebuf, sizeof(datebuf), "%g/%m/%d ", &tm)
1065 ccb26ccd 2018-11-05 stsp >= sizeof(datebuf))
1066 b39d25c7 2018-07-10 stsp return got_error(GOT_ERR_NO_SPACE);
1067 b39d25c7 2018-07-10 stsp
1068 b39d25c7 2018-07-10 stsp if (avail < date_display_cols)
1069 b39d25c7 2018-07-10 stsp limit = MIN(sizeof(datebuf) - 1, avail);
1070 b39d25c7 2018-07-10 stsp else
1071 b39d25c7 2018-07-10 stsp limit = MIN(date_display_cols, sizeof(datebuf) - 1);
1072 2814baeb 2018-08-01 stsp waddnstr(view->window, datebuf, limit);
1073 b39d25c7 2018-07-10 stsp col = limit + 1;
1074 b39d25c7 2018-07-10 stsp if (col > avail)
1075 b39d25c7 2018-07-10 stsp goto done;
1076 b39d25c7 2018-07-10 stsp
1077 5813d178 2019-03-09 stsp author = strdup(got_object_commit_get_author(commit));
1078 5813d178 2019-03-09 stsp if (author == NULL) {
1079 638f9024 2019-05-13 stsp err = got_error_from_errno("strdup");
1080 80ddbec8 2018-04-29 stsp goto done;
1081 80ddbec8 2018-04-29 stsp }
1082 5813d178 2019-03-09 stsp err = format_author(&wauthor, &author_width, author, avail - col);
1083 bb737323 2018-05-20 stsp if (err)
1084 bb737323 2018-05-20 stsp goto done;
1085 2814baeb 2018-08-01 stsp waddwstr(view->window, wauthor);
1086 bb737323 2018-05-20 stsp col += author_width;
1087 5813d178 2019-03-09 stsp while (col <= avail && author_width < author_display_cols + 2) {
1088 2814baeb 2018-08-01 stsp waddch(view->window, ' ');
1089 bb737323 2018-05-20 stsp col++;
1090 bb737323 2018-05-20 stsp author_width++;
1091 bb737323 2018-05-20 stsp }
1092 9c2eaf34 2018-05-20 stsp if (col > avail)
1093 9c2eaf34 2018-05-20 stsp goto done;
1094 80ddbec8 2018-04-29 stsp
1095 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
1096 5943eee2 2019-08-13 stsp if (err)
1097 6d9fbc00 2018-04-29 stsp goto done;
1098 bb737323 2018-05-20 stsp logmsg = logmsg0;
1099 bb737323 2018-05-20 stsp while (*logmsg == '\n')
1100 bb737323 2018-05-20 stsp logmsg++;
1101 bb737323 2018-05-20 stsp newline = strchr(logmsg, '\n');
1102 bb737323 2018-05-20 stsp if (newline)
1103 bb737323 2018-05-20 stsp *newline = '\0';
1104 bb737323 2018-05-20 stsp limit = avail - col;
1105 bb737323 2018-05-20 stsp err = format_line(&wlogmsg, &logmsg_width, logmsg, limit);
1106 bb737323 2018-05-20 stsp if (err)
1107 bb737323 2018-05-20 stsp goto done;
1108 2814baeb 2018-08-01 stsp waddwstr(view->window, wlogmsg);
1109 bb737323 2018-05-20 stsp col += logmsg_width;
1110 bb737323 2018-05-20 stsp while (col <= avail) {
1111 2814baeb 2018-08-01 stsp waddch(view->window, ' ');
1112 bb737323 2018-05-20 stsp col++;
1113 881b2d3e 2018-04-30 stsp }
1114 80ddbec8 2018-04-29 stsp done:
1115 80ddbec8 2018-04-29 stsp free(logmsg0);
1116 bb737323 2018-05-20 stsp free(wlogmsg);
1117 5813d178 2019-03-09 stsp free(author);
1118 bb737323 2018-05-20 stsp free(wauthor);
1119 80ddbec8 2018-04-29 stsp free(line);
1120 80ddbec8 2018-04-29 stsp return err;
1121 80ddbec8 2018-04-29 stsp }
1122 26ed57b2 2018-05-19 stsp
1123 899d86c2 2018-05-10 stsp static struct commit_queue_entry *
1124 899d86c2 2018-05-10 stsp alloc_commit_queue_entry(struct got_commit_object *commit,
1125 899d86c2 2018-05-10 stsp struct got_object_id *id)
1126 80ddbec8 2018-04-29 stsp {
1127 80ddbec8 2018-04-29 stsp struct commit_queue_entry *entry;
1128 80ddbec8 2018-04-29 stsp
1129 80ddbec8 2018-04-29 stsp entry = calloc(1, sizeof(*entry));
1130 80ddbec8 2018-04-29 stsp if (entry == NULL)
1131 899d86c2 2018-05-10 stsp return NULL;
1132 99db9666 2018-05-07 stsp
1133 899d86c2 2018-05-10 stsp entry->id = id;
1134 99db9666 2018-05-07 stsp entry->commit = commit;
1135 899d86c2 2018-05-10 stsp return entry;
1136 99db9666 2018-05-07 stsp }
1137 80ddbec8 2018-04-29 stsp
1138 99db9666 2018-05-07 stsp static void
1139 99db9666 2018-05-07 stsp pop_commit(struct commit_queue *commits)
1140 99db9666 2018-05-07 stsp {
1141 99db9666 2018-05-07 stsp struct commit_queue_entry *entry;
1142 99db9666 2018-05-07 stsp
1143 ecb28ae0 2018-07-16 stsp entry = TAILQ_FIRST(&commits->head);
1144 ecb28ae0 2018-07-16 stsp TAILQ_REMOVE(&commits->head, entry, entry);
1145 99db9666 2018-05-07 stsp got_object_commit_close(entry->commit);
1146 ecb28ae0 2018-07-16 stsp commits->ncommits--;
1147 9ba79e04 2018-06-11 stsp /* Don't free entry->id! It is owned by the commit graph. */
1148 99db9666 2018-05-07 stsp free(entry);
1149 99db9666 2018-05-07 stsp }
1150 99db9666 2018-05-07 stsp
1151 99db9666 2018-05-07 stsp static void
1152 99db9666 2018-05-07 stsp free_commits(struct commit_queue *commits)
1153 99db9666 2018-05-07 stsp {
1154 ecb28ae0 2018-07-16 stsp while (!TAILQ_EMPTY(&commits->head))
1155 99db9666 2018-05-07 stsp pop_commit(commits);
1156 c4972b91 2018-05-07 stsp }
1157 c4972b91 2018-05-07 stsp
1158 c4972b91 2018-05-07 stsp static const struct got_error *
1159 9ba79e04 2018-06-11 stsp queue_commits(struct got_commit_graph *graph, struct commit_queue *commits,
1160 1a76625f 2018-10-22 stsp int minqueue, struct got_repository *repo, const char *path)
1161 c4972b91 2018-05-07 stsp {
1162 899d86c2 2018-05-10 stsp const struct got_error *err = NULL;
1163 93e45b7c 2018-09-24 stsp int nqueued = 0;
1164 9ba79e04 2018-06-11 stsp
1165 1a76625f 2018-10-22 stsp /*
1166 1a76625f 2018-10-22 stsp * We keep all commits open throughout the lifetime of the log
1167 1a76625f 2018-10-22 stsp * view in order to avoid having to re-fetch commits from disk
1168 1a76625f 2018-10-22 stsp * while updating the display.
1169 1a76625f 2018-10-22 stsp */
1170 93e45b7c 2018-09-24 stsp while (nqueued < minqueue) {
1171 93e45b7c 2018-09-24 stsp struct got_object_id *id;
1172 9ba79e04 2018-06-11 stsp struct got_commit_object *commit;
1173 93e45b7c 2018-09-24 stsp struct commit_queue_entry *entry;
1174 1a76625f 2018-10-22 stsp int errcode;
1175 899d86c2 2018-05-10 stsp
1176 9ba79e04 2018-06-11 stsp err = got_commit_graph_iter_next(&id, graph);
1177 9ba79e04 2018-06-11 stsp if (err) {
1178 93e45b7c 2018-09-24 stsp if (err->code != GOT_ERR_ITER_NEED_MORE)
1179 93e45b7c 2018-09-24 stsp break;
1180 93e45b7c 2018-09-24 stsp err = got_commit_graph_fetch_commits(graph,
1181 93e45b7c 2018-09-24 stsp minqueue, repo);
1182 ecb28ae0 2018-07-16 stsp if (err)
1183 ecb28ae0 2018-07-16 stsp return err;
1184 ecb28ae0 2018-07-16 stsp continue;
1185 9ba79e04 2018-06-11 stsp }
1186 93e45b7c 2018-09-24 stsp
1187 ecb28ae0 2018-07-16 stsp if (id == NULL)
1188 ecb28ae0 2018-07-16 stsp break;
1189 899d86c2 2018-05-10 stsp
1190 9ba79e04 2018-06-11 stsp err = got_object_open_as_commit(&commit, repo, id);
1191 9ba79e04 2018-06-11 stsp if (err)
1192 9ba79e04 2018-06-11 stsp break;
1193 9ba79e04 2018-06-11 stsp entry = alloc_commit_queue_entry(commit, id);
1194 9ba79e04 2018-06-11 stsp if (entry == NULL) {
1195 638f9024 2019-05-13 stsp err = got_error_from_errno("alloc_commit_queue_entry");
1196 9ba79e04 2018-06-11 stsp break;
1197 9ba79e04 2018-06-11 stsp }
1198 93e45b7c 2018-09-24 stsp
1199 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
1200 1a76625f 2018-10-22 stsp if (errcode) {
1201 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode, "pthread_mutex_lock");
1202 1a76625f 2018-10-22 stsp break;
1203 1a76625f 2018-10-22 stsp }
1204 1a76625f 2018-10-22 stsp
1205 1a76625f 2018-10-22 stsp entry->idx = commits->ncommits;
1206 ecb28ae0 2018-07-16 stsp TAILQ_INSERT_TAIL(&commits->head, entry, entry);
1207 ecb28ae0 2018-07-16 stsp nqueued++;
1208 ecb28ae0 2018-07-16 stsp commits->ncommits++;
1209 1a76625f 2018-10-22 stsp
1210 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1211 1a76625f 2018-10-22 stsp if (errcode && err == NULL)
1212 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode,
1213 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
1214 899d86c2 2018-05-10 stsp }
1215 899d86c2 2018-05-10 stsp
1216 9ba79e04 2018-06-11 stsp return err;
1217 99db9666 2018-05-07 stsp }
1218 99db9666 2018-05-07 stsp
1219 99db9666 2018-05-07 stsp static const struct got_error *
1220 19e70ad6 2019-05-14 stsp get_head_commit_id(struct got_object_id **head_id, const char *branch_name,
1221 19e70ad6 2019-05-14 stsp struct got_repository *repo)
1222 99db9666 2018-05-07 stsp {
1223 9ba79e04 2018-06-11 stsp const struct got_error *err = NULL;
1224 9ba79e04 2018-06-11 stsp struct got_reference *head_ref;
1225 99db9666 2018-05-07 stsp
1226 9ba79e04 2018-06-11 stsp *head_id = NULL;
1227 899d86c2 2018-05-10 stsp
1228 19e70ad6 2019-05-14 stsp err = got_ref_open(&head_ref, repo, branch_name, 0);
1229 99db9666 2018-05-07 stsp if (err)
1230 99db9666 2018-05-07 stsp return err;
1231 99db9666 2018-05-07 stsp
1232 9ba79e04 2018-06-11 stsp err = got_ref_resolve(head_id, repo, head_ref);
1233 9ba79e04 2018-06-11 stsp got_ref_close(head_ref);
1234 9ba79e04 2018-06-11 stsp if (err) {
1235 9ba79e04 2018-06-11 stsp *head_id = NULL;
1236 99db9666 2018-05-07 stsp return err;
1237 0553a4e3 2018-04-30 stsp }
1238 80ddbec8 2018-04-29 stsp
1239 9ba79e04 2018-06-11 stsp return NULL;
1240 0553a4e3 2018-04-30 stsp }
1241 0553a4e3 2018-04-30 stsp
1242 0553a4e3 2018-04-30 stsp static const struct got_error *
1243 2814baeb 2018-08-01 stsp draw_commits(struct tog_view *view, struct commit_queue_entry **last,
1244 ecb28ae0 2018-07-16 stsp struct commit_queue_entry **selected, struct commit_queue_entry *first,
1245 a7f40148 2018-07-18 stsp struct commit_queue *commits, int selected_idx, int limit,
1246 8b473291 2019-02-21 stsp struct got_reflist_head *refs, const char *path, int commits_needed)
1247 0553a4e3 2018-04-30 stsp {
1248 0553a4e3 2018-04-30 stsp const struct got_error *err = NULL;
1249 52b5abe1 2019-08-13 stsp struct tog_log_view_state *s = &view->state.log;
1250 0553a4e3 2018-04-30 stsp struct commit_queue_entry *entry;
1251 60493ae3 2019-06-20 stsp int width;
1252 60493ae3 2019-06-20 stsp int ncommits, author_cols = 10;
1253 1a76625f 2018-10-22 stsp char *id_str = NULL, *header = NULL, *ncommits_str = NULL;
1254 8b473291 2019-02-21 stsp char *refs_str = NULL;
1255 ecb28ae0 2018-07-16 stsp wchar_t *wline;
1256 0553a4e3 2018-04-30 stsp
1257 e0d42f60 2018-07-22 stsp entry = first;
1258 e0d42f60 2018-07-22 stsp ncommits = 0;
1259 e0d42f60 2018-07-22 stsp while (entry) {
1260 e0d42f60 2018-07-22 stsp if (ncommits == selected_idx) {
1261 e0d42f60 2018-07-22 stsp *selected = entry;
1262 e0d42f60 2018-07-22 stsp break;
1263 e0d42f60 2018-07-22 stsp }
1264 e0d42f60 2018-07-22 stsp entry = TAILQ_NEXT(entry, entry);
1265 e0d42f60 2018-07-22 stsp ncommits++;
1266 e0d42f60 2018-07-22 stsp }
1267 e0d42f60 2018-07-22 stsp
1268 60493ae3 2019-06-20 stsp if (*selected && !(view->searching && view->search_next_done == 0)) {
1269 1a76625f 2018-10-22 stsp err = got_object_id_str(&id_str, (*selected)->id);
1270 1a76625f 2018-10-22 stsp if (err)
1271 ecb28ae0 2018-07-16 stsp return err;
1272 8b473291 2019-02-21 stsp if (refs) {
1273 52b5abe1 2019-08-13 stsp err = build_refs_str(&refs_str, refs, (*selected)->id,
1274 52b5abe1 2019-08-13 stsp s->repo);
1275 8b473291 2019-02-21 stsp if (err)
1276 8b473291 2019-02-21 stsp goto done;
1277 8b473291 2019-02-21 stsp }
1278 867c6645 2018-07-10 stsp }
1279 359bfafd 2019-02-22 stsp
1280 359bfafd 2019-02-22 stsp if (commits_needed == 0)
1281 359bfafd 2019-02-22 stsp halfdelay(10); /* disable fast refresh */
1282 1a76625f 2018-10-22 stsp
1283 8b473291 2019-02-21 stsp if (asprintf(&ncommits_str, " [%d/%d] %s",
1284 1a76625f 2018-10-22 stsp entry ? entry->idx + 1 : 0, commits->ncommits,
1285 60493ae3 2019-06-20 stsp commits_needed > 0 ?
1286 60493ae3 2019-06-20 stsp (view->searching && view->search_next_done == 0
1287 60493ae3 2019-06-20 stsp ? "searching..." : "loading... ") :
1288 8b473291 2019-02-21 stsp (refs_str ? refs_str : "")) == -1) {
1289 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
1290 8b473291 2019-02-21 stsp goto done;
1291 8b473291 2019-02-21 stsp }
1292 1a76625f 2018-10-22 stsp
1293 1a76625f 2018-10-22 stsp if (path && strcmp(path, "/") != 0) {
1294 c1124f18 2018-12-23 stsp if (asprintf(&header, "commit %s %s%s",
1295 1a76625f 2018-10-22 stsp id_str ? id_str : "........................................",
1296 1a76625f 2018-10-22 stsp path, ncommits_str) == -1) {
1297 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
1298 1a76625f 2018-10-22 stsp header = NULL;
1299 1a76625f 2018-10-22 stsp goto done;
1300 1a76625f 2018-10-22 stsp }
1301 c1124f18 2018-12-23 stsp } else if (asprintf(&header, "commit %s%s",
1302 1a76625f 2018-10-22 stsp id_str ? id_str : "........................................",
1303 1a76625f 2018-10-22 stsp ncommits_str) == -1) {
1304 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
1305 1a76625f 2018-10-22 stsp header = NULL;
1306 1a76625f 2018-10-22 stsp goto done;
1307 ecb28ae0 2018-07-16 stsp }
1308 1a76625f 2018-10-22 stsp err = format_line(&wline, &width, header, view->ncols);
1309 1a76625f 2018-10-22 stsp if (err)
1310 1a76625f 2018-10-22 stsp goto done;
1311 867c6645 2018-07-10 stsp
1312 2814baeb 2018-08-01 stsp werase(view->window);
1313 867c6645 2018-07-10 stsp
1314 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
1315 a3404814 2018-09-02 stsp wstandout(view->window);
1316 2814baeb 2018-08-01 stsp waddwstr(view->window, wline);
1317 1a76625f 2018-10-22 stsp while (width < view->ncols) {
1318 1a76625f 2018-10-22 stsp waddch(view->window, ' ');
1319 1a76625f 2018-10-22 stsp width++;
1320 1a76625f 2018-10-22 stsp }
1321 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
1322 a3404814 2018-09-02 stsp wstandend(view->window);
1323 ecb28ae0 2018-07-16 stsp free(wline);
1324 ecb28ae0 2018-07-16 stsp if (limit <= 1)
1325 1a76625f 2018-10-22 stsp goto done;
1326 0553a4e3 2018-04-30 stsp
1327 5813d178 2019-03-09 stsp /* Grow author column size if necessary. */
1328 899d86c2 2018-05-10 stsp entry = first;
1329 5813d178 2019-03-09 stsp ncommits = 0;
1330 5813d178 2019-03-09 stsp while (entry) {
1331 5813d178 2019-03-09 stsp char *author;
1332 5813d178 2019-03-09 stsp wchar_t *wauthor;
1333 5813d178 2019-03-09 stsp int width;
1334 5813d178 2019-03-09 stsp if (ncommits >= limit - 1)
1335 5813d178 2019-03-09 stsp break;
1336 5813d178 2019-03-09 stsp author = strdup(got_object_commit_get_author(entry->commit));
1337 5813d178 2019-03-09 stsp if (author == NULL) {
1338 638f9024 2019-05-13 stsp err = got_error_from_errno("strdup");
1339 5813d178 2019-03-09 stsp goto done;
1340 5813d178 2019-03-09 stsp }
1341 5813d178 2019-03-09 stsp err = format_author(&wauthor, &width, author, COLS);
1342 5813d178 2019-03-09 stsp if (author_cols < width)
1343 5813d178 2019-03-09 stsp author_cols = width;
1344 5813d178 2019-03-09 stsp free(wauthor);
1345 5813d178 2019-03-09 stsp free(author);
1346 5813d178 2019-03-09 stsp entry = TAILQ_NEXT(entry, entry);
1347 5813d178 2019-03-09 stsp }
1348 5813d178 2019-03-09 stsp
1349 5813d178 2019-03-09 stsp entry = first;
1350 899d86c2 2018-05-10 stsp *last = first;
1351 867c6645 2018-07-10 stsp ncommits = 0;
1352 899d86c2 2018-05-10 stsp while (entry) {
1353 ecb28ae0 2018-07-16 stsp if (ncommits >= limit - 1)
1354 899d86c2 2018-05-10 stsp break;
1355 b51189f7 2019-03-01 stsp if (ncommits == selected_idx)
1356 2814baeb 2018-08-01 stsp wstandout(view->window);
1357 5813d178 2019-03-09 stsp err = draw_commit(view, entry->commit, entry->id, refs,
1358 5813d178 2019-03-09 stsp author_cols);
1359 b51189f7 2019-03-01 stsp if (ncommits == selected_idx)
1360 2814baeb 2018-08-01 stsp wstandend(view->window);
1361 0553a4e3 2018-04-30 stsp if (err)
1362 60493ae3 2019-06-20 stsp goto done;
1363 0553a4e3 2018-04-30 stsp ncommits++;
1364 899d86c2 2018-05-10 stsp *last = entry;
1365 899d86c2 2018-05-10 stsp entry = TAILQ_NEXT(entry, entry);
1366 80ddbec8 2018-04-29 stsp }
1367 80ddbec8 2018-04-29 stsp
1368 1a57306a 2018-09-02 stsp view_vborder(view);
1369 1a76625f 2018-10-22 stsp done:
1370 1a76625f 2018-10-22 stsp free(id_str);
1371 8b473291 2019-02-21 stsp free(refs_str);
1372 1a76625f 2018-10-22 stsp free(ncommits_str);
1373 1a76625f 2018-10-22 stsp free(header);
1374 80ddbec8 2018-04-29 stsp return err;
1375 9f7d7167 2018-04-29 stsp }
1376 07b55e75 2018-05-10 stsp
1377 07b55e75 2018-05-10 stsp static void
1378 34bc9ec9 2019-02-22 stsp scroll_up(struct tog_view *view,
1379 34bc9ec9 2019-02-22 stsp struct commit_queue_entry **first_displayed_entry, int maxscroll,
1380 07b55e75 2018-05-10 stsp struct commit_queue *commits)
1381 07b55e75 2018-05-10 stsp {
1382 07b55e75 2018-05-10 stsp struct commit_queue_entry *entry;
1383 07b55e75 2018-05-10 stsp int nscrolled = 0;
1384 07b55e75 2018-05-10 stsp
1385 ecb28ae0 2018-07-16 stsp entry = TAILQ_FIRST(&commits->head);
1386 00ba99a7 2019-05-12 jcs if (*first_displayed_entry == entry)
1387 07b55e75 2018-05-10 stsp return;
1388 9f7d7167 2018-04-29 stsp
1389 07b55e75 2018-05-10 stsp entry = *first_displayed_entry;
1390 16482c3b 2018-05-20 stsp while (entry && nscrolled < maxscroll) {
1391 ecb28ae0 2018-07-16 stsp entry = TAILQ_PREV(entry, commit_queue_head, entry);
1392 07b55e75 2018-05-10 stsp if (entry) {
1393 07b55e75 2018-05-10 stsp *first_displayed_entry = entry;
1394 07b55e75 2018-05-10 stsp nscrolled++;
1395 07b55e75 2018-05-10 stsp }
1396 07b55e75 2018-05-10 stsp }
1397 aa075928 2018-05-10 stsp }
1398 aa075928 2018-05-10 stsp
1399 aa075928 2018-05-10 stsp static const struct got_error *
1400 5e224a3e 2019-02-22 stsp trigger_log_thread(int load_all, int *commits_needed, int *log_complete,
1401 1a76625f 2018-10-22 stsp pthread_cond_t *need_commits)
1402 aa075928 2018-05-10 stsp {
1403 5e224a3e 2019-02-22 stsp int errcode;
1404 8a42fca8 2019-02-22 stsp int max_wait = 20;
1405 8a42fca8 2019-02-22 stsp
1406 8a42fca8 2019-02-22 stsp halfdelay(1); /* fast refresh while loading commits */
1407 aa075928 2018-05-10 stsp
1408 5e224a3e 2019-02-22 stsp while (*commits_needed > 0) {
1409 5e224a3e 2019-02-22 stsp if (*log_complete)
1410 5e224a3e 2019-02-22 stsp break;
1411 b295e71b 2019-02-22 stsp
1412 5e224a3e 2019-02-22 stsp /* Wake the log thread. */
1413 7aafa0d1 2019-02-22 stsp errcode = pthread_cond_signal(need_commits);
1414 7aafa0d1 2019-02-22 stsp if (errcode)
1415 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
1416 2af4a041 2019-05-11 jcs "pthread_cond_signal");
1417 7aafa0d1 2019-02-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1418 7aafa0d1 2019-02-22 stsp if (errcode)
1419 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
1420 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
1421 7aafa0d1 2019-02-22 stsp pthread_yield();
1422 7aafa0d1 2019-02-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
1423 7aafa0d1 2019-02-22 stsp if (errcode)
1424 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
1425 2af4a041 2019-05-11 jcs "pthread_mutex_lock");
1426 5e224a3e 2019-02-22 stsp
1427 8a42fca8 2019-02-22 stsp if (*commits_needed > 0 && (!load_all || --max_wait <= 0)) {
1428 5e224a3e 2019-02-22 stsp /*
1429 5e224a3e 2019-02-22 stsp * Thread is not done yet; lose a key press
1430 5e224a3e 2019-02-22 stsp * and let the user retry... this way the GUI
1431 5e224a3e 2019-02-22 stsp * remains interactive while logging deep paths
1432 5e224a3e 2019-02-22 stsp * with few commits in history.
1433 5e224a3e 2019-02-22 stsp */
1434 7aafa0d1 2019-02-22 stsp return NULL;
1435 7aafa0d1 2019-02-22 stsp }
1436 5e224a3e 2019-02-22 stsp }
1437 5e224a3e 2019-02-22 stsp
1438 5e224a3e 2019-02-22 stsp return NULL;
1439 5e224a3e 2019-02-22 stsp }
1440 5e224a3e 2019-02-22 stsp
1441 5e224a3e 2019-02-22 stsp static const struct got_error *
1442 34bc9ec9 2019-02-22 stsp scroll_down(struct tog_view *view,
1443 34bc9ec9 2019-02-22 stsp struct commit_queue_entry **first_displayed_entry, int maxscroll,
1444 5e224a3e 2019-02-22 stsp struct commit_queue_entry **last_displayed_entry,
1445 5e224a3e 2019-02-22 stsp struct commit_queue *commits, int *log_complete, int *commits_needed,
1446 5e224a3e 2019-02-22 stsp pthread_cond_t *need_commits)
1447 5e224a3e 2019-02-22 stsp {
1448 5e224a3e 2019-02-22 stsp const struct got_error *err = NULL;
1449 5e224a3e 2019-02-22 stsp struct commit_queue_entry *pentry;
1450 5e224a3e 2019-02-22 stsp int nscrolled = 0;
1451 5e224a3e 2019-02-22 stsp
1452 5e224a3e 2019-02-22 stsp if (*last_displayed_entry == NULL)
1453 5e224a3e 2019-02-22 stsp return NULL;
1454 5e224a3e 2019-02-22 stsp
1455 5e224a3e 2019-02-22 stsp pentry = TAILQ_NEXT(*last_displayed_entry, entry);
1456 5e224a3e 2019-02-22 stsp if (pentry == NULL && !*log_complete) {
1457 08ebd0a9 2019-02-22 stsp /*
1458 08ebd0a9 2019-02-22 stsp * Ask the log thread for required amount of commits
1459 08ebd0a9 2019-02-22 stsp * plus some amount of pre-fetching.
1460 08ebd0a9 2019-02-22 stsp */
1461 08ebd0a9 2019-02-22 stsp (*commits_needed) += maxscroll + 20;
1462 5e224a3e 2019-02-22 stsp err = trigger_log_thread(0, commits_needed, log_complete,
1463 5e224a3e 2019-02-22 stsp need_commits);
1464 5e224a3e 2019-02-22 stsp if (err)
1465 5e224a3e 2019-02-22 stsp return err;
1466 7aafa0d1 2019-02-22 stsp }
1467 b295e71b 2019-02-22 stsp
1468 7aafa0d1 2019-02-22 stsp do {
1469 7226d972 2019-02-21 stsp pentry = TAILQ_NEXT(*last_displayed_entry, entry);
1470 00ba99a7 2019-05-12 jcs if (pentry == NULL)
1471 88048b54 2019-02-21 stsp break;
1472 88048b54 2019-02-21 stsp
1473 93e45b7c 2018-09-24 stsp *last_displayed_entry = pentry;
1474 aa075928 2018-05-10 stsp
1475 dd0a52c1 2018-05-20 stsp pentry = TAILQ_NEXT(*first_displayed_entry, entry);
1476 dd0a52c1 2018-05-20 stsp if (pentry == NULL)
1477 dd0a52c1 2018-05-20 stsp break;
1478 aa075928 2018-05-10 stsp *first_displayed_entry = pentry;
1479 16482c3b 2018-05-20 stsp } while (++nscrolled < maxscroll);
1480 aa075928 2018-05-10 stsp
1481 dd0a52c1 2018-05-20 stsp return err;
1482 07b55e75 2018-05-10 stsp }
1483 4a7f7875 2018-05-10 stsp
1484 cd0acaa7 2018-05-20 stsp static const struct got_error *
1485 0cf4efb1 2018-09-29 stsp open_diff_view_for_commit(struct tog_view **new_view, int begin_x,
1486 fb872ab2 2019-02-21 stsp struct got_commit_object *commit, struct got_object_id *commit_id,
1487 8b473291 2019-02-21 stsp struct tog_view *log_view, struct got_reflist_head *refs,
1488 8b473291 2019-02-21 stsp struct got_repository *repo)
1489 cd0acaa7 2018-05-20 stsp {
1490 cd0acaa7 2018-05-20 stsp const struct got_error *err;
1491 9ba79e04 2018-06-11 stsp struct got_object_qid *parent_id;
1492 e5a0f69f 2018-08-18 stsp struct tog_view *diff_view;
1493 cd0acaa7 2018-05-20 stsp
1494 669b5ffa 2018-10-07 stsp diff_view = view_open(0, 0, 0, begin_x, TOG_VIEW_DIFF);
1495 15a94983 2018-12-23 stsp if (diff_view == NULL)
1496 638f9024 2019-05-13 stsp return got_error_from_errno("view_open");
1497 ea5e7bb5 2018-08-01 stsp
1498 4acef5ee 2018-12-24 stsp parent_id = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
1499 4acef5ee 2018-12-24 stsp err = open_diff_view(diff_view, parent_id ? parent_id->id : NULL,
1500 8b473291 2019-02-21 stsp commit_id, log_view, refs, repo);
1501 e5a0f69f 2018-08-18 stsp if (err == NULL)
1502 e5a0f69f 2018-08-18 stsp *new_view = diff_view;
1503 cd0acaa7 2018-05-20 stsp return err;
1504 4a7f7875 2018-05-10 stsp }
1505 4a7f7875 2018-05-10 stsp
1506 80ddbec8 2018-04-29 stsp static const struct got_error *
1507 941e9f74 2019-05-21 stsp tree_view_visit_subtree(struct got_tree_object *subtree,
1508 941e9f74 2019-05-21 stsp struct tog_tree_view_state *s)
1509 9343a5fb 2018-06-23 stsp {
1510 941e9f74 2019-05-21 stsp struct tog_parent_tree *parent;
1511 941e9f74 2019-05-21 stsp
1512 941e9f74 2019-05-21 stsp parent = calloc(1, sizeof(*parent));
1513 941e9f74 2019-05-21 stsp if (parent == NULL)
1514 941e9f74 2019-05-21 stsp return got_error_from_errno("calloc");
1515 941e9f74 2019-05-21 stsp
1516 941e9f74 2019-05-21 stsp parent->tree = s->tree;
1517 941e9f74 2019-05-21 stsp parent->first_displayed_entry = s->first_displayed_entry;
1518 941e9f74 2019-05-21 stsp parent->selected_entry = s->selected_entry;
1519 941e9f74 2019-05-21 stsp parent->selected = s->selected;
1520 941e9f74 2019-05-21 stsp TAILQ_INSERT_HEAD(&s->parents, parent, entry);
1521 941e9f74 2019-05-21 stsp s->tree = subtree;
1522 941e9f74 2019-05-21 stsp s->entries = got_object_tree_get_entries(s->tree);
1523 941e9f74 2019-05-21 stsp s->selected = 0;
1524 941e9f74 2019-05-21 stsp s->first_displayed_entry = NULL;
1525 941e9f74 2019-05-21 stsp return NULL;
1526 941e9f74 2019-05-21 stsp }
1527 941e9f74 2019-05-21 stsp
1528 941e9f74 2019-05-21 stsp
1529 941e9f74 2019-05-21 stsp static const struct got_error *
1530 941e9f74 2019-05-21 stsp browse_commit_tree(struct tog_view **new_view, int begin_x,
1531 941e9f74 2019-05-21 stsp struct commit_queue_entry *entry, const char *path,
1532 941e9f74 2019-05-21 stsp struct got_reflist_head *refs, struct got_repository *repo)
1533 941e9f74 2019-05-21 stsp {
1534 9343a5fb 2018-06-23 stsp const struct got_error *err = NULL;
1535 9343a5fb 2018-06-23 stsp struct got_tree_object *tree;
1536 941e9f74 2019-05-21 stsp struct got_tree_entry *te;
1537 941e9f74 2019-05-21 stsp struct tog_tree_view_state *s;
1538 e5a0f69f 2018-08-18 stsp struct tog_view *tree_view;
1539 b03c880f 2019-05-21 stsp char *slash, *subpath = NULL;
1540 941e9f74 2019-05-21 stsp const char *p;
1541 9343a5fb 2018-06-23 stsp
1542 45d799e2 2018-12-23 stsp err = got_object_open_as_tree(&tree, repo,
1543 45d799e2 2018-12-23 stsp got_object_commit_get_tree_id(entry->commit));
1544 9343a5fb 2018-06-23 stsp if (err)
1545 9343a5fb 2018-06-23 stsp return err;
1546 9343a5fb 2018-06-23 stsp
1547 669b5ffa 2018-10-07 stsp tree_view = view_open(0, 0, 0, begin_x, TOG_VIEW_TREE);
1548 e5a0f69f 2018-08-18 stsp if (tree_view == NULL)
1549 638f9024 2019-05-13 stsp return got_error_from_errno("view_open");
1550 e5a0f69f 2018-08-18 stsp
1551 8b473291 2019-02-21 stsp err = open_tree_view(tree_view, tree, entry->id, refs, repo);
1552 941e9f74 2019-05-21 stsp if (err) {
1553 e5a0f69f 2018-08-18 stsp got_object_tree_close(tree);
1554 941e9f74 2019-05-21 stsp return err;
1555 941e9f74 2019-05-21 stsp }
1556 941e9f74 2019-05-21 stsp s = &tree_view->state.tree;
1557 941e9f74 2019-05-21 stsp
1558 941e9f74 2019-05-21 stsp *new_view = tree_view;
1559 941e9f74 2019-05-21 stsp
1560 941e9f74 2019-05-21 stsp /* Walk the path and open corresponding tree objects. */
1561 941e9f74 2019-05-21 stsp p = path;
1562 8d0fe45a 2019-08-12 stsp while (p[0] == '/')
1563 8d0fe45a 2019-08-12 stsp p++;
1564 941e9f74 2019-05-21 stsp while (*p) {
1565 941e9f74 2019-05-21 stsp struct got_object_id *tree_id;
1566 941e9f74 2019-05-21 stsp
1567 941e9f74 2019-05-21 stsp /* Ensure the correct subtree entry is selected. */
1568 941e9f74 2019-05-21 stsp slash = strchr(p, '/');
1569 941e9f74 2019-05-21 stsp if (slash == NULL)
1570 941e9f74 2019-05-21 stsp slash = strchr(p, '\0');
1571 941e9f74 2019-05-21 stsp SIMPLEQ_FOREACH(te, &s->entries->head, entry) {
1572 941e9f74 2019-05-21 stsp if (strncmp(p, te->name, slash - p) == 0) {
1573 941e9f74 2019-05-21 stsp s->selected_entry = te;
1574 941e9f74 2019-05-21 stsp break;
1575 941e9f74 2019-05-21 stsp }
1576 b03c880f 2019-05-21 stsp s->selected++;
1577 941e9f74 2019-05-21 stsp }
1578 941e9f74 2019-05-21 stsp if (s->selected_entry == NULL) {
1579 941e9f74 2019-05-21 stsp err = got_error(GOT_ERR_NO_TREE_ENTRY);
1580 941e9f74 2019-05-21 stsp break;
1581 941e9f74 2019-05-21 stsp }
1582 b03c880f 2019-05-21 stsp if (s->tree != s->root)
1583 b03c880f 2019-05-21 stsp s->selected++; /* skip '..' */
1584 941e9f74 2019-05-21 stsp
1585 67409a31 2019-05-24 stsp if (!S_ISDIR(s->selected_entry->mode)) {
1586 67409a31 2019-05-24 stsp /* Jump to this file's entry. */
1587 67409a31 2019-05-24 stsp s->first_displayed_entry = s->selected_entry;
1588 67409a31 2019-05-24 stsp s->selected = 0;
1589 b03c880f 2019-05-21 stsp break;
1590 67409a31 2019-05-24 stsp }
1591 b03c880f 2019-05-21 stsp
1592 941e9f74 2019-05-21 stsp slash = strchr(p, '/');
1593 941e9f74 2019-05-21 stsp if (slash)
1594 941e9f74 2019-05-21 stsp subpath = strndup(path, slash - path);
1595 941e9f74 2019-05-21 stsp else
1596 941e9f74 2019-05-21 stsp subpath = strdup(path);
1597 941e9f74 2019-05-21 stsp if (subpath == NULL) {
1598 941e9f74 2019-05-21 stsp err = got_error_from_errno("strdup");
1599 941e9f74 2019-05-21 stsp break;
1600 941e9f74 2019-05-21 stsp }
1601 941e9f74 2019-05-21 stsp
1602 941e9f74 2019-05-21 stsp err = got_object_id_by_path(&tree_id, repo, entry->id,
1603 941e9f74 2019-05-21 stsp subpath);
1604 941e9f74 2019-05-21 stsp if (err)
1605 941e9f74 2019-05-21 stsp break;
1606 941e9f74 2019-05-21 stsp
1607 941e9f74 2019-05-21 stsp err = got_object_open_as_tree(&tree, repo, tree_id);
1608 941e9f74 2019-05-21 stsp free(tree_id);
1609 941e9f74 2019-05-21 stsp if (err)
1610 941e9f74 2019-05-21 stsp break;
1611 941e9f74 2019-05-21 stsp
1612 941e9f74 2019-05-21 stsp err = tree_view_visit_subtree(tree, s);
1613 941e9f74 2019-05-21 stsp if (err) {
1614 941e9f74 2019-05-21 stsp got_object_tree_close(tree);
1615 941e9f74 2019-05-21 stsp break;
1616 941e9f74 2019-05-21 stsp }
1617 941e9f74 2019-05-21 stsp if (slash == NULL)
1618 941e9f74 2019-05-21 stsp break;
1619 941e9f74 2019-05-21 stsp free(subpath);
1620 941e9f74 2019-05-21 stsp subpath = NULL;
1621 941e9f74 2019-05-21 stsp p = slash;
1622 941e9f74 2019-05-21 stsp }
1623 941e9f74 2019-05-21 stsp
1624 941e9f74 2019-05-21 stsp free(subpath);
1625 1a76625f 2018-10-22 stsp return err;
1626 1a76625f 2018-10-22 stsp }
1627 1a76625f 2018-10-22 stsp
1628 1a76625f 2018-10-22 stsp static void *
1629 1a76625f 2018-10-22 stsp log_thread(void *arg)
1630 1a76625f 2018-10-22 stsp {
1631 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
1632 1a76625f 2018-10-22 stsp int errcode = 0;
1633 1a76625f 2018-10-22 stsp struct tog_log_thread_args *a = arg;
1634 1a76625f 2018-10-22 stsp int done = 0;
1635 1a76625f 2018-10-22 stsp
1636 1a76625f 2018-10-22 stsp err = got_commit_graph_iter_start(a->graph, a->start_id, a->repo);
1637 1a76625f 2018-10-22 stsp if (err)
1638 1a76625f 2018-10-22 stsp return (void *)err;
1639 1a76625f 2018-10-22 stsp
1640 d264cece 2019-08-12 stsp while (!done && !err && !tog_sigpipe_received) {
1641 1a76625f 2018-10-22 stsp err = queue_commits(a->graph, a->commits, 1, a->repo,
1642 1a76625f 2018-10-22 stsp a->in_repo_path);
1643 1a76625f 2018-10-22 stsp if (err) {
1644 1a76625f 2018-10-22 stsp if (err->code != GOT_ERR_ITER_COMPLETED)
1645 1a76625f 2018-10-22 stsp return (void *)err;
1646 1a76625f 2018-10-22 stsp err = NULL;
1647 1a76625f 2018-10-22 stsp done = 1;
1648 1a76625f 2018-10-22 stsp } else if (a->commits_needed > 0)
1649 1a76625f 2018-10-22 stsp a->commits_needed--;
1650 1a76625f 2018-10-22 stsp
1651 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
1652 3abe8080 2019-04-10 stsp if (errcode) {
1653 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode,
1654 2af4a041 2019-05-11 jcs "pthread_mutex_lock");
1655 3abe8080 2019-04-10 stsp break;
1656 3abe8080 2019-04-10 stsp } else if (*a->quit)
1657 1a76625f 2018-10-22 stsp done = 1;
1658 3abe8080 2019-04-10 stsp else if (*a->first_displayed_entry == NULL) {
1659 1a76625f 2018-10-22 stsp *a->first_displayed_entry =
1660 1a76625f 2018-10-22 stsp TAILQ_FIRST(&a->commits->head);
1661 1a76625f 2018-10-22 stsp *a->selected_entry = *a->first_displayed_entry;
1662 1a76625f 2018-10-22 stsp }
1663 1a76625f 2018-10-22 stsp
1664 1a76625f 2018-10-22 stsp if (done)
1665 1a76625f 2018-10-22 stsp a->commits_needed = 0;
1666 1a76625f 2018-10-22 stsp else if (a->commits_needed == 0) {
1667 1a76625f 2018-10-22 stsp errcode = pthread_cond_wait(&a->need_commits,
1668 1a76625f 2018-10-22 stsp &tog_mutex);
1669 1a76625f 2018-10-22 stsp if (errcode)
1670 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode,
1671 2af4a041 2019-05-11 jcs "pthread_cond_wait");
1672 1a76625f 2018-10-22 stsp }
1673 1a76625f 2018-10-22 stsp
1674 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1675 1a76625f 2018-10-22 stsp if (errcode && err == NULL)
1676 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode,
1677 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
1678 1a76625f 2018-10-22 stsp }
1679 3abe8080 2019-04-10 stsp a->log_complete = 1;
1680 1a76625f 2018-10-22 stsp return (void *)err;
1681 1a76625f 2018-10-22 stsp }
1682 1a76625f 2018-10-22 stsp
1683 1a76625f 2018-10-22 stsp static const struct got_error *
1684 1a76625f 2018-10-22 stsp stop_log_thread(struct tog_log_view_state *s)
1685 1a76625f 2018-10-22 stsp {
1686 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
1687 1a76625f 2018-10-22 stsp int errcode;
1688 1a76625f 2018-10-22 stsp
1689 1a76625f 2018-10-22 stsp if (s->thread) {
1690 1a76625f 2018-10-22 stsp s->quit = 1;
1691 1a76625f 2018-10-22 stsp errcode = pthread_cond_signal(&s->thread_args.need_commits);
1692 1a76625f 2018-10-22 stsp if (errcode)
1693 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
1694 2af4a041 2019-05-11 jcs "pthread_cond_signal");
1695 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
1696 1a76625f 2018-10-22 stsp if (errcode)
1697 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
1698 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
1699 1a76625f 2018-10-22 stsp errcode = pthread_join(s->thread, (void **)&err);
1700 1a76625f 2018-10-22 stsp if (errcode)
1701 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_join");
1702 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
1703 1a76625f 2018-10-22 stsp if (errcode)
1704 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
1705 2af4a041 2019-05-11 jcs "pthread_mutex_lock");
1706 1a76625f 2018-10-22 stsp s->thread = NULL;
1707 1a76625f 2018-10-22 stsp }
1708 1a76625f 2018-10-22 stsp
1709 1a76625f 2018-10-22 stsp errcode = pthread_cond_destroy(&s->thread_args.need_commits);
1710 1a76625f 2018-10-22 stsp if (errcode && err == NULL)
1711 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode, "pthread_cond_destroy");
1712 1a76625f 2018-10-22 stsp
1713 1a76625f 2018-10-22 stsp if (s->thread_args.repo) {
1714 1a76625f 2018-10-22 stsp got_repo_close(s->thread_args.repo);
1715 1a76625f 2018-10-22 stsp s->thread_args.repo = NULL;
1716 1a76625f 2018-10-22 stsp }
1717 1a76625f 2018-10-22 stsp
1718 1a76625f 2018-10-22 stsp if (s->thread_args.graph) {
1719 1a76625f 2018-10-22 stsp got_commit_graph_close(s->thread_args.graph);
1720 1a76625f 2018-10-22 stsp s->thread_args.graph = NULL;
1721 1a76625f 2018-10-22 stsp }
1722 1a76625f 2018-10-22 stsp
1723 9343a5fb 2018-06-23 stsp return err;
1724 9343a5fb 2018-06-23 stsp }
1725 9343a5fb 2018-06-23 stsp
1726 9343a5fb 2018-06-23 stsp static const struct got_error *
1727 1a76625f 2018-10-22 stsp close_log_view(struct tog_view *view)
1728 1a76625f 2018-10-22 stsp {
1729 1a76625f 2018-10-22 stsp const struct got_error *err = NULL;
1730 1a76625f 2018-10-22 stsp struct tog_log_view_state *s = &view->state.log;
1731 1a76625f 2018-10-22 stsp
1732 1a76625f 2018-10-22 stsp err = stop_log_thread(s);
1733 1a76625f 2018-10-22 stsp free_commits(&s->commits);
1734 1a76625f 2018-10-22 stsp free(s->in_repo_path);
1735 797bc7b9 2018-10-22 stsp s->in_repo_path = NULL;
1736 1a76625f 2018-10-22 stsp free(s->start_id);
1737 797bc7b9 2018-10-22 stsp s->start_id = NULL;
1738 1a76625f 2018-10-22 stsp return err;
1739 1a76625f 2018-10-22 stsp }
1740 1a76625f 2018-10-22 stsp
1741 1a76625f 2018-10-22 stsp static const struct got_error *
1742 60493ae3 2019-06-20 stsp search_start_log_view(struct tog_view *view)
1743 60493ae3 2019-06-20 stsp {
1744 60493ae3 2019-06-20 stsp struct tog_log_view_state *s = &view->state.log;
1745 60493ae3 2019-06-20 stsp
1746 60493ae3 2019-06-20 stsp s->matched_entry = NULL;
1747 96e2b566 2019-07-08 stsp s->search_entry = NULL;
1748 60493ae3 2019-06-20 stsp return NULL;
1749 60493ae3 2019-06-20 stsp }
1750 60493ae3 2019-06-20 stsp
1751 60493ae3 2019-06-20 stsp static int
1752 df0b3d8a 2019-06-28 stsp match_commit(struct got_commit_object *commit, const char *id_str,
1753 5943eee2 2019-08-13 stsp const char *logmsg, regex_t *regex)
1754 60493ae3 2019-06-20 stsp {
1755 60493ae3 2019-06-20 stsp regmatch_t regmatch;
1756 60493ae3 2019-06-20 stsp
1757 60493ae3 2019-06-20 stsp if (regexec(regex, got_object_commit_get_author(commit), 1,
1758 60493ae3 2019-06-20 stsp &regmatch, 0) == 0 ||
1759 60493ae3 2019-06-20 stsp regexec(regex, got_object_commit_get_committer(commit), 1,
1760 60493ae3 2019-06-20 stsp &regmatch, 0) == 0 ||
1761 5943eee2 2019-08-13 stsp regexec(regex, id_str, 1, &regmatch, 0) == 0 ||
1762 5943eee2 2019-08-13 stsp regexec(regex, logmsg, 1, &regmatch, 0) == 0)
1763 60493ae3 2019-06-20 stsp return 1;
1764 60493ae3 2019-06-20 stsp
1765 60493ae3 2019-06-20 stsp return 0;
1766 60493ae3 2019-06-20 stsp }
1767 60493ae3 2019-06-20 stsp
1768 60493ae3 2019-06-20 stsp static const struct got_error *
1769 60493ae3 2019-06-20 stsp search_next_log_view(struct tog_view *view)
1770 60493ae3 2019-06-20 stsp {
1771 60493ae3 2019-06-20 stsp const struct got_error *err = NULL;
1772 60493ae3 2019-06-20 stsp struct tog_log_view_state *s = &view->state.log;
1773 60493ae3 2019-06-20 stsp struct commit_queue_entry *entry;
1774 60493ae3 2019-06-20 stsp
1775 60493ae3 2019-06-20 stsp if (!view->searching) {
1776 60493ae3 2019-06-20 stsp view->search_next_done = 1;
1777 60493ae3 2019-06-20 stsp return NULL;
1778 60493ae3 2019-06-20 stsp }
1779 60493ae3 2019-06-20 stsp
1780 96e2b566 2019-07-08 stsp if (s->search_entry) {
1781 678cbce5 2019-07-28 stsp if (wgetch(view->window) == KEY_BACKSPACE) {
1782 678cbce5 2019-07-28 stsp view->search_next_done = 1;
1783 678cbce5 2019-07-28 stsp return NULL;
1784 678cbce5 2019-07-28 stsp }
1785 96e2b566 2019-07-08 stsp if (view->searching == TOG_SEARCH_FORWARD)
1786 96e2b566 2019-07-08 stsp entry = TAILQ_NEXT(s->search_entry, entry);
1787 96e2b566 2019-07-08 stsp else
1788 96e2b566 2019-07-08 stsp entry = TAILQ_PREV(s->search_entry,
1789 96e2b566 2019-07-08 stsp commit_queue_head, entry);
1790 96e2b566 2019-07-08 stsp } else if (s->matched_entry) {
1791 b1bf1435 2019-06-21 stsp if (view->searching == TOG_SEARCH_FORWARD)
1792 b55df7bc 2019-06-21 stsp entry = TAILQ_NEXT(s->selected_entry, entry);
1793 b1bf1435 2019-06-21 stsp else
1794 b55df7bc 2019-06-21 stsp entry = TAILQ_PREV(s->selected_entry,
1795 b1bf1435 2019-06-21 stsp commit_queue_head, entry);
1796 20be8d96 2019-06-21 stsp } else {
1797 20be8d96 2019-06-21 stsp if (view->searching == TOG_SEARCH_FORWARD)
1798 20be8d96 2019-06-21 stsp entry = TAILQ_FIRST(&s->commits.head);
1799 20be8d96 2019-06-21 stsp else
1800 20be8d96 2019-06-21 stsp entry = TAILQ_LAST(&s->commits.head, commit_queue_head);
1801 20be8d96 2019-06-21 stsp }
1802 60493ae3 2019-06-20 stsp
1803 60493ae3 2019-06-20 stsp while (1) {
1804 5943eee2 2019-08-13 stsp char *id_str, *logmsg;
1805 60493ae3 2019-06-20 stsp if (entry == NULL) {
1806 f801134a 2019-06-25 stsp if (s->thread_args.log_complete ||
1807 f801134a 2019-06-25 stsp view->searching == TOG_SEARCH_BACKWARD) {
1808 f801134a 2019-06-25 stsp view->search_next_done = 1;
1809 f801134a 2019-06-25 stsp return NULL;
1810 60493ae3 2019-06-20 stsp }
1811 96e2b566 2019-07-08 stsp /*
1812 96e2b566 2019-07-08 stsp * Poke the log thread for more commits and return,
1813 96e2b566 2019-07-08 stsp * allowing the main loop to make progress. Search
1814 96e2b566 2019-07-08 stsp * will resume at s->search_entry once we come back.
1815 96e2b566 2019-07-08 stsp */
1816 57b33b64 2019-07-08 stsp s->thread_args.commits_needed++;
1817 57b33b64 2019-07-08 stsp return trigger_log_thread(1,
1818 f801134a 2019-06-25 stsp &s->thread_args.commits_needed,
1819 f801134a 2019-06-25 stsp &s->thread_args.log_complete,
1820 f801134a 2019-06-25 stsp &s->thread_args.need_commits);
1821 60493ae3 2019-06-20 stsp }
1822 60493ae3 2019-06-20 stsp
1823 df0b3d8a 2019-06-28 stsp err = got_object_id_str(&id_str, entry->id);
1824 df0b3d8a 2019-06-28 stsp if (err)
1825 df0b3d8a 2019-06-28 stsp return err;
1826 df0b3d8a 2019-06-28 stsp
1827 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg, entry->commit);
1828 5943eee2 2019-08-13 stsp if (err)
1829 5943eee2 2019-08-13 stsp return err;
1830 5943eee2 2019-08-13 stsp if (match_commit(entry->commit, id_str, logmsg, &view->regex)) {
1831 5943eee2 2019-08-13 stsp free(logmsg);
1832 60493ae3 2019-06-20 stsp view->search_next_done = 1;
1833 bcf2df4d 2019-06-21 stsp s->matched_entry = entry;
1834 df0b3d8a 2019-06-28 stsp free(id_str);
1835 60493ae3 2019-06-20 stsp break;
1836 60493ae3 2019-06-20 stsp }
1837 5943eee2 2019-08-13 stsp free(logmsg);
1838 df0b3d8a 2019-06-28 stsp free(id_str);
1839 96e2b566 2019-07-08 stsp s->search_entry = entry;
1840 b1bf1435 2019-06-21 stsp if (view->searching == TOG_SEARCH_FORWARD)
1841 b1bf1435 2019-06-21 stsp entry = TAILQ_NEXT(entry, entry);
1842 b1bf1435 2019-06-21 stsp else
1843 b1bf1435 2019-06-21 stsp entry = TAILQ_PREV(entry, commit_queue_head, entry);
1844 60493ae3 2019-06-20 stsp }
1845 60493ae3 2019-06-20 stsp
1846 bcf2df4d 2019-06-21 stsp if (s->matched_entry) {
1847 ead14cbe 2019-06-21 stsp int cur = s->selected_entry->idx;
1848 ead14cbe 2019-06-21 stsp while (cur < s->matched_entry->idx) {
1849 60493ae3 2019-06-20 stsp err = input_log_view(NULL, NULL, NULL, view, KEY_DOWN);
1850 60493ae3 2019-06-20 stsp if (err)
1851 60493ae3 2019-06-20 stsp return err;
1852 ead14cbe 2019-06-21 stsp cur++;
1853 ead14cbe 2019-06-21 stsp }
1854 ead14cbe 2019-06-21 stsp while (cur > s->matched_entry->idx) {
1855 ead14cbe 2019-06-21 stsp err = input_log_view(NULL, NULL, NULL, view, KEY_UP);
1856 60493ae3 2019-06-20 stsp if (err)
1857 60493ae3 2019-06-20 stsp return err;
1858 ead14cbe 2019-06-21 stsp cur--;
1859 60493ae3 2019-06-20 stsp }
1860 60493ae3 2019-06-20 stsp }
1861 60493ae3 2019-06-20 stsp
1862 96e2b566 2019-07-08 stsp s->search_entry = NULL;
1863 96e2b566 2019-07-08 stsp
1864 60493ae3 2019-06-20 stsp return NULL;
1865 60493ae3 2019-06-20 stsp }
1866 60493ae3 2019-06-20 stsp
1867 60493ae3 2019-06-20 stsp static const struct got_error *
1868 ba4f502b 2018-08-04 stsp open_log_view(struct tog_view *view, struct got_object_id *start_id,
1869 8b473291 2019-02-21 stsp struct got_reflist_head *refs, struct got_repository *repo,
1870 d01904d4 2019-06-25 stsp const char *head_ref_name, const char *path, int check_disk)
1871 80ddbec8 2018-04-29 stsp {
1872 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
1873 fb2756b9 2018-08-04 stsp struct tog_log_view_state *s = &view->state.log;
1874 1a76625f 2018-10-22 stsp struct got_repository *thread_repo = NULL;
1875 1a76625f 2018-10-22 stsp struct got_commit_graph *thread_graph = NULL;
1876 1a76625f 2018-10-22 stsp int errcode;
1877 80ddbec8 2018-04-29 stsp
1878 23721109 2018-10-22 stsp err = got_repo_map_path(&s->in_repo_path, repo, path, check_disk);
1879 ecb28ae0 2018-07-16 stsp if (err != NULL)
1880 ecb28ae0 2018-07-16 stsp goto done;
1881 ecb28ae0 2018-07-16 stsp
1882 93e45b7c 2018-09-24 stsp /* The commit queue only contains commits being displayed. */
1883 fb2756b9 2018-08-04 stsp TAILQ_INIT(&s->commits.head);
1884 fb2756b9 2018-08-04 stsp s->commits.ncommits = 0;
1885 9ba79e04 2018-06-11 stsp
1886 8b473291 2019-02-21 stsp s->refs = refs;
1887 fb2756b9 2018-08-04 stsp s->repo = repo;
1888 d01904d4 2019-06-25 stsp s->head_ref_name = head_ref_name;
1889 5036bf37 2018-09-24 stsp s->start_id = got_object_id_dup(start_id);
1890 5036bf37 2018-09-24 stsp if (s->start_id == NULL) {
1891 638f9024 2019-05-13 stsp err = got_error_from_errno("got_object_id_dup");
1892 5036bf37 2018-09-24 stsp goto done;
1893 5036bf37 2018-09-24 stsp }
1894 e5a0f69f 2018-08-18 stsp
1895 e5a0f69f 2018-08-18 stsp view->show = show_log_view;
1896 e5a0f69f 2018-08-18 stsp view->input = input_log_view;
1897 e5a0f69f 2018-08-18 stsp view->close = close_log_view;
1898 60493ae3 2019-06-20 stsp view->search_start = search_start_log_view;
1899 60493ae3 2019-06-20 stsp view->search_next = search_next_log_view;
1900 1a76625f 2018-10-22 stsp
1901 1a76625f 2018-10-22 stsp err = got_repo_open(&thread_repo, got_repo_get_path(repo));
1902 1a76625f 2018-10-22 stsp if (err)
1903 1a76625f 2018-10-22 stsp goto done;
1904 1a76625f 2018-10-22 stsp err = got_commit_graph_open(&thread_graph, start_id, s->in_repo_path,
1905 1a76625f 2018-10-22 stsp 0, thread_repo);
1906 1a76625f 2018-10-22 stsp if (err)
1907 1a76625f 2018-10-22 stsp goto done;
1908 1a76625f 2018-10-22 stsp
1909 1a76625f 2018-10-22 stsp errcode = pthread_cond_init(&s->thread_args.need_commits, NULL);
1910 1a76625f 2018-10-22 stsp if (errcode) {
1911 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode, "pthread_cond_init");
1912 1a76625f 2018-10-22 stsp goto done;
1913 1a76625f 2018-10-22 stsp }
1914 1a76625f 2018-10-22 stsp
1915 1a76625f 2018-10-22 stsp s->thread_args.commits_needed = view->nlines;
1916 1a76625f 2018-10-22 stsp s->thread_args.graph = thread_graph;
1917 1a76625f 2018-10-22 stsp s->thread_args.commits = &s->commits;
1918 1a76625f 2018-10-22 stsp s->thread_args.in_repo_path = s->in_repo_path;
1919 1a76625f 2018-10-22 stsp s->thread_args.start_id = s->start_id;
1920 1a76625f 2018-10-22 stsp s->thread_args.repo = thread_repo;
1921 1a76625f 2018-10-22 stsp s->thread_args.log_complete = 0;
1922 1a76625f 2018-10-22 stsp s->thread_args.quit = &s->quit;
1923 1a76625f 2018-10-22 stsp s->thread_args.view = view;
1924 1a76625f 2018-10-22 stsp s->thread_args.first_displayed_entry = &s->first_displayed_entry;
1925 1a76625f 2018-10-22 stsp s->thread_args.selected_entry = &s->selected_entry;
1926 ba4f502b 2018-08-04 stsp done:
1927 1a76625f 2018-10-22 stsp if (err)
1928 1a76625f 2018-10-22 stsp close_log_view(view);
1929 ba4f502b 2018-08-04 stsp return err;
1930 ba4f502b 2018-08-04 stsp }
1931 ba4f502b 2018-08-04 stsp
1932 e5a0f69f 2018-08-18 stsp static const struct got_error *
1933 ba4f502b 2018-08-04 stsp show_log_view(struct tog_view *view)
1934 ba4f502b 2018-08-04 stsp {
1935 fb2756b9 2018-08-04 stsp struct tog_log_view_state *s = &view->state.log;
1936 ba4f502b 2018-08-04 stsp
1937 2b380cc8 2018-10-24 stsp if (s->thread == NULL) {
1938 2b380cc8 2018-10-24 stsp int errcode = pthread_create(&s->thread, NULL, log_thread,
1939 2b380cc8 2018-10-24 stsp &s->thread_args);
1940 2b380cc8 2018-10-24 stsp if (errcode)
1941 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_create");
1942 2b380cc8 2018-10-24 stsp }
1943 2b380cc8 2018-10-24 stsp
1944 0cf4efb1 2018-09-29 stsp return draw_commits(view, &s->last_displayed_entry,
1945 e5a0f69f 2018-08-18 stsp &s->selected_entry, s->first_displayed_entry,
1946 8b473291 2019-02-21 stsp &s->commits, s->selected, view->nlines, s->refs,
1947 1a76625f 2018-10-22 stsp s->in_repo_path, s->thread_args.commits_needed);
1948 e5a0f69f 2018-08-18 stsp }
1949 04cc582a 2018-08-01 stsp
1950 e5a0f69f 2018-08-18 stsp static const struct got_error *
1951 e5a0f69f 2018-08-18 stsp input_log_view(struct tog_view **new_view, struct tog_view **dead_view,
1952 878940b7 2018-09-29 stsp struct tog_view **focus_view, struct tog_view *view, int ch)
1953 e5a0f69f 2018-08-18 stsp {
1954 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
1955 e5a0f69f 2018-08-18 stsp struct tog_log_view_state *s = &view->state.log;
1956 d01904d4 2019-06-25 stsp char *parent_path, *in_repo_path = NULL;
1957 d01904d4 2019-06-25 stsp struct tog_view *diff_view = NULL, *tree_view = NULL, *lv = NULL;
1958 669b5ffa 2018-10-07 stsp int begin_x = 0;
1959 d01904d4 2019-06-25 stsp struct got_object_id *start_id;
1960 80ddbec8 2018-04-29 stsp
1961 e5a0f69f 2018-08-18 stsp switch (ch) {
1962 1e37a5c2 2019-05-12 jcs case 'q':
1963 1e37a5c2 2019-05-12 jcs s->quit = 1;
1964 1e37a5c2 2019-05-12 jcs break;
1965 1e37a5c2 2019-05-12 jcs case 'k':
1966 1e37a5c2 2019-05-12 jcs case KEY_UP:
1967 1e37a5c2 2019-05-12 jcs case '<':
1968 1e37a5c2 2019-05-12 jcs case ',':
1969 1e37a5c2 2019-05-12 jcs if (s->first_displayed_entry == NULL)
1970 1a76625f 2018-10-22 stsp break;
1971 1e37a5c2 2019-05-12 jcs if (s->selected > 0)
1972 1e37a5c2 2019-05-12 jcs s->selected--;
1973 1144d21a 2019-06-21 stsp else
1974 1144d21a 2019-06-21 stsp scroll_up(view, &s->first_displayed_entry, 1,
1975 1144d21a 2019-06-21 stsp &s->commits);
1976 1e37a5c2 2019-05-12 jcs break;
1977 1e37a5c2 2019-05-12 jcs case KEY_PPAGE:
1978 a4292ac5 2019-05-12 jcs case CTRL('b'):
1979 1e37a5c2 2019-05-12 jcs if (s->first_displayed_entry == NULL)
1980 e5a0f69f 2018-08-18 stsp break;
1981 1e37a5c2 2019-05-12 jcs if (TAILQ_FIRST(&s->commits.head) ==
1982 1e37a5c2 2019-05-12 jcs s->first_displayed_entry) {
1983 1e37a5c2 2019-05-12 jcs s->selected = 0;
1984 e5a0f69f 2018-08-18 stsp break;
1985 1e37a5c2 2019-05-12 jcs }
1986 1e37a5c2 2019-05-12 jcs scroll_up(view, &s->first_displayed_entry,
1987 1e37a5c2 2019-05-12 jcs view->nlines, &s->commits);
1988 1e37a5c2 2019-05-12 jcs break;
1989 1e37a5c2 2019-05-12 jcs case 'j':
1990 1e37a5c2 2019-05-12 jcs case KEY_DOWN:
1991 1e37a5c2 2019-05-12 jcs case '>':
1992 1e37a5c2 2019-05-12 jcs case '.':
1993 1e37a5c2 2019-05-12 jcs if (s->first_displayed_entry == NULL)
1994 e5a0f69f 2018-08-18 stsp break;
1995 1e37a5c2 2019-05-12 jcs if (s->selected < MIN(view->nlines - 2,
1996 1e37a5c2 2019-05-12 jcs s->commits.ncommits - 1)) {
1997 1e37a5c2 2019-05-12 jcs s->selected++;
1998 1e37a5c2 2019-05-12 jcs break;
1999 80ddbec8 2018-04-29 stsp }
2000 1e37a5c2 2019-05-12 jcs err = scroll_down(view, &s->first_displayed_entry, 1,
2001 1e37a5c2 2019-05-12 jcs &s->last_displayed_entry, &s->commits,
2002 1e37a5c2 2019-05-12 jcs &s->thread_args.log_complete,
2003 1e37a5c2 2019-05-12 jcs &s->thread_args.commits_needed,
2004 1e37a5c2 2019-05-12 jcs &s->thread_args.need_commits);
2005 1e37a5c2 2019-05-12 jcs break;
2006 a4292ac5 2019-05-12 jcs case KEY_NPAGE:
2007 a4292ac5 2019-05-12 jcs case CTRL('f'): {
2008 1e37a5c2 2019-05-12 jcs struct commit_queue_entry *first;
2009 1e37a5c2 2019-05-12 jcs first = s->first_displayed_entry;
2010 1e37a5c2 2019-05-12 jcs if (first == NULL)
2011 e5a0f69f 2018-08-18 stsp break;
2012 1e37a5c2 2019-05-12 jcs err = scroll_down(view, &s->first_displayed_entry,
2013 1e37a5c2 2019-05-12 jcs view->nlines, &s->last_displayed_entry,
2014 1e37a5c2 2019-05-12 jcs &s->commits, &s->thread_args.log_complete,
2015 1e37a5c2 2019-05-12 jcs &s->thread_args.commits_needed,
2016 1e37a5c2 2019-05-12 jcs &s->thread_args.need_commits);
2017 1e37a5c2 2019-05-12 jcs if (first == s->first_displayed_entry &&
2018 1e37a5c2 2019-05-12 jcs s->selected < MIN(view->nlines - 2,
2019 1e37a5c2 2019-05-12 jcs s->commits.ncommits - 1)) {
2020 1e37a5c2 2019-05-12 jcs /* can't scroll further down */
2021 1e37a5c2 2019-05-12 jcs s->selected = MIN(view->nlines - 2,
2022 1e37a5c2 2019-05-12 jcs s->commits.ncommits - 1);
2023 1e37a5c2 2019-05-12 jcs }
2024 1e37a5c2 2019-05-12 jcs err = NULL;
2025 1e37a5c2 2019-05-12 jcs break;
2026 1e37a5c2 2019-05-12 jcs }
2027 1e37a5c2 2019-05-12 jcs case KEY_RESIZE:
2028 1e37a5c2 2019-05-12 jcs if (s->selected > view->nlines - 2)
2029 1e37a5c2 2019-05-12 jcs s->selected = view->nlines - 2;
2030 1e37a5c2 2019-05-12 jcs if (s->selected > s->commits.ncommits - 1)
2031 1e37a5c2 2019-05-12 jcs s->selected = s->commits.ncommits - 1;
2032 1e37a5c2 2019-05-12 jcs break;
2033 1e37a5c2 2019-05-12 jcs case KEY_ENTER:
2034 87c7274c 2019-05-12 jcs case ' ':
2035 1e37a5c2 2019-05-12 jcs case '\r':
2036 1e37a5c2 2019-05-12 jcs if (s->selected_entry == NULL)
2037 e5a0f69f 2018-08-18 stsp break;
2038 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view))
2039 1e37a5c2 2019-05-12 jcs begin_x = view_split_begin_x(view->begin_x);
2040 1e37a5c2 2019-05-12 jcs err = open_diff_view_for_commit(&diff_view, begin_x,
2041 1e37a5c2 2019-05-12 jcs s->selected_entry->commit, s->selected_entry->id,
2042 1e37a5c2 2019-05-12 jcs view, s->refs, s->repo);
2043 1e37a5c2 2019-05-12 jcs if (err)
2044 1e37a5c2 2019-05-12 jcs break;
2045 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view)) {
2046 1e37a5c2 2019-05-12 jcs err = view_close_child(view);
2047 f7013a22 2018-10-24 stsp if (err)
2048 1e37a5c2 2019-05-12 jcs return err;
2049 1e37a5c2 2019-05-12 jcs err = view_set_child(view, diff_view);
2050 1e37a5c2 2019-05-12 jcs if (err) {
2051 1e37a5c2 2019-05-12 jcs view_close(diff_view);
2052 f7013a22 2018-10-24 stsp break;
2053 5036bf37 2018-09-24 stsp }
2054 1e37a5c2 2019-05-12 jcs *focus_view = diff_view;
2055 1e37a5c2 2019-05-12 jcs view->child_focussed = 1;
2056 1e37a5c2 2019-05-12 jcs } else
2057 1e37a5c2 2019-05-12 jcs *new_view = diff_view;
2058 1e37a5c2 2019-05-12 jcs break;
2059 1e37a5c2 2019-05-12 jcs case 't':
2060 1e37a5c2 2019-05-12 jcs if (s->selected_entry == NULL)
2061 5036bf37 2018-09-24 stsp break;
2062 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view))
2063 1e37a5c2 2019-05-12 jcs begin_x = view_split_begin_x(view->begin_x);
2064 941e9f74 2019-05-21 stsp err = browse_commit_tree(&tree_view, begin_x,
2065 941e9f74 2019-05-21 stsp s->selected_entry, s->in_repo_path, s->refs, s->repo);
2066 1e37a5c2 2019-05-12 jcs if (err)
2067 e5a0f69f 2018-08-18 stsp break;
2068 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view)) {
2069 1e37a5c2 2019-05-12 jcs err = view_close_child(view);
2070 1e37a5c2 2019-05-12 jcs if (err)
2071 1e37a5c2 2019-05-12 jcs return err;
2072 1e37a5c2 2019-05-12 jcs err = view_set_child(view, tree_view);
2073 1e37a5c2 2019-05-12 jcs if (err) {
2074 1e37a5c2 2019-05-12 jcs view_close(tree_view);
2075 1e37a5c2 2019-05-12 jcs break;
2076 1e37a5c2 2019-05-12 jcs }
2077 1e37a5c2 2019-05-12 jcs *focus_view = tree_view;
2078 1e37a5c2 2019-05-12 jcs view->child_focussed = 1;
2079 1e37a5c2 2019-05-12 jcs } else
2080 1e37a5c2 2019-05-12 jcs *new_view = tree_view;
2081 1e37a5c2 2019-05-12 jcs break;
2082 1e37a5c2 2019-05-12 jcs case KEY_BACKSPACE:
2083 1e37a5c2 2019-05-12 jcs if (strcmp(s->in_repo_path, "/") == 0)
2084 1e37a5c2 2019-05-12 jcs break;
2085 1e37a5c2 2019-05-12 jcs parent_path = dirname(s->in_repo_path);
2086 1e37a5c2 2019-05-12 jcs if (parent_path && strcmp(parent_path, ".") != 0) {
2087 1e37a5c2 2019-05-12 jcs err = stop_log_thread(s);
2088 1e37a5c2 2019-05-12 jcs if (err)
2089 1e37a5c2 2019-05-12 jcs return err;
2090 1e37a5c2 2019-05-12 jcs lv = view_open(view->nlines, view->ncols,
2091 1e37a5c2 2019-05-12 jcs view->begin_y, view->begin_x, TOG_VIEW_LOG);
2092 1e37a5c2 2019-05-12 jcs if (lv == NULL)
2093 638f9024 2019-05-13 stsp return got_error_from_errno(
2094 1e37a5c2 2019-05-12 jcs "view_open");
2095 1e37a5c2 2019-05-12 jcs err = open_log_view(lv, s->start_id, s->refs,
2096 d01904d4 2019-06-25 stsp s->repo, s->head_ref_name, parent_path, 0);
2097 1e37a5c2 2019-05-12 jcs if (err)
2098 1e37a5c2 2019-05-12 jcs return err;;
2099 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view))
2100 1e37a5c2 2019-05-12 jcs *new_view = lv;
2101 1e37a5c2 2019-05-12 jcs else {
2102 1e37a5c2 2019-05-12 jcs view_set_child(view->parent, lv);
2103 1e37a5c2 2019-05-12 jcs *focus_view = lv;
2104 1e37a5c2 2019-05-12 jcs }
2105 1e37a5c2 2019-05-12 jcs return NULL;
2106 1e37a5c2 2019-05-12 jcs }
2107 1e37a5c2 2019-05-12 jcs break;
2108 e3d2a5c6 2019-06-26 stsp case CTRL('l'):
2109 d01904d4 2019-06-25 stsp err = stop_log_thread(s);
2110 d01904d4 2019-06-25 stsp if (err)
2111 d01904d4 2019-06-25 stsp return err;
2112 d01904d4 2019-06-25 stsp lv = view_open(view->nlines, view->ncols,
2113 d01904d4 2019-06-25 stsp view->begin_y, view->begin_x, TOG_VIEW_LOG);
2114 d01904d4 2019-06-25 stsp if (lv == NULL)
2115 d01904d4 2019-06-25 stsp return got_error_from_errno("view_open");
2116 d01904d4 2019-06-25 stsp err = get_head_commit_id(&start_id, s->head_ref_name ?
2117 d01904d4 2019-06-25 stsp s->head_ref_name : GOT_REF_HEAD, s->repo);
2118 ef129c5e 2019-08-03 stsp if (err) {
2119 ef129c5e 2019-08-03 stsp view_close(lv);
2120 d01904d4 2019-06-25 stsp return err;
2121 ef129c5e 2019-08-03 stsp }
2122 d01904d4 2019-06-25 stsp in_repo_path = strdup(s->in_repo_path);
2123 d01904d4 2019-06-25 stsp if (in_repo_path == NULL) {
2124 d01904d4 2019-06-25 stsp free(start_id);
2125 ef129c5e 2019-08-03 stsp view_close(lv);
2126 d01904d4 2019-06-25 stsp return got_error_from_errno("strdup");
2127 d01904d4 2019-06-25 stsp }
2128 d01904d4 2019-06-25 stsp err = open_log_view(lv, start_id, s->refs, s->repo,
2129 d01904d4 2019-06-25 stsp s->head_ref_name, in_repo_path, 0);
2130 ef129c5e 2019-08-03 stsp if (err) {
2131 ef129c5e 2019-08-03 stsp free(start_id);
2132 ef129c5e 2019-08-03 stsp view_close(lv);
2133 d01904d4 2019-06-25 stsp return err;;
2134 ef129c5e 2019-08-03 stsp }
2135 d01904d4 2019-06-25 stsp *dead_view = view;
2136 d01904d4 2019-06-25 stsp *new_view = lv;
2137 d01904d4 2019-06-25 stsp break;
2138 1e37a5c2 2019-05-12 jcs default:
2139 1e37a5c2 2019-05-12 jcs break;
2140 899d86c2 2018-05-10 stsp }
2141 e5a0f69f 2018-08-18 stsp
2142 80ddbec8 2018-04-29 stsp return err;
2143 80ddbec8 2018-04-29 stsp }
2144 80ddbec8 2018-04-29 stsp
2145 4ed7e80c 2018-05-20 stsp static const struct got_error *
2146 c2db6724 2019-01-04 stsp apply_unveil(const char *repo_path, const char *worktree_path)
2147 c2db6724 2019-01-04 stsp {
2148 c2db6724 2019-01-04 stsp const struct got_error *error;
2149 c2db6724 2019-01-04 stsp
2150 37c06ea4 2019-07-15 stsp #ifdef PROFILE
2151 37c06ea4 2019-07-15 stsp if (unveil("gmon.out", "rwc") != 0)
2152 37c06ea4 2019-07-15 stsp return got_error_from_errno2("unveil", "gmon.out");
2153 37c06ea4 2019-07-15 stsp #endif
2154 c2db6724 2019-01-04 stsp if (repo_path && unveil(repo_path, "r") != 0)
2155 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", repo_path);
2156 c2db6724 2019-01-04 stsp
2157 c2db6724 2019-01-04 stsp if (worktree_path && unveil(worktree_path, "rwc") != 0)
2158 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", worktree_path);
2159 c2db6724 2019-01-04 stsp
2160 f12d0dbe 2019-01-04 stsp if (unveil("/tmp", "rwc") != 0)
2161 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", "/tmp");
2162 c2db6724 2019-01-04 stsp
2163 c2db6724 2019-01-04 stsp error = got_privsep_unveil_exec_helpers();
2164 c2db6724 2019-01-04 stsp if (error != NULL)
2165 c2db6724 2019-01-04 stsp return error;
2166 c2db6724 2019-01-04 stsp
2167 c2db6724 2019-01-04 stsp if (unveil(NULL, NULL) != 0)
2168 638f9024 2019-05-13 stsp return got_error_from_errno("unveil");
2169 c2db6724 2019-01-04 stsp
2170 c2db6724 2019-01-04 stsp return NULL;
2171 c2db6724 2019-01-04 stsp }
2172 c2db6724 2019-01-04 stsp
2173 a915003a 2019-02-05 stsp static void
2174 a915003a 2019-02-05 stsp init_curses(void)
2175 a915003a 2019-02-05 stsp {
2176 a915003a 2019-02-05 stsp initscr();
2177 a915003a 2019-02-05 stsp cbreak();
2178 a915003a 2019-02-05 stsp halfdelay(1); /* Do fast refresh while initial view is loading. */
2179 a915003a 2019-02-05 stsp noecho();
2180 a915003a 2019-02-05 stsp nonl();
2181 a915003a 2019-02-05 stsp intrflush(stdscr, FALSE);
2182 a915003a 2019-02-05 stsp keypad(stdscr, TRUE);
2183 a915003a 2019-02-05 stsp curs_set(0);
2184 a915003a 2019-02-05 stsp signal(SIGWINCH, tog_sigwinch);
2185 83baff54 2019-08-12 stsp signal(SIGPIPE, tog_sigpipe);
2186 a915003a 2019-02-05 stsp }
2187 a915003a 2019-02-05 stsp
2188 c2db6724 2019-01-04 stsp static const struct got_error *
2189 9f7d7167 2018-04-29 stsp cmd_log(int argc, char *argv[])
2190 9f7d7167 2018-04-29 stsp {
2191 80ddbec8 2018-04-29 stsp const struct got_error *error;
2192 ecb28ae0 2018-07-16 stsp struct got_repository *repo = NULL;
2193 ec142235 2019-03-07 stsp struct got_worktree *worktree = NULL;
2194 8b473291 2019-02-21 stsp struct got_reflist_head refs;
2195 899d86c2 2018-05-10 stsp struct got_object_id *start_id = NULL;
2196 ecb28ae0 2018-07-16 stsp char *path = NULL, *repo_path = NULL, *cwd = NULL;
2197 80ddbec8 2018-04-29 stsp char *start_commit = NULL;
2198 80ddbec8 2018-04-29 stsp int ch;
2199 04cc582a 2018-08-01 stsp struct tog_view *view;
2200 a55555f2 2019-03-28 stsp
2201 a55555f2 2019-03-28 stsp SIMPLEQ_INIT(&refs);
2202 80ddbec8 2018-04-29 stsp
2203 80ddbec8 2018-04-29 stsp #ifndef PROFILE
2204 c2db6724 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd unveil",
2205 c2db6724 2019-01-04 stsp NULL) == -1)
2206 80ddbec8 2018-04-29 stsp err(1, "pledge");
2207 80ddbec8 2018-04-29 stsp #endif
2208 80ddbec8 2018-04-29 stsp
2209 ecb28ae0 2018-07-16 stsp while ((ch = getopt(argc, argv, "c:r:")) != -1) {
2210 80ddbec8 2018-04-29 stsp switch (ch) {
2211 80ddbec8 2018-04-29 stsp case 'c':
2212 80ddbec8 2018-04-29 stsp start_commit = optarg;
2213 80ddbec8 2018-04-29 stsp break;
2214 ecb28ae0 2018-07-16 stsp case 'r':
2215 ecb28ae0 2018-07-16 stsp repo_path = realpath(optarg, NULL);
2216 ecb28ae0 2018-07-16 stsp if (repo_path == NULL)
2217 ecb28ae0 2018-07-16 stsp err(1, "-r option");
2218 ecb28ae0 2018-07-16 stsp break;
2219 80ddbec8 2018-04-29 stsp default:
2220 17020d27 2019-03-07 stsp usage_log();
2221 80ddbec8 2018-04-29 stsp /* NOTREACHED */
2222 80ddbec8 2018-04-29 stsp }
2223 80ddbec8 2018-04-29 stsp }
2224 80ddbec8 2018-04-29 stsp
2225 80ddbec8 2018-04-29 stsp argc -= optind;
2226 80ddbec8 2018-04-29 stsp argv += optind;
2227 80ddbec8 2018-04-29 stsp
2228 ecb28ae0 2018-07-16 stsp cwd = getcwd(NULL, 0);
2229 ecb28ae0 2018-07-16 stsp if (cwd == NULL) {
2230 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
2231 ecb28ae0 2018-07-16 stsp goto done;
2232 ecb28ae0 2018-07-16 stsp }
2233 963f97a1 2019-03-18 stsp error = got_worktree_open(&worktree, cwd);
2234 963f97a1 2019-03-18 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
2235 963f97a1 2019-03-18 stsp goto done;
2236 963f97a1 2019-03-18 stsp error = NULL;
2237 963f97a1 2019-03-18 stsp
2238 963f97a1 2019-03-18 stsp if (argc == 0) {
2239 963f97a1 2019-03-18 stsp path = strdup("");
2240 963f97a1 2019-03-18 stsp if (path == NULL) {
2241 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
2242 ecb28ae0 2018-07-16 stsp goto done;
2243 ecb28ae0 2018-07-16 stsp }
2244 963f97a1 2019-03-18 stsp } else if (argc == 1) {
2245 963f97a1 2019-03-18 stsp if (worktree) {
2246 963f97a1 2019-03-18 stsp error = got_worktree_resolve_path(&path, worktree,
2247 963f97a1 2019-03-18 stsp argv[0]);
2248 963f97a1 2019-03-18 stsp if (error)
2249 963f97a1 2019-03-18 stsp goto done;
2250 963f97a1 2019-03-18 stsp } else {
2251 963f97a1 2019-03-18 stsp path = strdup(argv[0]);
2252 963f97a1 2019-03-18 stsp if (path == NULL) {
2253 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
2254 963f97a1 2019-03-18 stsp goto done;
2255 963f97a1 2019-03-18 stsp }
2256 963f97a1 2019-03-18 stsp }
2257 963f97a1 2019-03-18 stsp } else
2258 963f97a1 2019-03-18 stsp usage_log();
2259 963f97a1 2019-03-18 stsp
2260 a1fbf39a 2019-08-11 stsp if (repo_path == NULL) {
2261 a1fbf39a 2019-08-11 stsp if (worktree)
2262 b9d7675a 2019-08-11 stsp repo_path = strdup(
2263 b9d7675a 2019-08-11 stsp got_worktree_get_repo_path(worktree));
2264 a1fbf39a 2019-08-11 stsp else
2265 a1fbf39a 2019-08-11 stsp repo_path = strdup(cwd);
2266 a1fbf39a 2019-08-11 stsp }
2267 963f97a1 2019-03-18 stsp if (repo_path == NULL) {
2268 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
2269 963f97a1 2019-03-18 stsp goto done;
2270 ecb28ae0 2018-07-16 stsp }
2271 c2db6724 2019-01-04 stsp
2272 a915003a 2019-02-05 stsp init_curses();
2273 ecb28ae0 2018-07-16 stsp
2274 80ddbec8 2018-04-29 stsp error = got_repo_open(&repo, repo_path);
2275 80ddbec8 2018-04-29 stsp if (error != NULL)
2276 ecb28ae0 2018-07-16 stsp goto done;
2277 80ddbec8 2018-04-29 stsp
2278 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo),
2279 c02c541e 2019-03-29 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
2280 c02c541e 2019-03-29 stsp if (error)
2281 c02c541e 2019-03-29 stsp goto done;
2282 c02c541e 2019-03-29 stsp
2283 15a94983 2018-12-23 stsp if (start_commit == NULL)
2284 19e70ad6 2019-05-14 stsp error = get_head_commit_id(&start_id, worktree ?
2285 19e70ad6 2019-05-14 stsp got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD,
2286 19e70ad6 2019-05-14 stsp repo);
2287 f2b6a97d 2019-07-15 stsp else {
2288 f2b6a97d 2019-07-15 stsp error = get_head_commit_id(&start_id, start_commit, repo);
2289 f2b6a97d 2019-07-15 stsp if (error) {
2290 f2b6a97d 2019-07-15 stsp if (error->code != GOT_ERR_NOT_REF)
2291 f2b6a97d 2019-07-15 stsp goto done;
2292 f2b6a97d 2019-07-15 stsp error = got_repo_match_object_id_prefix(&start_id,
2293 f2b6a97d 2019-07-15 stsp start_commit, GOT_OBJ_TYPE_COMMIT, repo);
2294 f2b6a97d 2019-07-15 stsp }
2295 f2b6a97d 2019-07-15 stsp }
2296 80ddbec8 2018-04-29 stsp if (error != NULL)
2297 8b473291 2019-02-21 stsp goto done;
2298 8b473291 2019-02-21 stsp
2299 8b473291 2019-02-21 stsp error = got_ref_list(&refs, repo);
2300 8b473291 2019-02-21 stsp if (error)
2301 ecb28ae0 2018-07-16 stsp goto done;
2302 ecb28ae0 2018-07-16 stsp
2303 0cf4efb1 2018-09-29 stsp view = view_open(0, 0, 0, 0, TOG_VIEW_LOG);
2304 04cc582a 2018-08-01 stsp if (view == NULL) {
2305 638f9024 2019-05-13 stsp error = got_error_from_errno("view_open");
2306 04cc582a 2018-08-01 stsp goto done;
2307 04cc582a 2018-08-01 stsp }
2308 d01904d4 2019-06-25 stsp error = open_log_view(view, start_id, &refs, repo, worktree ?
2309 d01904d4 2019-06-25 stsp got_worktree_get_head_ref_name(worktree) : NULL, path, 1);
2310 ba4f502b 2018-08-04 stsp if (error)
2311 ba4f502b 2018-08-04 stsp goto done;
2312 e5a0f69f 2018-08-18 stsp error = view_loop(view);
2313 ecb28ae0 2018-07-16 stsp done:
2314 ecb28ae0 2018-07-16 stsp free(repo_path);
2315 ecb28ae0 2018-07-16 stsp free(cwd);
2316 ecb28ae0 2018-07-16 stsp free(path);
2317 899d86c2 2018-05-10 stsp free(start_id);
2318 ecb28ae0 2018-07-16 stsp if (repo)
2319 ecb28ae0 2018-07-16 stsp got_repo_close(repo);
2320 ec142235 2019-03-07 stsp if (worktree)
2321 ec142235 2019-03-07 stsp got_worktree_close(worktree);
2322 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
2323 80ddbec8 2018-04-29 stsp return error;
2324 9f7d7167 2018-04-29 stsp }
2325 9f7d7167 2018-04-29 stsp
2326 4ed7e80c 2018-05-20 stsp __dead static void
2327 9f7d7167 2018-04-29 stsp usage_diff(void)
2328 9f7d7167 2018-04-29 stsp {
2329 80ddbec8 2018-04-29 stsp endwin();
2330 9f7d7167 2018-04-29 stsp fprintf(stderr, "usage: %s diff [repository-path] object1 object2\n",
2331 9f7d7167 2018-04-29 stsp getprogname());
2332 9f7d7167 2018-04-29 stsp exit(1);
2333 b304db33 2018-05-20 stsp }
2334 b304db33 2018-05-20 stsp
2335 b304db33 2018-05-20 stsp static char *
2336 b304db33 2018-05-20 stsp parse_next_line(FILE *f, size_t *len)
2337 b304db33 2018-05-20 stsp {
2338 b304db33 2018-05-20 stsp char *line;
2339 b304db33 2018-05-20 stsp size_t linelen;
2340 b304db33 2018-05-20 stsp size_t lineno;
2341 b304db33 2018-05-20 stsp const char delim[3] = { '\0', '\0', '\0'};
2342 b304db33 2018-05-20 stsp
2343 b304db33 2018-05-20 stsp line = fparseln(f, &linelen, &lineno, delim, 0);
2344 b304db33 2018-05-20 stsp if (len)
2345 b304db33 2018-05-20 stsp *len = linelen;
2346 b304db33 2018-05-20 stsp return line;
2347 26ed57b2 2018-05-19 stsp }
2348 26ed57b2 2018-05-19 stsp
2349 4ed7e80c 2018-05-20 stsp static const struct got_error *
2350 f7d12f7e 2018-08-01 stsp draw_file(struct tog_view *view, FILE *f, int *first_displayed_line,
2351 a3404814 2018-09-02 stsp int *last_displayed_line, int *eof, int max_lines,
2352 c3e9aa98 2019-05-13 jcs char *header)
2353 26ed57b2 2018-05-19 stsp {
2354 61e69b96 2018-05-20 stsp const struct got_error *err;
2355 26ed57b2 2018-05-19 stsp int nlines = 0, nprinted = 0;
2356 b304db33 2018-05-20 stsp char *line;
2357 b304db33 2018-05-20 stsp size_t len;
2358 61e69b96 2018-05-20 stsp wchar_t *wline;
2359 e0b650dd 2018-05-20 stsp int width;
2360 26ed57b2 2018-05-19 stsp
2361 26ed57b2 2018-05-19 stsp rewind(f);
2362 f7d12f7e 2018-08-01 stsp werase(view->window);
2363 a3404814 2018-09-02 stsp
2364 a3404814 2018-09-02 stsp if (header) {
2365 a3404814 2018-09-02 stsp err = format_line(&wline, &width, header, view->ncols);
2366 a3404814 2018-09-02 stsp if (err) {
2367 a3404814 2018-09-02 stsp return err;
2368 a3404814 2018-09-02 stsp }
2369 a3404814 2018-09-02 stsp
2370 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
2371 a3404814 2018-09-02 stsp wstandout(view->window);
2372 a3404814 2018-09-02 stsp waddwstr(view->window, wline);
2373 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
2374 a3404814 2018-09-02 stsp wstandend(view->window);
2375 30f8fd5e 2019-06-04 stsp if (width < view->ncols - 1)
2376 a3404814 2018-09-02 stsp waddch(view->window, '\n');
2377 26ed57b2 2018-05-19 stsp
2378 a3404814 2018-09-02 stsp if (max_lines <= 1)
2379 a3404814 2018-09-02 stsp return NULL;
2380 a3404814 2018-09-02 stsp max_lines--;
2381 a3404814 2018-09-02 stsp }
2382 a3404814 2018-09-02 stsp
2383 26ed57b2 2018-05-19 stsp *eof = 0;
2384 26ed57b2 2018-05-19 stsp while (nprinted < max_lines) {
2385 b304db33 2018-05-20 stsp line = parse_next_line(f, &len);
2386 26ed57b2 2018-05-19 stsp if (line == NULL) {
2387 26ed57b2 2018-05-19 stsp *eof = 1;
2388 26ed57b2 2018-05-19 stsp break;
2389 26ed57b2 2018-05-19 stsp }
2390 26ed57b2 2018-05-19 stsp if (++nlines < *first_displayed_line) {
2391 26ed57b2 2018-05-19 stsp free(line);
2392 26ed57b2 2018-05-19 stsp continue;
2393 26ed57b2 2018-05-19 stsp }
2394 26ed57b2 2018-05-19 stsp
2395 f7d12f7e 2018-08-01 stsp err = format_line(&wline, &width, line, view->ncols);
2396 61e69b96 2018-05-20 stsp if (err) {
2397 61e69b96 2018-05-20 stsp free(line);
2398 61e69b96 2018-05-20 stsp return err;
2399 61e69b96 2018-05-20 stsp }
2400 f7d12f7e 2018-08-01 stsp waddwstr(view->window, wline);
2401 30f8fd5e 2019-06-04 stsp if (width < view->ncols - 1)
2402 f7d12f7e 2018-08-01 stsp waddch(view->window, '\n');
2403 26ed57b2 2018-05-19 stsp if (++nprinted == 1)
2404 26ed57b2 2018-05-19 stsp *first_displayed_line = nlines;
2405 26ed57b2 2018-05-19 stsp free(line);
2406 2550e4c3 2018-07-13 stsp free(wline);
2407 2550e4c3 2018-07-13 stsp wline = NULL;
2408 26ed57b2 2018-05-19 stsp }
2409 26ed57b2 2018-05-19 stsp *last_displayed_line = nlines;
2410 26ed57b2 2018-05-19 stsp
2411 1a57306a 2018-09-02 stsp view_vborder(view);
2412 c3e9aa98 2019-05-13 jcs
2413 c3e9aa98 2019-05-13 jcs if (*eof) {
2414 c3e9aa98 2019-05-13 jcs while (nprinted < view->nlines) {
2415 c3e9aa98 2019-05-13 jcs waddch(view->window, '\n');
2416 c3e9aa98 2019-05-13 jcs nprinted++;
2417 c3e9aa98 2019-05-13 jcs }
2418 c3e9aa98 2019-05-13 jcs
2419 c3e9aa98 2019-05-13 jcs err = format_line(&wline, &width, TOG_EOF_STRING, view->ncols);
2420 c3e9aa98 2019-05-13 jcs if (err) {
2421 c3e9aa98 2019-05-13 jcs return err;
2422 c3e9aa98 2019-05-13 jcs }
2423 26ed57b2 2018-05-19 stsp
2424 c3e9aa98 2019-05-13 jcs wstandout(view->window);
2425 c3e9aa98 2019-05-13 jcs waddwstr(view->window, wline);
2426 c3e9aa98 2019-05-13 jcs wstandend(view->window);
2427 c3e9aa98 2019-05-13 jcs }
2428 c3e9aa98 2019-05-13 jcs
2429 26ed57b2 2018-05-19 stsp return NULL;
2430 abd2672a 2018-12-23 stsp }
2431 abd2672a 2018-12-23 stsp
2432 abd2672a 2018-12-23 stsp static char *
2433 abd2672a 2018-12-23 stsp get_datestr(time_t *time, char *datebuf)
2434 abd2672a 2018-12-23 stsp {
2435 09867e48 2019-08-13 stsp struct tm mytm, *tm;
2436 09867e48 2019-08-13 stsp char *p, *s;
2437 09867e48 2019-08-13 stsp
2438 09867e48 2019-08-13 stsp tm = gmtime_r(time, &mytm);
2439 09867e48 2019-08-13 stsp if (tm == NULL)
2440 09867e48 2019-08-13 stsp return NULL;
2441 09867e48 2019-08-13 stsp s = asctime_r(tm, datebuf);
2442 09867e48 2019-08-13 stsp if (s == NULL)
2443 09867e48 2019-08-13 stsp return NULL;
2444 abd2672a 2018-12-23 stsp p = strchr(s, '\n');
2445 abd2672a 2018-12-23 stsp if (p)
2446 abd2672a 2018-12-23 stsp *p = '\0';
2447 abd2672a 2018-12-23 stsp return s;
2448 9f7d7167 2018-04-29 stsp }
2449 9f7d7167 2018-04-29 stsp
2450 4ed7e80c 2018-05-20 stsp static const struct got_error *
2451 8b473291 2019-02-21 stsp write_commit_info(struct got_object_id *commit_id,
2452 8b473291 2019-02-21 stsp struct got_reflist_head *refs, struct got_repository *repo, FILE *outfile)
2453 abd2672a 2018-12-23 stsp {
2454 abd2672a 2018-12-23 stsp const struct got_error *err = NULL;
2455 09867e48 2019-08-13 stsp char datebuf[26], *datestr;
2456 15a94983 2018-12-23 stsp struct got_commit_object *commit;
2457 5943eee2 2019-08-13 stsp char *id_str = NULL, *logmsg = NULL;
2458 45d799e2 2018-12-23 stsp time_t committer_time;
2459 45d799e2 2018-12-23 stsp const char *author, *committer;
2460 8b473291 2019-02-21 stsp char *refs_str = NULL;
2461 abd2672a 2018-12-23 stsp
2462 8b473291 2019-02-21 stsp if (refs) {
2463 52b5abe1 2019-08-13 stsp err = build_refs_str(&refs_str, refs, commit_id, repo);
2464 8b473291 2019-02-21 stsp if (err)
2465 8b473291 2019-02-21 stsp return err;
2466 8b473291 2019-02-21 stsp }
2467 8b473291 2019-02-21 stsp
2468 15a94983 2018-12-23 stsp err = got_object_open_as_commit(&commit, repo, commit_id);
2469 abd2672a 2018-12-23 stsp if (err)
2470 abd2672a 2018-12-23 stsp return err;
2471 abd2672a 2018-12-23 stsp
2472 15a94983 2018-12-23 stsp err = got_object_id_str(&id_str, commit_id);
2473 15a94983 2018-12-23 stsp if (err) {
2474 638f9024 2019-05-13 stsp err = got_error_from_errno("got_object_id_str");
2475 15a94983 2018-12-23 stsp goto done;
2476 15a94983 2018-12-23 stsp }
2477 abd2672a 2018-12-23 stsp
2478 8b473291 2019-02-21 stsp if (fprintf(outfile, "commit %s%s%s%s\n", id_str, refs_str ? " (" : "",
2479 8b473291 2019-02-21 stsp refs_str ? refs_str : "", refs_str ? ")" : "") < 0) {
2480 638f9024 2019-05-13 stsp err = got_error_from_errno("fprintf");
2481 abd2672a 2018-12-23 stsp goto done;
2482 abd2672a 2018-12-23 stsp }
2483 45d799e2 2018-12-23 stsp if (fprintf(outfile, "from: %s\n",
2484 45d799e2 2018-12-23 stsp got_object_commit_get_author(commit)) < 0) {
2485 638f9024 2019-05-13 stsp err = got_error_from_errno("fprintf");
2486 abd2672a 2018-12-23 stsp goto done;
2487 abd2672a 2018-12-23 stsp }
2488 45d799e2 2018-12-23 stsp committer_time = got_object_commit_get_committer_time(commit);
2489 09867e48 2019-08-13 stsp datestr = get_datestr(&committer_time, datebuf);
2490 09867e48 2019-08-13 stsp if (datestr && fprintf(outfile, "date: %s UTC\n", datestr) < 0) {
2491 638f9024 2019-05-13 stsp err = got_error_from_errno("fprintf");
2492 abd2672a 2018-12-23 stsp goto done;
2493 abd2672a 2018-12-23 stsp }
2494 45d799e2 2018-12-23 stsp author = got_object_commit_get_author(commit);
2495 45d799e2 2018-12-23 stsp committer = got_object_commit_get_committer(commit);
2496 45d799e2 2018-12-23 stsp if (strcmp(author, committer) != 0 &&
2497 45d799e2 2018-12-23 stsp fprintf(outfile, "via: %s\n", committer) < 0) {
2498 638f9024 2019-05-13 stsp err = got_error_from_errno("fprintf");
2499 abd2672a 2018-12-23 stsp goto done;
2500 abd2672a 2018-12-23 stsp }
2501 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg, commit);
2502 5943eee2 2019-08-13 stsp if (err)
2503 5943eee2 2019-08-13 stsp goto done;
2504 5943eee2 2019-08-13 stsp if (fprintf(outfile, "%s\n", logmsg) < 0) {
2505 638f9024 2019-05-13 stsp err = got_error_from_errno("fprintf");
2506 abd2672a 2018-12-23 stsp goto done;
2507 abd2672a 2018-12-23 stsp }
2508 abd2672a 2018-12-23 stsp done:
2509 abd2672a 2018-12-23 stsp free(id_str);
2510 5943eee2 2019-08-13 stsp free(logmsg);
2511 8b473291 2019-02-21 stsp free(refs_str);
2512 15a94983 2018-12-23 stsp got_object_commit_close(commit);
2513 abd2672a 2018-12-23 stsp return err;
2514 abd2672a 2018-12-23 stsp }
2515 abd2672a 2018-12-23 stsp
2516 abd2672a 2018-12-23 stsp static const struct got_error *
2517 48ae06ee 2018-10-18 stsp create_diff(struct tog_diff_view_state *s)
2518 26ed57b2 2018-05-19 stsp {
2519 48ae06ee 2018-10-18 stsp const struct got_error *err = NULL;
2520 48ae06ee 2018-10-18 stsp FILE *f = NULL;
2521 15a94983 2018-12-23 stsp int obj_type;
2522 26ed57b2 2018-05-19 stsp
2523 511a516b 2018-05-19 stsp f = got_opentemp();
2524 48ae06ee 2018-10-18 stsp if (f == NULL) {
2525 638f9024 2019-05-13 stsp err = got_error_from_errno("got_opentemp");
2526 48ae06ee 2018-10-18 stsp goto done;
2527 48ae06ee 2018-10-18 stsp }
2528 fb43ecf1 2019-02-11 stsp if (s->f && fclose(s->f) != 0) {
2529 638f9024 2019-05-13 stsp err = got_error_from_errno("fclose");
2530 fb43ecf1 2019-02-11 stsp goto done;
2531 fb43ecf1 2019-02-11 stsp }
2532 48ae06ee 2018-10-18 stsp s->f = f;
2533 26ed57b2 2018-05-19 stsp
2534 15a94983 2018-12-23 stsp if (s->id1)
2535 15a94983 2018-12-23 stsp err = got_object_get_type(&obj_type, s->repo, s->id1);
2536 15a94983 2018-12-23 stsp else
2537 15a94983 2018-12-23 stsp err = got_object_get_type(&obj_type, s->repo, s->id2);
2538 15a94983 2018-12-23 stsp if (err)
2539 15a94983 2018-12-23 stsp goto done;
2540 15a94983 2018-12-23 stsp
2541 15a94983 2018-12-23 stsp switch (obj_type) {
2542 26ed57b2 2018-05-19 stsp case GOT_OBJ_TYPE_BLOB:
2543 15a94983 2018-12-23 stsp err = got_diff_objects_as_blobs(s->id1, s->id2, NULL, NULL,
2544 54156555 2018-12-24 stsp s->diff_context, s->repo, f);
2545 26ed57b2 2018-05-19 stsp break;
2546 26ed57b2 2018-05-19 stsp case GOT_OBJ_TYPE_TREE:
2547 54156555 2018-12-24 stsp err = got_diff_objects_as_trees(s->id1, s->id2, "", "",
2548 48ae06ee 2018-10-18 stsp s->diff_context, s->repo, f);
2549 26ed57b2 2018-05-19 stsp break;
2550 abd2672a 2018-12-23 stsp case GOT_OBJ_TYPE_COMMIT: {
2551 45d799e2 2018-12-23 stsp const struct got_object_id_queue *parent_ids;
2552 abd2672a 2018-12-23 stsp struct got_object_qid *pid;
2553 abd2672a 2018-12-23 stsp struct got_commit_object *commit2;
2554 abd2672a 2018-12-23 stsp
2555 15a94983 2018-12-23 stsp err = got_object_open_as_commit(&commit2, s->repo, s->id2);
2556 abd2672a 2018-12-23 stsp if (err)
2557 abd2672a 2018-12-23 stsp break;
2558 15a087fe 2019-02-21 stsp /* Show commit info if we're diffing to a parent/root commit. */
2559 15a087fe 2019-02-21 stsp if (s->id1 == NULL)
2560 8b473291 2019-02-21 stsp write_commit_info(s->id2, s->refs, s->repo, f);
2561 15a087fe 2019-02-21 stsp else {
2562 15a087fe 2019-02-21 stsp parent_ids = got_object_commit_get_parent_ids(commit2);
2563 15a087fe 2019-02-21 stsp SIMPLEQ_FOREACH(pid, parent_ids, entry) {
2564 15a087fe 2019-02-21 stsp if (got_object_id_cmp(s->id1, pid->id) == 0) {
2565 8b473291 2019-02-21 stsp write_commit_info(s->id2, s->refs,
2566 8b473291 2019-02-21 stsp s->repo, f);
2567 15a087fe 2019-02-21 stsp break;
2568 15a087fe 2019-02-21 stsp }
2569 abd2672a 2018-12-23 stsp }
2570 abd2672a 2018-12-23 stsp }
2571 abd2672a 2018-12-23 stsp got_object_commit_close(commit2);
2572 abd2672a 2018-12-23 stsp
2573 15a94983 2018-12-23 stsp err = got_diff_objects_as_commits(s->id1, s->id2,
2574 15a94983 2018-12-23 stsp s->diff_context, s->repo, f);
2575 26ed57b2 2018-05-19 stsp break;
2576 abd2672a 2018-12-23 stsp }
2577 26ed57b2 2018-05-19 stsp default:
2578 48ae06ee 2018-10-18 stsp err = got_error(GOT_ERR_OBJ_TYPE);
2579 48ae06ee 2018-10-18 stsp break;
2580 26ed57b2 2018-05-19 stsp }
2581 48ae06ee 2018-10-18 stsp done:
2582 cbe7f848 2019-02-11 stsp if (f && fflush(f) != 0 && err == NULL)
2583 638f9024 2019-05-13 stsp err = got_error_from_errno("fflush");
2584 48ae06ee 2018-10-18 stsp return err;
2585 48ae06ee 2018-10-18 stsp }
2586 26ed57b2 2018-05-19 stsp
2587 f5215bb9 2019-02-22 stsp static void
2588 f5215bb9 2019-02-22 stsp diff_view_indicate_progress(struct tog_view *view)
2589 f5215bb9 2019-02-22 stsp {
2590 baf4288f 2019-05-13 stsp mvwaddstr(view->window, 0, 0, "diffing...");
2591 f5215bb9 2019-02-22 stsp update_panels();
2592 f5215bb9 2019-02-22 stsp doupdate();
2593 f5215bb9 2019-02-22 stsp }
2594 f5215bb9 2019-02-22 stsp
2595 48ae06ee 2018-10-18 stsp static const struct got_error *
2596 15a94983 2018-12-23 stsp open_diff_view(struct tog_view *view, struct got_object_id *id1,
2597 fb872ab2 2019-02-21 stsp struct got_object_id *id2, struct tog_view *log_view,
2598 8b473291 2019-02-21 stsp struct got_reflist_head *refs, struct got_repository *repo)
2599 48ae06ee 2018-10-18 stsp {
2600 48ae06ee 2018-10-18 stsp const struct got_error *err;
2601 5dc9f4bc 2018-08-04 stsp
2602 15a94983 2018-12-23 stsp if (id1 != NULL && id2 != NULL) {
2603 15a94983 2018-12-23 stsp int type1, type2;
2604 15a94983 2018-12-23 stsp err = got_object_get_type(&type1, repo, id1);
2605 15a94983 2018-12-23 stsp if (err)
2606 15a94983 2018-12-23 stsp return err;
2607 15a94983 2018-12-23 stsp err = got_object_get_type(&type2, repo, id2);
2608 15a94983 2018-12-23 stsp if (err)
2609 15a94983 2018-12-23 stsp return err;
2610 15a94983 2018-12-23 stsp
2611 15a94983 2018-12-23 stsp if (type1 != type2)
2612 48ae06ee 2018-10-18 stsp return got_error(GOT_ERR_OBJ_TYPE);
2613 15a94983 2018-12-23 stsp }
2614 48ae06ee 2018-10-18 stsp
2615 15a94983 2018-12-23 stsp if (id1) {
2616 15a94983 2018-12-23 stsp view->state.diff.id1 = got_object_id_dup(id1);
2617 15a94983 2018-12-23 stsp if (view->state.diff.id1 == NULL)
2618 638f9024 2019-05-13 stsp return got_error_from_errno("got_object_id_dup");
2619 48ae06ee 2018-10-18 stsp } else
2620 48ae06ee 2018-10-18 stsp view->state.diff.id1 = NULL;
2621 48ae06ee 2018-10-18 stsp
2622 15a94983 2018-12-23 stsp view->state.diff.id2 = got_object_id_dup(id2);
2623 48ae06ee 2018-10-18 stsp if (view->state.diff.id2 == NULL) {
2624 48ae06ee 2018-10-18 stsp free(view->state.diff.id1);
2625 48ae06ee 2018-10-18 stsp view->state.diff.id1 = NULL;
2626 638f9024 2019-05-13 stsp return got_error_from_errno("got_object_id_dup");
2627 48ae06ee 2018-10-18 stsp }
2628 48ae06ee 2018-10-18 stsp view->state.diff.f = NULL;
2629 5dc9f4bc 2018-08-04 stsp view->state.diff.first_displayed_line = 1;
2630 5dc9f4bc 2018-08-04 stsp view->state.diff.last_displayed_line = view->nlines;
2631 48ae06ee 2018-10-18 stsp view->state.diff.diff_context = 3;
2632 fb872ab2 2019-02-21 stsp view->state.diff.log_view = log_view;
2633 48ae06ee 2018-10-18 stsp view->state.diff.repo = repo;
2634 8b473291 2019-02-21 stsp view->state.diff.refs = refs;
2635 5dc9f4bc 2018-08-04 stsp
2636 f5215bb9 2019-02-22 stsp if (log_view && view_is_splitscreen(view))
2637 f5215bb9 2019-02-22 stsp show_log_view(log_view); /* draw vborder */
2638 f5215bb9 2019-02-22 stsp diff_view_indicate_progress(view);
2639 f5215bb9 2019-02-22 stsp
2640 48ae06ee 2018-10-18 stsp err = create_diff(&view->state.diff);
2641 48ae06ee 2018-10-18 stsp if (err) {
2642 48ae06ee 2018-10-18 stsp free(view->state.diff.id1);
2643 48ae06ee 2018-10-18 stsp view->state.diff.id1 = NULL;
2644 48ae06ee 2018-10-18 stsp free(view->state.diff.id2);
2645 48ae06ee 2018-10-18 stsp view->state.diff.id2 = NULL;
2646 48ae06ee 2018-10-18 stsp return err;
2647 48ae06ee 2018-10-18 stsp }
2648 48ae06ee 2018-10-18 stsp
2649 e5a0f69f 2018-08-18 stsp view->show = show_diff_view;
2650 e5a0f69f 2018-08-18 stsp view->input = input_diff_view;
2651 e5a0f69f 2018-08-18 stsp view->close = close_diff_view;
2652 e5a0f69f 2018-08-18 stsp
2653 5dc9f4bc 2018-08-04 stsp return NULL;
2654 5dc9f4bc 2018-08-04 stsp }
2655 5dc9f4bc 2018-08-04 stsp
2656 e5a0f69f 2018-08-18 stsp static const struct got_error *
2657 5dc9f4bc 2018-08-04 stsp close_diff_view(struct tog_view *view)
2658 5dc9f4bc 2018-08-04 stsp {
2659 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
2660 e5a0f69f 2018-08-18 stsp
2661 48ae06ee 2018-10-18 stsp free(view->state.diff.id1);
2662 48ae06ee 2018-10-18 stsp view->state.diff.id1 = NULL;
2663 48ae06ee 2018-10-18 stsp free(view->state.diff.id2);
2664 48ae06ee 2018-10-18 stsp view->state.diff.id2 = NULL;
2665 e5a0f69f 2018-08-18 stsp if (view->state.diff.f && fclose(view->state.diff.f) == EOF)
2666 638f9024 2019-05-13 stsp err = got_error_from_errno("fclose");
2667 e5a0f69f 2018-08-18 stsp return err;
2668 5dc9f4bc 2018-08-04 stsp }
2669 5dc9f4bc 2018-08-04 stsp
2670 5dc9f4bc 2018-08-04 stsp static const struct got_error *
2671 5dc9f4bc 2018-08-04 stsp show_diff_view(struct tog_view *view)
2672 5dc9f4bc 2018-08-04 stsp {
2673 a3404814 2018-09-02 stsp const struct got_error *err;
2674 fb2756b9 2018-08-04 stsp struct tog_diff_view_state *s = &view->state.diff;
2675 a3404814 2018-09-02 stsp char *id_str1 = NULL, *id_str2, *header;
2676 a3404814 2018-09-02 stsp
2677 a3404814 2018-09-02 stsp if (s->id1) {
2678 a3404814 2018-09-02 stsp err = got_object_id_str(&id_str1, s->id1);
2679 a3404814 2018-09-02 stsp if (err)
2680 a3404814 2018-09-02 stsp return err;
2681 a3404814 2018-09-02 stsp }
2682 a3404814 2018-09-02 stsp err = got_object_id_str(&id_str2, s->id2);
2683 a3404814 2018-09-02 stsp if (err)
2684 a3404814 2018-09-02 stsp return err;
2685 26ed57b2 2018-05-19 stsp
2686 56765ebb 2018-12-23 stsp if (asprintf(&header, "diff %s %s",
2687 a3404814 2018-09-02 stsp id_str1 ? id_str1 : "/dev/null", id_str2) == -1) {
2688 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
2689 a3404814 2018-09-02 stsp free(id_str1);
2690 a3404814 2018-09-02 stsp free(id_str2);
2691 a3404814 2018-09-02 stsp return err;
2692 a3404814 2018-09-02 stsp }
2693 a3404814 2018-09-02 stsp free(id_str1);
2694 a3404814 2018-09-02 stsp free(id_str2);
2695 a3404814 2018-09-02 stsp
2696 e5a0f69f 2018-08-18 stsp return draw_file(view, s->f, &s->first_displayed_line,
2697 a3404814 2018-09-02 stsp &s->last_displayed_line, &s->eof, view->nlines,
2698 a3404814 2018-09-02 stsp header);
2699 15a087fe 2019-02-21 stsp }
2700 15a087fe 2019-02-21 stsp
2701 15a087fe 2019-02-21 stsp static const struct got_error *
2702 15a087fe 2019-02-21 stsp set_selected_commit(struct tog_diff_view_state *s,
2703 15a087fe 2019-02-21 stsp struct commit_queue_entry *entry)
2704 15a087fe 2019-02-21 stsp {
2705 d7a04538 2019-02-21 stsp const struct got_error *err;
2706 d7a04538 2019-02-21 stsp const struct got_object_id_queue *parent_ids;
2707 d7a04538 2019-02-21 stsp struct got_commit_object *selected_commit;
2708 d7a04538 2019-02-21 stsp struct got_object_qid *pid;
2709 15a087fe 2019-02-21 stsp
2710 15a087fe 2019-02-21 stsp free(s->id2);
2711 15a087fe 2019-02-21 stsp s->id2 = got_object_id_dup(entry->id);
2712 15a087fe 2019-02-21 stsp if (s->id2 == NULL)
2713 638f9024 2019-05-13 stsp return got_error_from_errno("got_object_id_dup");
2714 15a087fe 2019-02-21 stsp
2715 d7a04538 2019-02-21 stsp err = got_object_open_as_commit(&selected_commit, s->repo, entry->id);
2716 d7a04538 2019-02-21 stsp if (err)
2717 d7a04538 2019-02-21 stsp return err;
2718 d7a04538 2019-02-21 stsp parent_ids = got_object_commit_get_parent_ids(selected_commit);
2719 15a087fe 2019-02-21 stsp free(s->id1);
2720 d7a04538 2019-02-21 stsp pid = SIMPLEQ_FIRST(parent_ids);
2721 d7a04538 2019-02-21 stsp s->id1 = pid ? got_object_id_dup(pid->id) : NULL;
2722 0311546b 2019-02-21 stsp got_object_commit_close(selected_commit);
2723 15a087fe 2019-02-21 stsp return NULL;
2724 0cf4efb1 2018-09-29 stsp }
2725 0cf4efb1 2018-09-29 stsp
2726 0cf4efb1 2018-09-29 stsp static const struct got_error *
2727 bcbd79e2 2018-08-19 stsp input_diff_view(struct tog_view **new_view, struct tog_view **dead_view,
2728 878940b7 2018-09-29 stsp struct tog_view **focus_view, struct tog_view *view, int ch)
2729 e5a0f69f 2018-08-18 stsp {
2730 bcbd79e2 2018-08-19 stsp const struct got_error *err = NULL;
2731 e5a0f69f 2018-08-18 stsp struct tog_diff_view_state *s = &view->state.diff;
2732 fb872ab2 2019-02-21 stsp struct tog_log_view_state *ls;
2733 fb872ab2 2019-02-21 stsp struct commit_queue_entry *entry;
2734 e5a0f69f 2018-08-18 stsp int i;
2735 e5a0f69f 2018-08-18 stsp
2736 e5a0f69f 2018-08-18 stsp switch (ch) {
2737 1e37a5c2 2019-05-12 jcs case 'k':
2738 1e37a5c2 2019-05-12 jcs case KEY_UP:
2739 1e37a5c2 2019-05-12 jcs if (s->first_displayed_line > 1)
2740 1e37a5c2 2019-05-12 jcs s->first_displayed_line--;
2741 1e37a5c2 2019-05-12 jcs break;
2742 1e37a5c2 2019-05-12 jcs case KEY_PPAGE:
2743 a60a9dc4 2019-05-13 jcs case CTRL('b'):
2744 00ba99a7 2019-05-12 jcs if (s->first_displayed_line == 1)
2745 26ed57b2 2018-05-19 stsp break;
2746 1e37a5c2 2019-05-12 jcs i = 0;
2747 1e37a5c2 2019-05-12 jcs while (i++ < view->nlines - 1 &&
2748 1e37a5c2 2019-05-12 jcs s->first_displayed_line > 1)
2749 1e37a5c2 2019-05-12 jcs s->first_displayed_line--;
2750 1e37a5c2 2019-05-12 jcs break;
2751 1e37a5c2 2019-05-12 jcs case 'j':
2752 1e37a5c2 2019-05-12 jcs case KEY_DOWN:
2753 1e37a5c2 2019-05-12 jcs if (!s->eof)
2754 1e37a5c2 2019-05-12 jcs s->first_displayed_line++;
2755 1e37a5c2 2019-05-12 jcs break;
2756 1e37a5c2 2019-05-12 jcs case KEY_NPAGE:
2757 a60a9dc4 2019-05-13 jcs case CTRL('f'):
2758 1e37a5c2 2019-05-12 jcs case ' ':
2759 00ba99a7 2019-05-12 jcs if (s->eof)
2760 1e37a5c2 2019-05-12 jcs break;
2761 1e37a5c2 2019-05-12 jcs i = 0;
2762 1e37a5c2 2019-05-12 jcs while (!s->eof && i++ < view->nlines - 1) {
2763 1e37a5c2 2019-05-12 jcs char *line;
2764 1e37a5c2 2019-05-12 jcs line = parse_next_line(s->f, NULL);
2765 1e37a5c2 2019-05-12 jcs s->first_displayed_line++;
2766 1e37a5c2 2019-05-12 jcs if (line == NULL)
2767 34bc9ec9 2019-02-22 stsp break;
2768 1e37a5c2 2019-05-12 jcs }
2769 1e37a5c2 2019-05-12 jcs break;
2770 1e37a5c2 2019-05-12 jcs case '[':
2771 1e37a5c2 2019-05-12 jcs if (s->diff_context > 0) {
2772 1e37a5c2 2019-05-12 jcs s->diff_context--;
2773 1e37a5c2 2019-05-12 jcs diff_view_indicate_progress(view);
2774 1e37a5c2 2019-05-12 jcs err = create_diff(s);
2775 1e37a5c2 2019-05-12 jcs }
2776 1e37a5c2 2019-05-12 jcs break;
2777 1e37a5c2 2019-05-12 jcs case ']':
2778 1e37a5c2 2019-05-12 jcs if (s->diff_context < GOT_DIFF_MAX_CONTEXT) {
2779 1e37a5c2 2019-05-12 jcs s->diff_context++;
2780 1e37a5c2 2019-05-12 jcs diff_view_indicate_progress(view);
2781 1e37a5c2 2019-05-12 jcs err = create_diff(s);
2782 1e37a5c2 2019-05-12 jcs }
2783 1e37a5c2 2019-05-12 jcs break;
2784 1e37a5c2 2019-05-12 jcs case '<':
2785 1e37a5c2 2019-05-12 jcs case ',':
2786 1e37a5c2 2019-05-12 jcs if (s->log_view == NULL)
2787 48ae06ee 2018-10-18 stsp break;
2788 1e37a5c2 2019-05-12 jcs ls = &s->log_view->state.log;
2789 1e37a5c2 2019-05-12 jcs entry = TAILQ_PREV(ls->selected_entry,
2790 1e37a5c2 2019-05-12 jcs commit_queue_head, entry);
2791 1e37a5c2 2019-05-12 jcs if (entry == NULL)
2792 48ae06ee 2018-10-18 stsp break;
2793 6524637e 2019-02-21 stsp
2794 1e37a5c2 2019-05-12 jcs err = input_log_view(NULL, NULL, NULL, s->log_view,
2795 1e37a5c2 2019-05-12 jcs KEY_UP);
2796 1e37a5c2 2019-05-12 jcs if (err)
2797 1e37a5c2 2019-05-12 jcs break;
2798 15a087fe 2019-02-21 stsp
2799 1e37a5c2 2019-05-12 jcs err = set_selected_commit(s, entry);
2800 1e37a5c2 2019-05-12 jcs if (err)
2801 1e37a5c2 2019-05-12 jcs break;
2802 15a087fe 2019-02-21 stsp
2803 1e37a5c2 2019-05-12 jcs s->first_displayed_line = 1;
2804 1e37a5c2 2019-05-12 jcs s->last_displayed_line = view->nlines;
2805 15a087fe 2019-02-21 stsp
2806 1e37a5c2 2019-05-12 jcs diff_view_indicate_progress(view);
2807 1e37a5c2 2019-05-12 jcs err = create_diff(s);
2808 1e37a5c2 2019-05-12 jcs break;
2809 1e37a5c2 2019-05-12 jcs case '>':
2810 1e37a5c2 2019-05-12 jcs case '.':
2811 1e37a5c2 2019-05-12 jcs if (s->log_view == NULL)
2812 15a087fe 2019-02-21 stsp break;
2813 1e37a5c2 2019-05-12 jcs ls = &s->log_view->state.log;
2814 5e224a3e 2019-02-22 stsp
2815 1e37a5c2 2019-05-12 jcs if (TAILQ_NEXT(ls->selected_entry, entry) == NULL) {
2816 1e37a5c2 2019-05-12 jcs ls->thread_args.commits_needed++;
2817 5e224a3e 2019-02-22 stsp
2818 1e37a5c2 2019-05-12 jcs /* Display "loading..." in log view. */
2819 1e37a5c2 2019-05-12 jcs show_log_view(s->log_view);
2820 1e37a5c2 2019-05-12 jcs update_panels();
2821 1e37a5c2 2019-05-12 jcs doupdate();
2822 6e73b0d6 2019-02-22 stsp
2823 1e37a5c2 2019-05-12 jcs err = trigger_log_thread(1 /* load_all */,
2824 1e37a5c2 2019-05-12 jcs &ls->thread_args.commits_needed,
2825 1e37a5c2 2019-05-12 jcs &ls->thread_args.log_complete,
2826 1e37a5c2 2019-05-12 jcs &ls->thread_args.need_commits);
2827 fb872ab2 2019-02-21 stsp if (err)
2828 fb872ab2 2019-02-21 stsp break;
2829 1e37a5c2 2019-05-12 jcs }
2830 1e37a5c2 2019-05-12 jcs err = input_log_view(NULL, NULL, NULL, s->log_view,
2831 1e37a5c2 2019-05-12 jcs KEY_DOWN);
2832 1e37a5c2 2019-05-12 jcs if (err)
2833 1e37a5c2 2019-05-12 jcs break;
2834 15a087fe 2019-02-21 stsp
2835 1e37a5c2 2019-05-12 jcs entry = TAILQ_NEXT(ls->selected_entry, entry);
2836 1e37a5c2 2019-05-12 jcs if (entry == NULL)
2837 1e37a5c2 2019-05-12 jcs break;
2838 15a087fe 2019-02-21 stsp
2839 1e37a5c2 2019-05-12 jcs err = set_selected_commit(s, entry);
2840 1e37a5c2 2019-05-12 jcs if (err)
2841 1e37a5c2 2019-05-12 jcs break;
2842 15a087fe 2019-02-21 stsp
2843 1e37a5c2 2019-05-12 jcs s->first_displayed_line = 1;
2844 1e37a5c2 2019-05-12 jcs s->last_displayed_line = view->nlines;
2845 1e37a5c2 2019-05-12 jcs
2846 1e37a5c2 2019-05-12 jcs diff_view_indicate_progress(view);
2847 1e37a5c2 2019-05-12 jcs err = create_diff(s);
2848 1e37a5c2 2019-05-12 jcs break;
2849 1e37a5c2 2019-05-12 jcs default:
2850 1e37a5c2 2019-05-12 jcs break;
2851 26ed57b2 2018-05-19 stsp }
2852 e5a0f69f 2018-08-18 stsp
2853 bcbd79e2 2018-08-19 stsp return err;
2854 26ed57b2 2018-05-19 stsp }
2855 26ed57b2 2018-05-19 stsp
2856 4ed7e80c 2018-05-20 stsp static const struct got_error *
2857 9f7d7167 2018-04-29 stsp cmd_diff(int argc, char *argv[])
2858 9f7d7167 2018-04-29 stsp {
2859 26ed57b2 2018-05-19 stsp const struct got_error *error = NULL;
2860 26ed57b2 2018-05-19 stsp struct got_repository *repo = NULL;
2861 8b473291 2019-02-21 stsp struct got_reflist_head refs;
2862 15a94983 2018-12-23 stsp struct got_object_id *id1 = NULL, *id2 = NULL;
2863 26ed57b2 2018-05-19 stsp char *repo_path = NULL;
2864 15a94983 2018-12-23 stsp char *id_str1 = NULL, *id_str2 = NULL;
2865 26ed57b2 2018-05-19 stsp int ch;
2866 ea5e7bb5 2018-08-01 stsp struct tog_view *view;
2867 70ac5f84 2019-03-28 stsp
2868 70ac5f84 2019-03-28 stsp SIMPLEQ_INIT(&refs);
2869 26ed57b2 2018-05-19 stsp
2870 26ed57b2 2018-05-19 stsp #ifndef PROFILE
2871 eb6600df 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd unveil",
2872 eb6600df 2019-01-04 stsp NULL) == -1)
2873 26ed57b2 2018-05-19 stsp err(1, "pledge");
2874 26ed57b2 2018-05-19 stsp #endif
2875 26ed57b2 2018-05-19 stsp
2876 26ed57b2 2018-05-19 stsp while ((ch = getopt(argc, argv, "")) != -1) {
2877 26ed57b2 2018-05-19 stsp switch (ch) {
2878 26ed57b2 2018-05-19 stsp default:
2879 17020d27 2019-03-07 stsp usage_diff();
2880 26ed57b2 2018-05-19 stsp /* NOTREACHED */
2881 26ed57b2 2018-05-19 stsp }
2882 26ed57b2 2018-05-19 stsp }
2883 26ed57b2 2018-05-19 stsp
2884 26ed57b2 2018-05-19 stsp argc -= optind;
2885 26ed57b2 2018-05-19 stsp argv += optind;
2886 26ed57b2 2018-05-19 stsp
2887 26ed57b2 2018-05-19 stsp if (argc == 0) {
2888 26ed57b2 2018-05-19 stsp usage_diff(); /* TODO show local worktree changes */
2889 26ed57b2 2018-05-19 stsp } else if (argc == 2) {
2890 26ed57b2 2018-05-19 stsp repo_path = getcwd(NULL, 0);
2891 26ed57b2 2018-05-19 stsp if (repo_path == NULL)
2892 638f9024 2019-05-13 stsp return got_error_from_errno("getcwd");
2893 15a94983 2018-12-23 stsp id_str1 = argv[0];
2894 15a94983 2018-12-23 stsp id_str2 = argv[1];
2895 26ed57b2 2018-05-19 stsp } else if (argc == 3) {
2896 26ed57b2 2018-05-19 stsp repo_path = realpath(argv[0], NULL);
2897 26ed57b2 2018-05-19 stsp if (repo_path == NULL)
2898 638f9024 2019-05-13 stsp return got_error_from_errno2("realpath", argv[0]);
2899 15a94983 2018-12-23 stsp id_str1 = argv[1];
2900 15a94983 2018-12-23 stsp id_str2 = argv[2];
2901 26ed57b2 2018-05-19 stsp } else
2902 26ed57b2 2018-05-19 stsp usage_diff();
2903 a915003a 2019-02-05 stsp
2904 a915003a 2019-02-05 stsp init_curses();
2905 eb6600df 2019-01-04 stsp
2906 c02c541e 2019-03-29 stsp error = got_repo_open(&repo, repo_path);
2907 eb6600df 2019-01-04 stsp if (error)
2908 eb6600df 2019-01-04 stsp goto done;
2909 26ed57b2 2018-05-19 stsp
2910 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), NULL);
2911 26ed57b2 2018-05-19 stsp if (error)
2912 26ed57b2 2018-05-19 stsp goto done;
2913 26ed57b2 2018-05-19 stsp
2914 dd88155e 2019-06-29 stsp error = got_repo_match_object_id_prefix(&id1, id_str1,
2915 dd88155e 2019-06-29 stsp GOT_OBJ_TYPE_ANY, repo);
2916 26ed57b2 2018-05-19 stsp if (error)
2917 26ed57b2 2018-05-19 stsp goto done;
2918 26ed57b2 2018-05-19 stsp
2919 dd88155e 2019-06-29 stsp error = got_repo_match_object_id_prefix(&id2, id_str2,
2920 dd88155e 2019-06-29 stsp GOT_OBJ_TYPE_ANY, repo);
2921 26ed57b2 2018-05-19 stsp if (error)
2922 26ed57b2 2018-05-19 stsp goto done;
2923 26ed57b2 2018-05-19 stsp
2924 8b473291 2019-02-21 stsp error = got_ref_list(&refs, repo);
2925 8b473291 2019-02-21 stsp if (error)
2926 8b473291 2019-02-21 stsp goto done;
2927 8b473291 2019-02-21 stsp
2928 0cf4efb1 2018-09-29 stsp view = view_open(0, 0, 0, 0, TOG_VIEW_DIFF);
2929 ea5e7bb5 2018-08-01 stsp if (view == NULL) {
2930 638f9024 2019-05-13 stsp error = got_error_from_errno("view_open");
2931 ea5e7bb5 2018-08-01 stsp goto done;
2932 ea5e7bb5 2018-08-01 stsp }
2933 8b473291 2019-02-21 stsp error = open_diff_view(view, id1, id2, NULL, &refs, repo);
2934 5dc9f4bc 2018-08-04 stsp if (error)
2935 5dc9f4bc 2018-08-04 stsp goto done;
2936 e5a0f69f 2018-08-18 stsp error = view_loop(view);
2937 26ed57b2 2018-05-19 stsp done:
2938 c02c541e 2019-03-29 stsp free(repo_path);
2939 921be706 2019-06-28 stsp if (repo)
2940 921be706 2019-06-28 stsp got_repo_close(repo);
2941 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
2942 26ed57b2 2018-05-19 stsp return error;
2943 9f7d7167 2018-04-29 stsp }
2944 9f7d7167 2018-04-29 stsp
2945 4ed7e80c 2018-05-20 stsp __dead static void
2946 9f7d7167 2018-04-29 stsp usage_blame(void)
2947 9f7d7167 2018-04-29 stsp {
2948 80ddbec8 2018-04-29 stsp endwin();
2949 69069811 2018-08-02 stsp fprintf(stderr, "usage: %s blame [-c commit] [-r repository-path] path\n",
2950 9f7d7167 2018-04-29 stsp getprogname());
2951 9f7d7167 2018-04-29 stsp exit(1);
2952 9f7d7167 2018-04-29 stsp }
2953 84451b3e 2018-07-10 stsp
2954 84451b3e 2018-07-10 stsp struct tog_blame_line {
2955 84451b3e 2018-07-10 stsp int annotated;
2956 84451b3e 2018-07-10 stsp struct got_object_id *id;
2957 84451b3e 2018-07-10 stsp };
2958 9f7d7167 2018-04-29 stsp
2959 4ed7e80c 2018-05-20 stsp static const struct got_error *
2960 f7d12f7e 2018-08-01 stsp draw_blame(struct tog_view *view, struct got_object_id *id, FILE *f,
2961 f7d12f7e 2018-08-01 stsp const char *path, struct tog_blame_line *lines, int nlines,
2962 f7d12f7e 2018-08-01 stsp int blame_complete, int selected_line, int *first_displayed_line,
2963 f7d12f7e 2018-08-01 stsp int *last_displayed_line, int *eof, int max_lines)
2964 84451b3e 2018-07-10 stsp {
2965 84451b3e 2018-07-10 stsp const struct got_error *err;
2966 84451b3e 2018-07-10 stsp int lineno = 0, nprinted = 0;
2967 84451b3e 2018-07-10 stsp char *line;
2968 84451b3e 2018-07-10 stsp size_t len;
2969 84451b3e 2018-07-10 stsp wchar_t *wline;
2970 b700b5d6 2018-07-10 stsp int width, wlimit;
2971 84451b3e 2018-07-10 stsp struct tog_blame_line *blame_line;
2972 ee41ec32 2018-07-10 stsp struct got_object_id *prev_id = NULL;
2973 ab089a2a 2018-07-12 stsp char *id_str;
2974 ab089a2a 2018-07-12 stsp
2975 ab089a2a 2018-07-12 stsp err = got_object_id_str(&id_str, id);
2976 ab089a2a 2018-07-12 stsp if (err)
2977 ab089a2a 2018-07-12 stsp return err;
2978 84451b3e 2018-07-10 stsp
2979 84451b3e 2018-07-10 stsp rewind(f);
2980 f7d12f7e 2018-08-01 stsp werase(view->window);
2981 84451b3e 2018-07-10 stsp
2982 c1124f18 2018-12-23 stsp if (asprintf(&line, "commit %s", id_str) == -1) {
2983 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
2984 ab089a2a 2018-07-12 stsp free(id_str);
2985 ab089a2a 2018-07-12 stsp return err;
2986 ab089a2a 2018-07-12 stsp }
2987 ab089a2a 2018-07-12 stsp
2988 f7d12f7e 2018-08-01 stsp err = format_line(&wline, &width, line, view->ncols);
2989 ab089a2a 2018-07-12 stsp free(line);
2990 2550e4c3 2018-07-13 stsp line = NULL;
2991 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
2992 a3404814 2018-09-02 stsp wstandout(view->window);
2993 f7d12f7e 2018-08-01 stsp waddwstr(view->window, wline);
2994 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
2995 a3404814 2018-09-02 stsp wstandend(view->window);
2996 2550e4c3 2018-07-13 stsp free(wline);
2997 2550e4c3 2018-07-13 stsp wline = NULL;
2998 30f8fd5e 2019-06-04 stsp if (width < view->ncols - 1)
2999 f7d12f7e 2018-08-01 stsp waddch(view->window, '\n');
3000 ab089a2a 2018-07-12 stsp
3001 084063cd 2018-07-12 stsp if (asprintf(&line, "[%d/%d] %s%s",
3002 084063cd 2018-07-12 stsp *first_displayed_line - 1 + selected_line, nlines,
3003 512d0df1 2019-02-22 stsp blame_complete ? "" : "annotating... ", path) == -1) {
3004 ab089a2a 2018-07-12 stsp free(id_str);
3005 638f9024 2019-05-13 stsp return got_error_from_errno("asprintf");
3006 ab089a2a 2018-07-12 stsp }
3007 ab089a2a 2018-07-12 stsp free(id_str);
3008 f7d12f7e 2018-08-01 stsp err = format_line(&wline, &width, line, view->ncols);
3009 3f60a8ef 2018-07-10 stsp free(line);
3010 2550e4c3 2018-07-13 stsp line = NULL;
3011 3f60a8ef 2018-07-10 stsp if (err)
3012 3f60a8ef 2018-07-10 stsp return err;
3013 f7d12f7e 2018-08-01 stsp waddwstr(view->window, wline);
3014 2550e4c3 2018-07-13 stsp free(wline);
3015 2550e4c3 2018-07-13 stsp wline = NULL;
3016 30f8fd5e 2019-06-04 stsp if (width < view->ncols - 1)
3017 f7d12f7e 2018-08-01 stsp waddch(view->window, '\n');
3018 3f60a8ef 2018-07-10 stsp
3019 84451b3e 2018-07-10 stsp *eof = 0;
3020 ab089a2a 2018-07-12 stsp while (nprinted < max_lines - 2) {
3021 84451b3e 2018-07-10 stsp line = parse_next_line(f, &len);
3022 84451b3e 2018-07-10 stsp if (line == NULL) {
3023 84451b3e 2018-07-10 stsp *eof = 1;
3024 84451b3e 2018-07-10 stsp break;
3025 84451b3e 2018-07-10 stsp }
3026 84451b3e 2018-07-10 stsp if (++lineno < *first_displayed_line) {
3027 84451b3e 2018-07-10 stsp free(line);
3028 84451b3e 2018-07-10 stsp continue;
3029 84451b3e 2018-07-10 stsp }
3030 84451b3e 2018-07-10 stsp
3031 f7d12f7e 2018-08-01 stsp wlimit = view->ncols < 9 ? 0 : view->ncols - 9;
3032 b700b5d6 2018-07-10 stsp err = format_line(&wline, &width, line, wlimit);
3033 84451b3e 2018-07-10 stsp if (err) {
3034 84451b3e 2018-07-10 stsp free(line);
3035 84451b3e 2018-07-10 stsp return err;
3036 84451b3e 2018-07-10 stsp }
3037 84451b3e 2018-07-10 stsp
3038 0cf4efb1 2018-09-29 stsp if (view->focussed && nprinted == selected_line - 1)
3039 f7d12f7e 2018-08-01 stsp wstandout(view->window);
3040 b700b5d6 2018-07-10 stsp
3041 8d0fe45a 2019-08-12 stsp if (nlines > 0) {
3042 8d0fe45a 2019-08-12 stsp blame_line = &lines[lineno - 1];
3043 8d0fe45a 2019-08-12 stsp if (blame_line->annotated && prev_id &&
3044 8d0fe45a 2019-08-12 stsp got_object_id_cmp(prev_id, blame_line->id) == 0)
3045 8d0fe45a 2019-08-12 stsp waddstr(view->window, " ");
3046 8d0fe45a 2019-08-12 stsp else if (blame_line->annotated) {
3047 8d0fe45a 2019-08-12 stsp char *id_str;
3048 8d0fe45a 2019-08-12 stsp err = got_object_id_str(&id_str, blame_line->id);
3049 8d0fe45a 2019-08-12 stsp if (err) {
3050 8d0fe45a 2019-08-12 stsp free(line);
3051 8d0fe45a 2019-08-12 stsp free(wline);
3052 8d0fe45a 2019-08-12 stsp return err;
3053 8d0fe45a 2019-08-12 stsp }
3054 8d0fe45a 2019-08-12 stsp wprintw(view->window, "%.8s ", id_str);
3055 8d0fe45a 2019-08-12 stsp free(id_str);
3056 8d0fe45a 2019-08-12 stsp prev_id = blame_line->id;
3057 8d0fe45a 2019-08-12 stsp } else {
3058 8d0fe45a 2019-08-12 stsp waddstr(view->window, "........ ");
3059 8d0fe45a 2019-08-12 stsp prev_id = NULL;
3060 84451b3e 2018-07-10 stsp }
3061 ee41ec32 2018-07-10 stsp } else {
3062 f7d12f7e 2018-08-01 stsp waddstr(view->window, "........ ");
3063 ee41ec32 2018-07-10 stsp prev_id = NULL;
3064 ee41ec32 2018-07-10 stsp }
3065 84451b3e 2018-07-10 stsp
3066 f7d12f7e 2018-08-01 stsp waddwstr(view->window, wline);
3067 b700b5d6 2018-07-10 stsp while (width < wlimit) {
3068 f7d12f7e 2018-08-01 stsp waddch(view->window, ' ');
3069 b700b5d6 2018-07-10 stsp width++;
3070 b700b5d6 2018-07-10 stsp }
3071 0cf4efb1 2018-09-29 stsp if (view->focussed && nprinted == selected_line - 1)
3072 f7d12f7e 2018-08-01 stsp wstandend(view->window);
3073 84451b3e 2018-07-10 stsp if (++nprinted == 1)
3074 84451b3e 2018-07-10 stsp *first_displayed_line = lineno;
3075 84451b3e 2018-07-10 stsp free(line);
3076 2550e4c3 2018-07-13 stsp free(wline);
3077 2550e4c3 2018-07-13 stsp wline = NULL;
3078 84451b3e 2018-07-10 stsp }
3079 84451b3e 2018-07-10 stsp *last_displayed_line = lineno;
3080 84451b3e 2018-07-10 stsp
3081 1a57306a 2018-09-02 stsp view_vborder(view);
3082 84451b3e 2018-07-10 stsp
3083 84451b3e 2018-07-10 stsp return NULL;
3084 84451b3e 2018-07-10 stsp }
3085 84451b3e 2018-07-10 stsp
3086 84451b3e 2018-07-10 stsp static const struct got_error *
3087 84451b3e 2018-07-10 stsp blame_cb(void *arg, int nlines, int lineno, struct got_object_id *id)
3088 84451b3e 2018-07-10 stsp {
3089 84451b3e 2018-07-10 stsp const struct got_error *err = NULL;
3090 84451b3e 2018-07-10 stsp struct tog_blame_cb_args *a = arg;
3091 84451b3e 2018-07-10 stsp struct tog_blame_line *line;
3092 1a76625f 2018-10-22 stsp int errcode;
3093 84451b3e 2018-07-10 stsp
3094 d68a0a7d 2018-07-10 stsp if (nlines != a->nlines ||
3095 d68a0a7d 2018-07-10 stsp (lineno != -1 && lineno < 1) || lineno > a->nlines)
3096 84451b3e 2018-07-10 stsp return got_error(GOT_ERR_RANGE);
3097 84451b3e 2018-07-10 stsp
3098 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
3099 1a76625f 2018-10-22 stsp if (errcode)
3100 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_mutex_lock");
3101 84451b3e 2018-07-10 stsp
3102 18430de3 2018-07-10 stsp if (*a->quit) { /* user has quit the blame view */
3103 d68a0a7d 2018-07-10 stsp err = got_error(GOT_ERR_ITER_COMPLETED);
3104 d68a0a7d 2018-07-10 stsp goto done;
3105 d68a0a7d 2018-07-10 stsp }
3106 d68a0a7d 2018-07-10 stsp
3107 d68a0a7d 2018-07-10 stsp if (lineno == -1)
3108 d68a0a7d 2018-07-10 stsp goto done; /* no change in this commit */
3109 d68a0a7d 2018-07-10 stsp
3110 84451b3e 2018-07-10 stsp line = &a->lines[lineno - 1];
3111 d68a0a7d 2018-07-10 stsp if (line->annotated)
3112 d68a0a7d 2018-07-10 stsp goto done;
3113 d68a0a7d 2018-07-10 stsp
3114 84451b3e 2018-07-10 stsp line->id = got_object_id_dup(id);
3115 84451b3e 2018-07-10 stsp if (line->id == NULL) {
3116 638f9024 2019-05-13 stsp err = got_error_from_errno("got_object_id_dup");
3117 84451b3e 2018-07-10 stsp goto done;
3118 84451b3e 2018-07-10 stsp }
3119 84451b3e 2018-07-10 stsp line->annotated = 1;
3120 84451b3e 2018-07-10 stsp done:
3121 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
3122 1a76625f 2018-10-22 stsp if (errcode)
3123 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode, "pthread_mutex_unlock");
3124 84451b3e 2018-07-10 stsp return err;
3125 84451b3e 2018-07-10 stsp }
3126 84451b3e 2018-07-10 stsp
3127 84451b3e 2018-07-10 stsp static void *
3128 84451b3e 2018-07-10 stsp blame_thread(void *arg)
3129 84451b3e 2018-07-10 stsp {
3130 18430de3 2018-07-10 stsp const struct got_error *err;
3131 18430de3 2018-07-10 stsp struct tog_blame_thread_args *ta = arg;
3132 245d91c1 2018-07-12 stsp struct tog_blame_cb_args *a = ta->cb_args;
3133 1a76625f 2018-10-22 stsp int errcode;
3134 18430de3 2018-07-10 stsp
3135 ab089a2a 2018-07-12 stsp err = got_blame_incremental(ta->path, a->commit_id, ta->repo,
3136 245d91c1 2018-07-12 stsp blame_cb, ta->cb_args);
3137 18430de3 2018-07-10 stsp
3138 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
3139 1a76625f 2018-10-22 stsp if (errcode)
3140 2af4a041 2019-05-11 jcs return (void *)got_error_set_errno(errcode,
3141 2af4a041 2019-05-11 jcs "pthread_mutex_lock");
3142 18430de3 2018-07-10 stsp
3143 c9beca56 2018-07-22 stsp got_repo_close(ta->repo);
3144 c9beca56 2018-07-22 stsp ta->repo = NULL;
3145 c9beca56 2018-07-22 stsp *ta->complete = 1;
3146 18430de3 2018-07-10 stsp
3147 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
3148 1a76625f 2018-10-22 stsp if (errcode && err == NULL)
3149 2af4a041 2019-05-11 jcs err = got_error_set_errno(errcode, "pthread_mutex_unlock");
3150 18430de3 2018-07-10 stsp
3151 18430de3 2018-07-10 stsp return (void *)err;
3152 84451b3e 2018-07-10 stsp }
3153 84451b3e 2018-07-10 stsp
3154 245d91c1 2018-07-12 stsp static struct got_object_id *
3155 8d0fe45a 2019-08-12 stsp get_selected_commit_id(struct tog_blame_line *lines, int nlines,
3156 8d0fe45a 2019-08-12 stsp int first_displayed_line, int selected_line)
3157 245d91c1 2018-07-12 stsp {
3158 245d91c1 2018-07-12 stsp struct tog_blame_line *line;
3159 8d0fe45a 2019-08-12 stsp
3160 8d0fe45a 2019-08-12 stsp if (nlines <= 0)
3161 8d0fe45a 2019-08-12 stsp return NULL;
3162 b880a918 2018-07-10 stsp
3163 245d91c1 2018-07-12 stsp line = &lines[first_displayed_line - 1 + selected_line - 1];
3164 245d91c1 2018-07-12 stsp if (!line->annotated)
3165 245d91c1 2018-07-12 stsp return NULL;
3166 245d91c1 2018-07-12 stsp
3167 245d91c1 2018-07-12 stsp return line->id;
3168 b880a918 2018-07-10 stsp }
3169 245d91c1 2018-07-12 stsp
3170 b880a918 2018-07-10 stsp static const struct got_error *
3171 245d91c1 2018-07-12 stsp stop_blame(struct tog_blame *blame)
3172 a70480e0 2018-06-23 stsp {
3173 a70480e0 2018-06-23 stsp const struct got_error *err = NULL;
3174 245d91c1 2018-07-12 stsp int i;
3175 245d91c1 2018-07-12 stsp
3176 245d91c1 2018-07-12 stsp if (blame->thread) {
3177 1a76625f 2018-10-22 stsp int errcode;
3178 1a76625f 2018-10-22 stsp errcode = pthread_mutex_unlock(&tog_mutex);
3179 1a76625f 2018-10-22 stsp if (errcode)
3180 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
3181 2af4a041 2019-05-11 jcs "pthread_mutex_unlock");
3182 1a76625f 2018-10-22 stsp errcode = pthread_join(blame->thread, (void **)&err);
3183 1a76625f 2018-10-22 stsp if (errcode)
3184 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_join");
3185 1a76625f 2018-10-22 stsp errcode = pthread_mutex_lock(&tog_mutex);
3186 1a76625f 2018-10-22 stsp if (errcode)
3187 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode,
3188 2af4a041 2019-05-11 jcs "pthread_mutex_lock");
3189 245d91c1 2018-07-12 stsp if (err && err->code == GOT_ERR_ITER_COMPLETED)
3190 245d91c1 2018-07-12 stsp err = NULL;
3191 245d91c1 2018-07-12 stsp blame->thread = NULL;
3192 245d91c1 2018-07-12 stsp }
3193 245d91c1 2018-07-12 stsp if (blame->thread_args.repo) {
3194 245d91c1 2018-07-12 stsp got_repo_close(blame->thread_args.repo);
3195 245d91c1 2018-07-12 stsp blame->thread_args.repo = NULL;
3196 245d91c1 2018-07-12 stsp }
3197 245d91c1 2018-07-12 stsp if (blame->f) {
3198 fb43ecf1 2019-02-11 stsp if (fclose(blame->f) != 0 && err == NULL)
3199 638f9024 2019-05-13 stsp err = got_error_from_errno("fclose");
3200 245d91c1 2018-07-12 stsp blame->f = NULL;
3201 245d91c1 2018-07-12 stsp }
3202 57670559 2018-12-23 stsp if (blame->lines) {
3203 57670559 2018-12-23 stsp for (i = 0; i < blame->nlines; i++)
3204 57670559 2018-12-23 stsp free(blame->lines[i].id);
3205 57670559 2018-12-23 stsp free(blame->lines);
3206 57670559 2018-12-23 stsp blame->lines = NULL;
3207 57670559 2018-12-23 stsp }
3208 75c32340 2018-07-23 stsp free(blame->cb_args.commit_id);
3209 75c32340 2018-07-23 stsp blame->cb_args.commit_id = NULL;
3210 245d91c1 2018-07-12 stsp
3211 245d91c1 2018-07-12 stsp return err;
3212 245d91c1 2018-07-12 stsp }
3213 245d91c1 2018-07-12 stsp
3214 245d91c1 2018-07-12 stsp static const struct got_error *
3215 1a76625f 2018-10-22 stsp run_blame(struct tog_blame *blame, struct tog_view *view, int *blame_complete,
3216 1a76625f 2018-10-22 stsp int *first_displayed_line, int *last_displayed_line, int *selected_line,
3217 1a76625f 2018-10-22 stsp int *done, int *eof, const char *path, struct got_object_id *commit_id,
3218 245d91c1 2018-07-12 stsp struct got_repository *repo)
3219 245d91c1 2018-07-12 stsp {
3220 245d91c1 2018-07-12 stsp const struct got_error *err = NULL;
3221 84451b3e 2018-07-10 stsp struct got_blob_object *blob = NULL;
3222 245d91c1 2018-07-12 stsp struct got_repository *thread_repo = NULL;
3223 27d434c2 2018-09-15 stsp struct got_object_id *obj_id = NULL;
3224 15a94983 2018-12-23 stsp int obj_type;
3225 a70480e0 2018-06-23 stsp
3226 27d434c2 2018-09-15 stsp err = got_object_id_by_path(&obj_id, repo, commit_id, path);
3227 27d434c2 2018-09-15 stsp if (err)
3228 15a94983 2018-12-23 stsp return err;
3229 15a94983 2018-12-23 stsp if (obj_id == NULL)
3230 15a94983 2018-12-23 stsp return got_error(GOT_ERR_NO_OBJ);
3231 27d434c2 2018-09-15 stsp
3232 15a94983 2018-12-23 stsp err = got_object_get_type(&obj_type, repo, obj_id);
3233 84451b3e 2018-07-10 stsp if (err)
3234 84451b3e 2018-07-10 stsp goto done;
3235 27d434c2 2018-09-15 stsp
3236 15a94983 2018-12-23 stsp if (obj_type != GOT_OBJ_TYPE_BLOB) {
3237 84451b3e 2018-07-10 stsp err = got_error(GOT_ERR_OBJ_TYPE);
3238 84451b3e 2018-07-10 stsp goto done;
3239 84451b3e 2018-07-10 stsp }
3240 a70480e0 2018-06-23 stsp
3241 15a94983 2018-12-23 stsp err = got_object_open_as_blob(&blob, repo, obj_id, 8192);
3242 a70480e0 2018-06-23 stsp if (err)
3243 a70480e0 2018-06-23 stsp goto done;
3244 245d91c1 2018-07-12 stsp blame->f = got_opentemp();
3245 245d91c1 2018-07-12 stsp if (blame->f == NULL) {
3246 638f9024 2019-05-13 stsp err = got_error_from_errno("got_opentemp");
3247 84451b3e 2018-07-10 stsp goto done;
3248 84451b3e 2018-07-10 stsp }
3249 245d91c1 2018-07-12 stsp err = got_object_blob_dump_to_file(&blame->filesize, &blame->nlines,
3250 6c4c42e0 2019-06-24 stsp &blame->line_offsets, blame->f, blob);
3251 84451b3e 2018-07-10 stsp if (err)
3252 84451b3e 2018-07-10 stsp goto done;
3253 a70480e0 2018-06-23 stsp
3254 245d91c1 2018-07-12 stsp blame->lines = calloc(blame->nlines, sizeof(*blame->lines));
3255 245d91c1 2018-07-12 stsp if (blame->lines == NULL) {
3256 638f9024 2019-05-13 stsp err = got_error_from_errno("calloc");
3257 84451b3e 2018-07-10 stsp goto done;
3258 84451b3e 2018-07-10 stsp }
3259 a70480e0 2018-06-23 stsp
3260 245d91c1 2018-07-12 stsp err = got_repo_open(&thread_repo, got_repo_get_path(repo));
3261 bd24772e 2018-07-11 stsp if (err)
3262 bd24772e 2018-07-11 stsp goto done;
3263 bd24772e 2018-07-11 stsp
3264 7cc84d77 2018-08-01 stsp blame->cb_args.view = view;
3265 245d91c1 2018-07-12 stsp blame->cb_args.lines = blame->lines;
3266 245d91c1 2018-07-12 stsp blame->cb_args.nlines = blame->nlines;
3267 245d91c1 2018-07-12 stsp blame->cb_args.commit_id = got_object_id_dup(commit_id);
3268 245d91c1 2018-07-12 stsp if (blame->cb_args.commit_id == NULL) {
3269 638f9024 2019-05-13 stsp err = got_error_from_errno("got_object_id_dup");
3270 245d91c1 2018-07-12 stsp goto done;
3271 245d91c1 2018-07-12 stsp }
3272 245d91c1 2018-07-12 stsp blame->cb_args.quit = done;
3273 245d91c1 2018-07-12 stsp
3274 245d91c1 2018-07-12 stsp blame->thread_args.path = path;
3275 245d91c1 2018-07-12 stsp blame->thread_args.repo = thread_repo;
3276 245d91c1 2018-07-12 stsp blame->thread_args.cb_args = &blame->cb_args;
3277 245d91c1 2018-07-12 stsp blame->thread_args.complete = blame_complete;
3278 245d91c1 2018-07-12 stsp *blame_complete = 0;
3279 245d91c1 2018-07-12 stsp
3280 245d91c1 2018-07-12 stsp done:
3281 245d91c1 2018-07-12 stsp if (blob)
3282 245d91c1 2018-07-12 stsp got_object_blob_close(blob);
3283 27d434c2 2018-09-15 stsp free(obj_id);
3284 245d91c1 2018-07-12 stsp if (err)
3285 245d91c1 2018-07-12 stsp stop_blame(blame);
3286 245d91c1 2018-07-12 stsp return err;
3287 245d91c1 2018-07-12 stsp }
3288 245d91c1 2018-07-12 stsp
3289 245d91c1 2018-07-12 stsp static const struct got_error *
3290 e5a0f69f 2018-08-18 stsp open_blame_view(struct tog_view *view, char *path,
3291 8b473291 2019-02-21 stsp struct got_object_id *commit_id, struct got_reflist_head *refs,
3292 8b473291 2019-02-21 stsp struct got_repository *repo)
3293 245d91c1 2018-07-12 stsp {
3294 7cbe629d 2018-08-04 stsp const struct got_error *err = NULL;
3295 fb2756b9 2018-08-04 stsp struct tog_blame_view_state *s = &view->state.blame;
3296 dbc6a6b6 2018-07-12 stsp
3297 fb2756b9 2018-08-04 stsp SIMPLEQ_INIT(&s->blamed_commits);
3298 245d91c1 2018-07-12 stsp
3299 c4843652 2019-08-12 stsp s->path = strdup(path);
3300 c4843652 2019-08-12 stsp if (s->path == NULL)
3301 c4843652 2019-08-12 stsp return got_error_from_errno("strdup");
3302 c4843652 2019-08-12 stsp
3303 fb2756b9 2018-08-04 stsp err = got_object_qid_alloc(&s->blamed_commit, commit_id);
3304 c4843652 2019-08-12 stsp if (err) {
3305 c4843652 2019-08-12 stsp free(s->path);
3306 7cbe629d 2018-08-04 stsp return err;
3307 c4843652 2019-08-12 stsp }
3308 245d91c1 2018-07-12 stsp
3309 fb2756b9 2018-08-04 stsp SIMPLEQ_INSERT_HEAD(&s->blamed_commits, s->blamed_commit, entry);
3310 fb2756b9 2018-08-04 stsp s->first_displayed_line = 1;
3311 fb2756b9 2018-08-04 stsp s->last_displayed_line = view->nlines;
3312 fb2756b9 2018-08-04 stsp s->selected_line = 1;
3313 fb2756b9 2018-08-04 stsp s->blame_complete = 0;
3314 fb2756b9 2018-08-04 stsp s->repo = repo;
3315 8b473291 2019-02-21 stsp s->refs = refs;
3316 fb2756b9 2018-08-04 stsp s->commit_id = commit_id;
3317 e9424729 2018-08-04 stsp memset(&s->blame, 0, sizeof(s->blame));
3318 7cbe629d 2018-08-04 stsp
3319 e5a0f69f 2018-08-18 stsp view->show = show_blame_view;
3320 e5a0f69f 2018-08-18 stsp view->input = input_blame_view;
3321 e5a0f69f 2018-08-18 stsp view->close = close_blame_view;
3322 6c4c42e0 2019-06-24 stsp view->search_start = search_start_blame_view;
3323 6c4c42e0 2019-06-24 stsp view->search_next = search_next_blame_view;
3324 e5a0f69f 2018-08-18 stsp
3325 1a76625f 2018-10-22 stsp return run_blame(&s->blame, view, &s->blame_complete,
3326 e5a0f69f 2018-08-18 stsp &s->first_displayed_line, &s->last_displayed_line,
3327 e5a0f69f 2018-08-18 stsp &s->selected_line, &s->done, &s->eof, s->path,
3328 e5a0f69f 2018-08-18 stsp s->blamed_commit->id, s->repo);
3329 7cbe629d 2018-08-04 stsp }
3330 7cbe629d 2018-08-04 stsp
3331 e5a0f69f 2018-08-18 stsp static const struct got_error *
3332 7cbe629d 2018-08-04 stsp close_blame_view(struct tog_view *view)
3333 7cbe629d 2018-08-04 stsp {
3334 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
3335 fb2756b9 2018-08-04 stsp struct tog_blame_view_state *s = &view->state.blame;
3336 7cbe629d 2018-08-04 stsp
3337 e5a0f69f 2018-08-18 stsp if (s->blame.thread)
3338 e5a0f69f 2018-08-18 stsp err = stop_blame(&s->blame);
3339 e5a0f69f 2018-08-18 stsp
3340 fb2756b9 2018-08-04 stsp while (!SIMPLEQ_EMPTY(&s->blamed_commits)) {
3341 7cbe629d 2018-08-04 stsp struct got_object_qid *blamed_commit;
3342 fb2756b9 2018-08-04 stsp blamed_commit = SIMPLEQ_FIRST(&s->blamed_commits);
3343 fb2756b9 2018-08-04 stsp SIMPLEQ_REMOVE_HEAD(&s->blamed_commits, entry);
3344 7cbe629d 2018-08-04 stsp got_object_qid_free(blamed_commit);
3345 7cbe629d 2018-08-04 stsp }
3346 e5a0f69f 2018-08-18 stsp
3347 e5a0f69f 2018-08-18 stsp free(s->path);
3348 e5a0f69f 2018-08-18 stsp
3349 e5a0f69f 2018-08-18 stsp return err;
3350 7cbe629d 2018-08-04 stsp }
3351 7cbe629d 2018-08-04 stsp
3352 7cbe629d 2018-08-04 stsp static const struct got_error *
3353 6c4c42e0 2019-06-24 stsp search_start_blame_view(struct tog_view *view)
3354 6c4c42e0 2019-06-24 stsp {
3355 6c4c42e0 2019-06-24 stsp struct tog_blame_view_state *s = &view->state.blame;
3356 6c4c42e0 2019-06-24 stsp
3357 6c4c42e0 2019-06-24 stsp s->matched_line = 0;
3358 6c4c42e0 2019-06-24 stsp return NULL;
3359 6c4c42e0 2019-06-24 stsp }
3360 6c4c42e0 2019-06-24 stsp
3361 6c4c42e0 2019-06-24 stsp static int
3362 6c4c42e0 2019-06-24 stsp match_line(const char *line, regex_t *regex)
3363 6c4c42e0 2019-06-24 stsp {
3364 6c4c42e0 2019-06-24 stsp regmatch_t regmatch;
3365 6c4c42e0 2019-06-24 stsp
3366 6c4c42e0 2019-06-24 stsp return regexec(regex, line, 1, &regmatch, 0) == 0;
3367 6c4c42e0 2019-06-24 stsp }
3368 6c4c42e0 2019-06-24 stsp
3369 6c4c42e0 2019-06-24 stsp
3370 6c4c42e0 2019-06-24 stsp static const struct got_error *
3371 6c4c42e0 2019-06-24 stsp search_next_blame_view(struct tog_view *view)
3372 6c4c42e0 2019-06-24 stsp {
3373 6c4c42e0 2019-06-24 stsp struct tog_blame_view_state *s = &view->state.blame;
3374 6c4c42e0 2019-06-24 stsp int lineno;
3375 6c4c42e0 2019-06-24 stsp
3376 6c4c42e0 2019-06-24 stsp if (!view->searching) {
3377 6c4c42e0 2019-06-24 stsp view->search_next_done = 1;
3378 6c4c42e0 2019-06-24 stsp return NULL;
3379 6c4c42e0 2019-06-24 stsp }
3380 6c4c42e0 2019-06-24 stsp
3381 6c4c42e0 2019-06-24 stsp if (s->matched_line) {
3382 6c4c42e0 2019-06-24 stsp if (view->searching == TOG_SEARCH_FORWARD)
3383 2246482e 2019-06-25 stsp lineno = s->matched_line + 1;
3384 6c4c42e0 2019-06-24 stsp else
3385 2246482e 2019-06-25 stsp lineno = s->matched_line - 1;
3386 6c4c42e0 2019-06-24 stsp } else {
3387 6c4c42e0 2019-06-24 stsp if (view->searching == TOG_SEARCH_FORWARD)
3388 6c4c42e0 2019-06-24 stsp lineno = 1;
3389 6c4c42e0 2019-06-24 stsp else
3390 6c4c42e0 2019-06-24 stsp lineno = s->blame.nlines;
3391 6c4c42e0 2019-06-24 stsp }
3392 6c4c42e0 2019-06-24 stsp
3393 6c4c42e0 2019-06-24 stsp while (1) {
3394 6c4c42e0 2019-06-24 stsp char *line = NULL;
3395 6c4c42e0 2019-06-24 stsp off_t offset;
3396 6c4c42e0 2019-06-24 stsp size_t len;
3397 6c4c42e0 2019-06-24 stsp
3398 6c4c42e0 2019-06-24 stsp if (lineno <= 0 || lineno > s->blame.nlines) {
3399 6c4c42e0 2019-06-24 stsp if (s->matched_line == 0) {
3400 6c4c42e0 2019-06-24 stsp view->search_next_done = 1;
3401 6c4c42e0 2019-06-24 stsp free(line);
3402 6c4c42e0 2019-06-24 stsp break;
3403 6c4c42e0 2019-06-24 stsp }
3404 2246482e 2019-06-25 stsp
3405 6c4c42e0 2019-06-24 stsp if (view->searching == TOG_SEARCH_FORWARD)
3406 6c4c42e0 2019-06-24 stsp lineno = 1;
3407 6c4c42e0 2019-06-24 stsp else
3408 6c4c42e0 2019-06-24 stsp lineno = s->blame.nlines;
3409 6c4c42e0 2019-06-24 stsp }
3410 6c4c42e0 2019-06-24 stsp
3411 6c4c42e0 2019-06-24 stsp offset = s->blame.line_offsets[lineno - 1];
3412 6c4c42e0 2019-06-24 stsp if (fseeko(s->blame.f, offset, SEEK_SET) != 0) {
3413 6c4c42e0 2019-06-24 stsp free(line);
3414 6c4c42e0 2019-06-24 stsp return got_error_from_errno("fseeko");
3415 6c4c42e0 2019-06-24 stsp }
3416 6c4c42e0 2019-06-24 stsp free(line);
3417 6c4c42e0 2019-06-24 stsp line = parse_next_line(s->blame.f, &len);
3418 2246482e 2019-06-25 stsp if (line && match_line(line, &view->regex)) {
3419 6c4c42e0 2019-06-24 stsp view->search_next_done = 1;
3420 6c4c42e0 2019-06-24 stsp s->matched_line = lineno;
3421 6c4c42e0 2019-06-24 stsp free(line);
3422 6c4c42e0 2019-06-24 stsp break;
3423 6c4c42e0 2019-06-24 stsp }
3424 6c4c42e0 2019-06-24 stsp free(line);
3425 6c4c42e0 2019-06-24 stsp if (view->searching == TOG_SEARCH_FORWARD)
3426 6c4c42e0 2019-06-24 stsp lineno++;
3427 6c4c42e0 2019-06-24 stsp else
3428 6c4c42e0 2019-06-24 stsp lineno--;
3429 6c4c42e0 2019-06-24 stsp }
3430 6c4c42e0 2019-06-24 stsp
3431 6c4c42e0 2019-06-24 stsp if (s->matched_line) {
3432 6c4c42e0 2019-06-24 stsp s->first_displayed_line = s->matched_line;
3433 6c4c42e0 2019-06-24 stsp s->selected_line = 1;
3434 6c4c42e0 2019-06-24 stsp }
3435 6c4c42e0 2019-06-24 stsp
3436 6c4c42e0 2019-06-24 stsp return NULL;
3437 6c4c42e0 2019-06-24 stsp }
3438 6c4c42e0 2019-06-24 stsp
3439 6c4c42e0 2019-06-24 stsp static const struct got_error *
3440 7cbe629d 2018-08-04 stsp show_blame_view(struct tog_view *view)
3441 7cbe629d 2018-08-04 stsp {
3442 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
3443 e5a0f69f 2018-08-18 stsp struct tog_blame_view_state *s = &view->state.blame;
3444 2b380cc8 2018-10-24 stsp int errcode;
3445 2b380cc8 2018-10-24 stsp
3446 2b380cc8 2018-10-24 stsp if (s->blame.thread == NULL) {
3447 2b380cc8 2018-10-24 stsp errcode = pthread_create(&s->blame.thread, NULL, blame_thread,
3448 2b380cc8 2018-10-24 stsp &s->blame.thread_args);
3449 2b380cc8 2018-10-24 stsp if (errcode)
3450 2af4a041 2019-05-11 jcs return got_error_set_errno(errcode, "pthread_create");
3451 2b380cc8 2018-10-24 stsp }
3452 e5a0f69f 2018-08-18 stsp
3453 e5a0f69f 2018-08-18 stsp err = draw_blame(view, s->blamed_commit->id, s->blame.f,
3454 e5a0f69f 2018-08-18 stsp s->path, s->blame.lines, s->blame.nlines, s->blame_complete,
3455 e5a0f69f 2018-08-18 stsp s->selected_line, &s->first_displayed_line,
3456 e5a0f69f 2018-08-18 stsp &s->last_displayed_line, &s->eof, view->nlines);
3457 e5a0f69f 2018-08-18 stsp
3458 669b5ffa 2018-10-07 stsp view_vborder(view);
3459 e5a0f69f 2018-08-18 stsp return err;
3460 e5a0f69f 2018-08-18 stsp }
3461 e5a0f69f 2018-08-18 stsp
3462 e5a0f69f 2018-08-18 stsp static const struct got_error *
3463 878940b7 2018-09-29 stsp input_blame_view(struct tog_view **new_view, struct tog_view **dead_view,
3464 878940b7 2018-09-29 stsp struct tog_view **focus_view, struct tog_view *view, int ch)
3465 e5a0f69f 2018-08-18 stsp {
3466 7cbe629d 2018-08-04 stsp const struct got_error *err = NULL, *thread_err = NULL;
3467 7cbe629d 2018-08-04 stsp struct tog_view *diff_view;
3468 fb2756b9 2018-08-04 stsp struct tog_blame_view_state *s = &view->state.blame;
3469 669b5ffa 2018-10-07 stsp int begin_x = 0;
3470 7cbe629d 2018-08-04 stsp
3471 e5a0f69f 2018-08-18 stsp switch (ch) {
3472 1e37a5c2 2019-05-12 jcs case 'q':
3473 1e37a5c2 2019-05-12 jcs s->done = 1;
3474 1e37a5c2 2019-05-12 jcs break;
3475 1e37a5c2 2019-05-12 jcs case 'k':
3476 1e37a5c2 2019-05-12 jcs case KEY_UP:
3477 1e37a5c2 2019-05-12 jcs if (s->selected_line > 1)
3478 1e37a5c2 2019-05-12 jcs s->selected_line--;
3479 1e37a5c2 2019-05-12 jcs else if (s->selected_line == 1 &&
3480 1e37a5c2 2019-05-12 jcs s->first_displayed_line > 1)
3481 1e37a5c2 2019-05-12 jcs s->first_displayed_line--;
3482 1e37a5c2 2019-05-12 jcs break;
3483 1e37a5c2 2019-05-12 jcs case KEY_PPAGE:
3484 1e37a5c2 2019-05-12 jcs if (s->first_displayed_line == 1) {
3485 1e37a5c2 2019-05-12 jcs s->selected_line = 1;
3486 e5a0f69f 2018-08-18 stsp break;
3487 1e37a5c2 2019-05-12 jcs }
3488 1e37a5c2 2019-05-12 jcs if (s->first_displayed_line > view->nlines - 2)
3489 1e37a5c2 2019-05-12 jcs s->first_displayed_line -=
3490 1e37a5c2 2019-05-12 jcs (view->nlines - 2);
3491 1e37a5c2 2019-05-12 jcs else
3492 1e37a5c2 2019-05-12 jcs s->first_displayed_line = 1;
3493 1e37a5c2 2019-05-12 jcs break;
3494 1e37a5c2 2019-05-12 jcs case 'j':
3495 1e37a5c2 2019-05-12 jcs case KEY_DOWN:
3496 1e37a5c2 2019-05-12 jcs if (s->selected_line < view->nlines - 2 &&
3497 1e37a5c2 2019-05-12 jcs s->first_displayed_line +
3498 1e37a5c2 2019-05-12 jcs s->selected_line <= s->blame.nlines)
3499 1e37a5c2 2019-05-12 jcs s->selected_line++;
3500 1e37a5c2 2019-05-12 jcs else if (s->last_displayed_line <
3501 1e37a5c2 2019-05-12 jcs s->blame.nlines)
3502 1e37a5c2 2019-05-12 jcs s->first_displayed_line++;
3503 1e37a5c2 2019-05-12 jcs break;
3504 1e37a5c2 2019-05-12 jcs case 'b':
3505 1e37a5c2 2019-05-12 jcs case 'p': {
3506 1e37a5c2 2019-05-12 jcs struct got_object_id *id = NULL;
3507 8d0fe45a 2019-08-12 stsp id = get_selected_commit_id(s->blame.lines, s->blame.nlines,
3508 1e37a5c2 2019-05-12 jcs s->first_displayed_line, s->selected_line);
3509 1e37a5c2 2019-05-12 jcs if (id == NULL)
3510 e5a0f69f 2018-08-18 stsp break;
3511 1e37a5c2 2019-05-12 jcs if (ch == 'p') {
3512 1e37a5c2 2019-05-12 jcs struct got_commit_object *commit;
3513 15a94983 2018-12-23 stsp struct got_object_qid *pid;
3514 1e37a5c2 2019-05-12 jcs struct got_object_id *blob_id = NULL;
3515 1e37a5c2 2019-05-12 jcs int obj_type;
3516 1e37a5c2 2019-05-12 jcs err = got_object_open_as_commit(&commit,
3517 1e37a5c2 2019-05-12 jcs s->repo, id);
3518 e5a0f69f 2018-08-18 stsp if (err)
3519 e5a0f69f 2018-08-18 stsp break;
3520 15a94983 2018-12-23 stsp pid = SIMPLEQ_FIRST(
3521 15a94983 2018-12-23 stsp got_object_commit_get_parent_ids(commit));
3522 1e37a5c2 2019-05-12 jcs if (pid == NULL) {
3523 15a94983 2018-12-23 stsp got_object_commit_close(commit);
3524 e5a0f69f 2018-08-18 stsp break;
3525 e5a0f69f 2018-08-18 stsp }
3526 1e37a5c2 2019-05-12 jcs /* Check if path history ends here. */
3527 1e37a5c2 2019-05-12 jcs err = got_object_id_by_path(&blob_id, s->repo,
3528 1e37a5c2 2019-05-12 jcs pid->id, s->path);
3529 e5a0f69f 2018-08-18 stsp if (err) {
3530 1e37a5c2 2019-05-12 jcs if (err->code == GOT_ERR_NO_TREE_ENTRY)
3531 1e37a5c2 2019-05-12 jcs err = NULL;
3532 1e37a5c2 2019-05-12 jcs got_object_commit_close(commit);
3533 e5a0f69f 2018-08-18 stsp break;
3534 e5a0f69f 2018-08-18 stsp }
3535 1e37a5c2 2019-05-12 jcs err = got_object_get_type(&obj_type, s->repo,
3536 1e37a5c2 2019-05-12 jcs blob_id);
3537 1e37a5c2 2019-05-12 jcs free(blob_id);
3538 1e37a5c2 2019-05-12 jcs /* Can't blame non-blob type objects. */
3539 1e37a5c2 2019-05-12 jcs if (obj_type != GOT_OBJ_TYPE_BLOB) {
3540 1e37a5c2 2019-05-12 jcs got_object_commit_close(commit);
3541 e5a0f69f 2018-08-18 stsp break;
3542 1e37a5c2 2019-05-12 jcs }
3543 1e37a5c2 2019-05-12 jcs err = got_object_qid_alloc(&s->blamed_commit,
3544 1e37a5c2 2019-05-12 jcs pid->id);
3545 1e37a5c2 2019-05-12 jcs got_object_commit_close(commit);
3546 1e37a5c2 2019-05-12 jcs } else {
3547 1e37a5c2 2019-05-12 jcs if (got_object_id_cmp(id,
3548 1e37a5c2 2019-05-12 jcs s->blamed_commit->id) == 0)
3549 1e37a5c2 2019-05-12 jcs break;
3550 1e37a5c2 2019-05-12 jcs err = got_object_qid_alloc(&s->blamed_commit,
3551 1e37a5c2 2019-05-12 jcs id);
3552 1e37a5c2 2019-05-12 jcs }
3553 1e37a5c2 2019-05-12 jcs if (err)
3554 e5a0f69f 2018-08-18 stsp break;
3555 1e37a5c2 2019-05-12 jcs s->done = 1;
3556 1e37a5c2 2019-05-12 jcs thread_err = stop_blame(&s->blame);
3557 1e37a5c2 2019-05-12 jcs s->done = 0;
3558 1e37a5c2 2019-05-12 jcs if (thread_err)
3559 1e37a5c2 2019-05-12 jcs break;
3560 1e37a5c2 2019-05-12 jcs SIMPLEQ_INSERT_HEAD(&s->blamed_commits,
3561 1e37a5c2 2019-05-12 jcs s->blamed_commit, entry);
3562 1e37a5c2 2019-05-12 jcs err = run_blame(&s->blame, view, &s->blame_complete,
3563 1e37a5c2 2019-05-12 jcs &s->first_displayed_line, &s->last_displayed_line,
3564 1e37a5c2 2019-05-12 jcs &s->selected_line, &s->done, &s->eof,
3565 1e37a5c2 2019-05-12 jcs s->path, s->blamed_commit->id, s->repo);
3566 1e37a5c2 2019-05-12 jcs if (err)
3567 1e37a5c2 2019-05-12 jcs break;
3568 1e37a5c2 2019-05-12 jcs break;
3569 1e37a5c2 2019-05-12 jcs }
3570 1e37a5c2 2019-05-12 jcs case 'B': {
3571 1e37a5c2 2019-05-12 jcs struct got_object_qid *first;
3572 1e37a5c2 2019-05-12 jcs first = SIMPLEQ_FIRST(&s->blamed_commits);
3573 1e37a5c2 2019-05-12 jcs if (!got_object_id_cmp(first->id, s->commit_id))
3574 1e37a5c2 2019-05-12 jcs break;
3575 1e37a5c2 2019-05-12 jcs s->done = 1;
3576 1e37a5c2 2019-05-12 jcs thread_err = stop_blame(&s->blame);
3577 1e37a5c2 2019-05-12 jcs s->done = 0;
3578 1e37a5c2 2019-05-12 jcs if (thread_err)
3579 1e37a5c2 2019-05-12 jcs break;
3580 1e37a5c2 2019-05-12 jcs SIMPLEQ_REMOVE_HEAD(&s->blamed_commits, entry);
3581 1e37a5c2 2019-05-12 jcs got_object_qid_free(s->blamed_commit);
3582 1e37a5c2 2019-05-12 jcs s->blamed_commit =
3583 1e37a5c2 2019-05-12 jcs SIMPLEQ_FIRST(&s->blamed_commits);
3584 1e37a5c2 2019-05-12 jcs err = run_blame(&s->blame, view, &s->blame_complete,
3585 1e37a5c2 2019-05-12 jcs &s->first_displayed_line, &s->last_displayed_line,
3586 1e37a5c2 2019-05-12 jcs &s->selected_line, &s->done, &s->eof, s->path,
3587 1e37a5c2 2019-05-12 jcs s->blamed_commit->id, s->repo);
3588 1e37a5c2 2019-05-12 jcs if (err)
3589 1e37a5c2 2019-05-12 jcs break;
3590 1e37a5c2 2019-05-12 jcs break;
3591 1e37a5c2 2019-05-12 jcs }
3592 1e37a5c2 2019-05-12 jcs case KEY_ENTER:
3593 1e37a5c2 2019-05-12 jcs case '\r': {
3594 1e37a5c2 2019-05-12 jcs struct got_object_id *id = NULL;
3595 1e37a5c2 2019-05-12 jcs struct got_object_qid *pid;
3596 1e37a5c2 2019-05-12 jcs struct got_commit_object *commit = NULL;
3597 8d0fe45a 2019-08-12 stsp id = get_selected_commit_id(s->blame.lines, s->blame.nlines,
3598 1e37a5c2 2019-05-12 jcs s->first_displayed_line, s->selected_line);
3599 1e37a5c2 2019-05-12 jcs if (id == NULL)
3600 1e37a5c2 2019-05-12 jcs break;
3601 1e37a5c2 2019-05-12 jcs err = got_object_open_as_commit(&commit, s->repo, id);
3602 1e37a5c2 2019-05-12 jcs if (err)
3603 1e37a5c2 2019-05-12 jcs break;
3604 1e37a5c2 2019-05-12 jcs pid = SIMPLEQ_FIRST(
3605 1e37a5c2 2019-05-12 jcs got_object_commit_get_parent_ids(commit));
3606 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view))
3607 1e37a5c2 2019-05-12 jcs begin_x = view_split_begin_x(view->begin_x);
3608 1e37a5c2 2019-05-12 jcs diff_view = view_open(0, 0, 0, begin_x, TOG_VIEW_DIFF);
3609 1e37a5c2 2019-05-12 jcs if (diff_view == NULL) {
3610 1e37a5c2 2019-05-12 jcs got_object_commit_close(commit);
3611 638f9024 2019-05-13 stsp err = got_error_from_errno("view_open");
3612 1e37a5c2 2019-05-12 jcs break;
3613 15a94983 2018-12-23 stsp }
3614 1e37a5c2 2019-05-12 jcs err = open_diff_view(diff_view, pid ? pid->id : NULL,
3615 1e37a5c2 2019-05-12 jcs id, NULL, s->refs, s->repo);
3616 1e37a5c2 2019-05-12 jcs got_object_commit_close(commit);
3617 1e37a5c2 2019-05-12 jcs if (err) {
3618 1e37a5c2 2019-05-12 jcs view_close(diff_view);
3619 1e37a5c2 2019-05-12 jcs break;
3620 1e37a5c2 2019-05-12 jcs }
3621 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view)) {
3622 1e37a5c2 2019-05-12 jcs err = view_close_child(view);
3623 1e37a5c2 2019-05-12 jcs if (err)
3624 34bc9ec9 2019-02-22 stsp break;
3625 1e37a5c2 2019-05-12 jcs err = view_set_child(view, diff_view);
3626 1e37a5c2 2019-05-12 jcs if (err) {
3627 1e37a5c2 2019-05-12 jcs view_close(diff_view);
3628 e5a0f69f 2018-08-18 stsp break;
3629 e5a0f69f 2018-08-18 stsp }
3630 1e37a5c2 2019-05-12 jcs *focus_view = diff_view;
3631 1e37a5c2 2019-05-12 jcs view->child_focussed = 1;
3632 1e37a5c2 2019-05-12 jcs } else
3633 1e37a5c2 2019-05-12 jcs *new_view = diff_view;
3634 1e37a5c2 2019-05-12 jcs if (err)
3635 e5a0f69f 2018-08-18 stsp break;
3636 1e37a5c2 2019-05-12 jcs break;
3637 1e37a5c2 2019-05-12 jcs }
3638 1e37a5c2 2019-05-12 jcs case KEY_NPAGE:
3639 1e37a5c2 2019-05-12 jcs case ' ':
3640 1e37a5c2 2019-05-12 jcs if (s->last_displayed_line >= s->blame.nlines &&
3641 1e37a5c2 2019-05-12 jcs s->selected_line >= MIN(s->blame.nlines,
3642 00ba99a7 2019-05-12 jcs view->nlines - 2)) {
3643 e5a0f69f 2018-08-18 stsp break;
3644 1e37a5c2 2019-05-12 jcs }
3645 1e37a5c2 2019-05-12 jcs if (s->last_displayed_line >= s->blame.nlines &&
3646 1e37a5c2 2019-05-12 jcs s->selected_line < view->nlines - 2) {
3647 1e37a5c2 2019-05-12 jcs s->selected_line = MIN(s->blame.nlines,
3648 1e37a5c2 2019-05-12 jcs view->nlines - 2);
3649 e5a0f69f 2018-08-18 stsp break;
3650 1e37a5c2 2019-05-12 jcs }
3651 1e37a5c2 2019-05-12 jcs if (s->last_displayed_line + view->nlines - 2
3652 1e37a5c2 2019-05-12 jcs <= s->blame.nlines)
3653 1e37a5c2 2019-05-12 jcs s->first_displayed_line +=
3654 1e37a5c2 2019-05-12 jcs view->nlines - 2;
3655 1e37a5c2 2019-05-12 jcs else
3656 1e37a5c2 2019-05-12 jcs s->first_displayed_line =
3657 1e37a5c2 2019-05-12 jcs s->blame.nlines -
3658 1e37a5c2 2019-05-12 jcs (view->nlines - 3);
3659 1e37a5c2 2019-05-12 jcs break;
3660 1e37a5c2 2019-05-12 jcs case KEY_RESIZE:
3661 1e37a5c2 2019-05-12 jcs if (s->selected_line > view->nlines - 2) {
3662 1e37a5c2 2019-05-12 jcs s->selected_line = MIN(s->blame.nlines,
3663 1e37a5c2 2019-05-12 jcs view->nlines - 2);
3664 1e37a5c2 2019-05-12 jcs }
3665 1e37a5c2 2019-05-12 jcs break;
3666 1e37a5c2 2019-05-12 jcs default:
3667 1e37a5c2 2019-05-12 jcs break;
3668 a70480e0 2018-06-23 stsp }
3669 245d91c1 2018-07-12 stsp return thread_err ? thread_err : err;
3670 a70480e0 2018-06-23 stsp }
3671 a70480e0 2018-06-23 stsp
3672 a70480e0 2018-06-23 stsp static const struct got_error *
3673 9f7d7167 2018-04-29 stsp cmd_blame(int argc, char *argv[])
3674 9f7d7167 2018-04-29 stsp {
3675 a70480e0 2018-06-23 stsp const struct got_error *error;
3676 a70480e0 2018-06-23 stsp struct got_repository *repo = NULL;
3677 8b473291 2019-02-21 stsp struct got_reflist_head refs;
3678 eb41ed75 2019-02-05 stsp struct got_worktree *worktree = NULL;
3679 69069811 2018-08-02 stsp char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
3680 a70480e0 2018-06-23 stsp struct got_object_id *commit_id = NULL;
3681 a70480e0 2018-06-23 stsp char *commit_id_str = NULL;
3682 a70480e0 2018-06-23 stsp int ch;
3683 e1cd8fed 2018-08-01 stsp struct tog_view *view;
3684 a70480e0 2018-06-23 stsp
3685 70ac5f84 2019-03-28 stsp SIMPLEQ_INIT(&refs);
3686 70ac5f84 2019-03-28 stsp
3687 a70480e0 2018-06-23 stsp #ifndef PROFILE
3688 8e94dd5b 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd unveil",
3689 8e94dd5b 2019-01-04 stsp NULL) == -1)
3690 a70480e0 2018-06-23 stsp err(1, "pledge");
3691 a70480e0 2018-06-23 stsp #endif
3692 a70480e0 2018-06-23 stsp
3693 69069811 2018-08-02 stsp while ((ch = getopt(argc, argv, "c:r:")) != -1) {
3694 a70480e0 2018-06-23 stsp switch (ch) {
3695 a70480e0 2018-06-23 stsp case 'c':
3696 a70480e0 2018-06-23 stsp commit_id_str = optarg;
3697 a70480e0 2018-06-23 stsp break;
3698 69069811 2018-08-02 stsp case 'r':
3699 69069811 2018-08-02 stsp repo_path = realpath(optarg, NULL);
3700 69069811 2018-08-02 stsp if (repo_path == NULL)
3701 69069811 2018-08-02 stsp err(1, "-r option");
3702 69069811 2018-08-02 stsp break;
3703 a70480e0 2018-06-23 stsp default:
3704 17020d27 2019-03-07 stsp usage_blame();
3705 a70480e0 2018-06-23 stsp /* NOTREACHED */
3706 a70480e0 2018-06-23 stsp }
3707 a70480e0 2018-06-23 stsp }
3708 a70480e0 2018-06-23 stsp
3709 a70480e0 2018-06-23 stsp argc -= optind;
3710 a70480e0 2018-06-23 stsp argv += optind;
3711 a70480e0 2018-06-23 stsp
3712 69069811 2018-08-02 stsp if (argc == 1)
3713 69069811 2018-08-02 stsp path = argv[0];
3714 69069811 2018-08-02 stsp else
3715 a70480e0 2018-06-23 stsp usage_blame();
3716 69069811 2018-08-02 stsp
3717 69069811 2018-08-02 stsp cwd = getcwd(NULL, 0);
3718 69069811 2018-08-02 stsp if (cwd == NULL) {
3719 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
3720 69069811 2018-08-02 stsp goto done;
3721 69069811 2018-08-02 stsp }
3722 69069811 2018-08-02 stsp if (repo_path == NULL) {
3723 eb41ed75 2019-02-05 stsp error = got_worktree_open(&worktree, cwd);
3724 eb41ed75 2019-02-05 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
3725 69069811 2018-08-02 stsp goto done;
3726 eb41ed75 2019-02-05 stsp else
3727 eb41ed75 2019-02-05 stsp error = NULL;
3728 eb41ed75 2019-02-05 stsp if (worktree) {
3729 eb41ed75 2019-02-05 stsp repo_path =
3730 eb41ed75 2019-02-05 stsp strdup(got_worktree_get_repo_path(worktree));
3731 eb41ed75 2019-02-05 stsp if (repo_path == NULL)
3732 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
3733 eb41ed75 2019-02-05 stsp if (error)
3734 eb41ed75 2019-02-05 stsp goto done;
3735 eb41ed75 2019-02-05 stsp } else {
3736 eb41ed75 2019-02-05 stsp repo_path = strdup(cwd);
3737 eb41ed75 2019-02-05 stsp if (repo_path == NULL) {
3738 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
3739 eb41ed75 2019-02-05 stsp goto done;
3740 eb41ed75 2019-02-05 stsp }
3741 69069811 2018-08-02 stsp }
3742 69069811 2018-08-02 stsp }
3743 a915003a 2019-02-05 stsp
3744 a915003a 2019-02-05 stsp init_curses();
3745 69069811 2018-08-02 stsp
3746 c02c541e 2019-03-29 stsp error = got_repo_open(&repo, repo_path);
3747 c02c541e 2019-03-29 stsp if (error != NULL)
3748 8e94dd5b 2019-01-04 stsp goto done;
3749 69069811 2018-08-02 stsp
3750 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), NULL);
3751 c02c541e 2019-03-29 stsp if (error)
3752 92205607 2019-01-04 stsp goto done;
3753 69069811 2018-08-02 stsp
3754 eb41ed75 2019-02-05 stsp if (worktree) {
3755 eb41ed75 2019-02-05 stsp const char *prefix = got_worktree_get_path_prefix(worktree);
3756 eb41ed75 2019-02-05 stsp char *p, *worktree_subdir = cwd +
3757 eb41ed75 2019-02-05 stsp strlen(got_worktree_get_root_path(worktree));
3758 eb41ed75 2019-02-05 stsp if (asprintf(&p, "%s%s%s%s%s",
3759 eb41ed75 2019-02-05 stsp prefix, (strcmp(prefix, "/") != 0) ? "/" : "",
3760 eb41ed75 2019-02-05 stsp worktree_subdir, worktree_subdir[0] ? "/" : "",
3761 eb41ed75 2019-02-05 stsp path) == -1) {
3762 638f9024 2019-05-13 stsp error = got_error_from_errno("asprintf");
3763 eb41ed75 2019-02-05 stsp goto done;
3764 eb41ed75 2019-02-05 stsp }
3765 eb41ed75 2019-02-05 stsp error = got_repo_map_path(&in_repo_path, repo, p, 0);
3766 eb41ed75 2019-02-05 stsp free(p);
3767 eb41ed75 2019-02-05 stsp } else {
3768 eb41ed75 2019-02-05 stsp error = got_repo_map_path(&in_repo_path, repo, path, 1);
3769 eb41ed75 2019-02-05 stsp }
3770 eb41ed75 2019-02-05 stsp if (error)
3771 69069811 2018-08-02 stsp goto done;
3772 a70480e0 2018-06-23 stsp
3773 a70480e0 2018-06-23 stsp if (commit_id_str == NULL) {
3774 a70480e0 2018-06-23 stsp struct got_reference *head_ref;
3775 2f17228e 2019-05-12 stsp error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
3776 a70480e0 2018-06-23 stsp if (error != NULL)
3777 66b4983c 2018-06-23 stsp goto done;
3778 a70480e0 2018-06-23 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
3779 a70480e0 2018-06-23 stsp got_ref_close(head_ref);
3780 a70480e0 2018-06-23 stsp } else {
3781 f2b6a97d 2019-07-15 stsp error = get_head_commit_id(&commit_id, commit_id_str, repo);
3782 f2b6a97d 2019-07-15 stsp if (error) {
3783 f2b6a97d 2019-07-15 stsp if (error->code != GOT_ERR_NOT_REF)
3784 f2b6a97d 2019-07-15 stsp goto done;
3785 f2b6a97d 2019-07-15 stsp error = got_repo_match_object_id_prefix(&commit_id,
3786 f2b6a97d 2019-07-15 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, repo);
3787 f2b6a97d 2019-07-15 stsp }
3788 a70480e0 2018-06-23 stsp }
3789 a19e88aa 2018-06-23 stsp if (error != NULL)
3790 8b473291 2019-02-21 stsp goto done;
3791 8b473291 2019-02-21 stsp
3792 8b473291 2019-02-21 stsp error = got_ref_list(&refs, repo);
3793 8b473291 2019-02-21 stsp if (error)
3794 a19e88aa 2018-06-23 stsp goto done;
3795 a70480e0 2018-06-23 stsp
3796 0cf4efb1 2018-09-29 stsp view = view_open(0, 0, 0, 0, TOG_VIEW_BLAME);
3797 e1cd8fed 2018-08-01 stsp if (view == NULL) {
3798 638f9024 2019-05-13 stsp error = got_error_from_errno("view_open");
3799 e1cd8fed 2018-08-01 stsp goto done;
3800 e1cd8fed 2018-08-01 stsp }
3801 8b473291 2019-02-21 stsp error = open_blame_view(view, in_repo_path, commit_id, &refs, repo);
3802 7cbe629d 2018-08-04 stsp if (error)
3803 7cbe629d 2018-08-04 stsp goto done;
3804 e5a0f69f 2018-08-18 stsp error = view_loop(view);
3805 a70480e0 2018-06-23 stsp done:
3806 69069811 2018-08-02 stsp free(repo_path);
3807 69069811 2018-08-02 stsp free(cwd);
3808 a70480e0 2018-06-23 stsp free(commit_id);
3809 eb41ed75 2019-02-05 stsp if (worktree)
3810 eb41ed75 2019-02-05 stsp got_worktree_close(worktree);
3811 a70480e0 2018-06-23 stsp if (repo)
3812 a70480e0 2018-06-23 stsp got_repo_close(repo);
3813 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
3814 a70480e0 2018-06-23 stsp return error;
3815 ffd1d5e5 2018-06-23 stsp }
3816 ffd1d5e5 2018-06-23 stsp
3817 ffd1d5e5 2018-06-23 stsp static const struct got_error *
3818 f7d12f7e 2018-08-01 stsp draw_tree_entries(struct tog_view *view,
3819 f7d12f7e 2018-08-01 stsp struct got_tree_entry **first_displayed_entry,
3820 ffd1d5e5 2018-06-23 stsp struct got_tree_entry **last_displayed_entry,
3821 ffd1d5e5 2018-06-23 stsp struct got_tree_entry **selected_entry, int *ndisplayed,
3822 f7d12f7e 2018-08-01 stsp const char *label, int show_ids, const char *parent_path,
3823 ce52c690 2018-06-23 stsp const struct got_tree_entries *entries, int selected, int limit, int isroot)
3824 ffd1d5e5 2018-06-23 stsp {
3825 ffd1d5e5 2018-06-23 stsp const struct got_error *err = NULL;
3826 ffd1d5e5 2018-06-23 stsp struct got_tree_entry *te;
3827 ffd1d5e5 2018-06-23 stsp wchar_t *wline;
3828 ffd1d5e5 2018-06-23 stsp int width, n;
3829 ffd1d5e5 2018-06-23 stsp
3830 ffd1d5e5 2018-06-23 stsp *ndisplayed = 0;
3831 ffd1d5e5 2018-06-23 stsp
3832 f7d12f7e 2018-08-01 stsp werase(view->window);
3833 ffd1d5e5 2018-06-23 stsp
3834 ffd1d5e5 2018-06-23 stsp if (limit == 0)
3835 ffd1d5e5 2018-06-23 stsp return NULL;
3836 ffd1d5e5 2018-06-23 stsp
3837 f7d12f7e 2018-08-01 stsp err = format_line(&wline, &width, label, view->ncols);
3838 ffd1d5e5 2018-06-23 stsp if (err)
3839 ffd1d5e5 2018-06-23 stsp return err;
3840 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
3841 a3404814 2018-09-02 stsp wstandout(view->window);
3842 f7d12f7e 2018-08-01 stsp waddwstr(view->window, wline);
3843 a3404814 2018-09-02 stsp if (view_needs_focus_indication(view))
3844 a3404814 2018-09-02 stsp wstandend(view->window);
3845 2550e4c3 2018-07-13 stsp free(wline);
3846 2550e4c3 2018-07-13 stsp wline = NULL;
3847 30f8fd5e 2019-06-04 stsp if (width < view->ncols - 1)
3848 f7d12f7e 2018-08-01 stsp waddch(view->window, '\n');
3849 ffd1d5e5 2018-06-23 stsp if (--limit <= 0)
3850 ffd1d5e5 2018-06-23 stsp return NULL;
3851 f7d12f7e 2018-08-01 stsp err = format_line(&wline, &width, parent_path, view->ncols);
3852 ce52c690 2018-06-23 stsp if (err)
3853 ce52c690 2018-06-23 stsp return err;
3854 f7d12f7e 2018-08-01 stsp waddwstr(view->window, wline);
3855 2550e4c3 2018-07-13 stsp free(wline);
3856 2550e4c3 2018-07-13 stsp wline = NULL;
3857 30f8fd5e 2019-06-04 stsp if (width < view->ncols - 1)
3858 f7d12f7e 2018-08-01 stsp waddch(view->window, '\n');
3859 ffd1d5e5 2018-06-23 stsp if (--limit <= 0)
3860 ffd1d5e5 2018-06-23 stsp return NULL;
3861 f7d12f7e 2018-08-01 stsp waddch(view->window, '\n');
3862 a1eca9bb 2018-06-23 stsp if (--limit <= 0)
3863 a1eca9bb 2018-06-23 stsp return NULL;
3864 ffd1d5e5 2018-06-23 stsp
3865 ffd1d5e5 2018-06-23 stsp te = SIMPLEQ_FIRST(&entries->head);
3866 ffd1d5e5 2018-06-23 stsp if (*first_displayed_entry == NULL) {
3867 ffd1d5e5 2018-06-23 stsp if (selected == 0) {
3868 0cf4efb1 2018-09-29 stsp if (view->focussed)
3869 0cf4efb1 2018-09-29 stsp wstandout(view->window);
3870 ffd1d5e5 2018-06-23 stsp *selected_entry = NULL;
3871 ffd1d5e5 2018-06-23 stsp }
3872 f7d12f7e 2018-08-01 stsp waddstr(view->window, " ..\n"); /* parent directory */
3873 0cf4efb1 2018-09-29 stsp if (selected == 0 && view->focussed)
3874 f7d12f7e 2018-08-01 stsp wstandend(view->window);
3875 ffd1d5e5 2018-06-23 stsp (*ndisplayed)++;
3876 ffd1d5e5 2018-06-23 stsp if (--limit <= 0)
3877 ffd1d5e5 2018-06-23 stsp return NULL;
3878 ffd1d5e5 2018-06-23 stsp n = 1;
3879 ffd1d5e5 2018-06-23 stsp } else {
3880 ffd1d5e5 2018-06-23 stsp n = 0;
3881 ffd1d5e5 2018-06-23 stsp while (te != *first_displayed_entry)
3882 ffd1d5e5 2018-06-23 stsp te = SIMPLEQ_NEXT(te, entry);
3883 ffd1d5e5 2018-06-23 stsp }
3884 ffd1d5e5 2018-06-23 stsp
3885 ffd1d5e5 2018-06-23 stsp while (te) {
3886 1d13200f 2018-07-12 stsp char *line = NULL, *id_str = NULL;
3887 848d6979 2019-08-12 stsp const char *modestr = "";
3888 1d13200f 2018-07-12 stsp
3889 1d13200f 2018-07-12 stsp if (show_ids) {
3890 1d13200f 2018-07-12 stsp err = got_object_id_str(&id_str, te->id);
3891 1d13200f 2018-07-12 stsp if (err)
3892 638f9024 2019-05-13 stsp return got_error_from_errno(
3893 230a42bd 2019-05-11 jcs "got_object_id_str");
3894 1d13200f 2018-07-12 stsp }
3895 848d6979 2019-08-12 stsp if (S_ISLNK(te->mode))
3896 848d6979 2019-08-12 stsp modestr = "@";
3897 848d6979 2019-08-12 stsp else if (S_ISDIR(te->mode))
3898 848d6979 2019-08-12 stsp modestr = "/";
3899 848d6979 2019-08-12 stsp else if (te->mode & S_IXUSR)
3900 848d6979 2019-08-12 stsp modestr = "*";
3901 1d13200f 2018-07-12 stsp if (asprintf(&line, "%s %s%s", id_str ? id_str : "",
3902 848d6979 2019-08-12 stsp te->name, modestr) == -1) {
3903 1d13200f 2018-07-12 stsp free(id_str);
3904 638f9024 2019-05-13 stsp return got_error_from_errno("asprintf");
3905 1d13200f 2018-07-12 stsp }
3906 1d13200f 2018-07-12 stsp free(id_str);
3907 f7d12f7e 2018-08-01 stsp err = format_line(&wline, &width, line, view->ncols);
3908 ffd1d5e5 2018-06-23 stsp if (err) {
3909 ffd1d5e5 2018-06-23 stsp free(line);
3910 ffd1d5e5 2018-06-23 stsp break;
3911 ffd1d5e5 2018-06-23 stsp }
3912 ffd1d5e5 2018-06-23 stsp if (n == selected) {
3913 0cf4efb1 2018-09-29 stsp if (view->focussed)
3914 0cf4efb1 2018-09-29 stsp wstandout(view->window);
3915 ffd1d5e5 2018-06-23 stsp *selected_entry = te;
3916 ffd1d5e5 2018-06-23 stsp }
3917 f7d12f7e 2018-08-01 stsp waddwstr(view->window, wline);
3918 30f8fd5e 2019-06-04 stsp if (width < view->ncols - 1)
3919 f7d12f7e 2018-08-01 stsp waddch(view->window, '\n');
3920 0cf4efb1 2018-09-29 stsp if (n == selected && view->focussed)
3921 f7d12f7e 2018-08-01 stsp wstandend(view->window);
3922 ffd1d5e5 2018-06-23 stsp free(line);
3923 2550e4c3 2018-07-13 stsp free(wline);
3924 2550e4c3 2018-07-13 stsp wline = NULL;
3925 ffd1d5e5 2018-06-23 stsp n++;
3926 ffd1d5e5 2018-06-23 stsp (*ndisplayed)++;
3927 ffd1d5e5 2018-06-23 stsp *last_displayed_entry = te;
3928 ffd1d5e5 2018-06-23 stsp if (--limit <= 0)
3929 ffd1d5e5 2018-06-23 stsp break;
3930 ffd1d5e5 2018-06-23 stsp te = SIMPLEQ_NEXT(te, entry);
3931 ffd1d5e5 2018-06-23 stsp }
3932 ffd1d5e5 2018-06-23 stsp
3933 ffd1d5e5 2018-06-23 stsp return err;
3934 ffd1d5e5 2018-06-23 stsp }
3935 ffd1d5e5 2018-06-23 stsp
3936 ffd1d5e5 2018-06-23 stsp static void
3937 34bc9ec9 2019-02-22 stsp tree_scroll_up(struct tog_view *view,
3938 34bc9ec9 2019-02-22 stsp struct got_tree_entry **first_displayed_entry, int maxscroll,
3939 ffd1d5e5 2018-06-23 stsp const struct got_tree_entries *entries, int isroot)
3940 ffd1d5e5 2018-06-23 stsp {
3941 ffd1d5e5 2018-06-23 stsp struct got_tree_entry *te, *prev;
3942 ffd1d5e5 2018-06-23 stsp int i;
3943 ffd1d5e5 2018-06-23 stsp
3944 00ba99a7 2019-05-12 jcs if (*first_displayed_entry == NULL)
3945 ffd1d5e5 2018-06-23 stsp return;
3946 ffd1d5e5 2018-06-23 stsp
3947 ffd1d5e5 2018-06-23 stsp te = SIMPLEQ_FIRST(&entries->head);
3948 ffd1d5e5 2018-06-23 stsp if (*first_displayed_entry == te) {
3949 ffd1d5e5 2018-06-23 stsp if (!isroot)
3950 ffd1d5e5 2018-06-23 stsp *first_displayed_entry = NULL;
3951 ffd1d5e5 2018-06-23 stsp return;
3952 ffd1d5e5 2018-06-23 stsp }
3953 ffd1d5e5 2018-06-23 stsp
3954 ffd1d5e5 2018-06-23 stsp /* XXX this is stupid... switch to TAILQ? */
3955 ffd1d5e5 2018-06-23 stsp for (i = 0; i < maxscroll; i++) {
3956 ffd1d5e5 2018-06-23 stsp while (te != *first_displayed_entry) {
3957 ffd1d5e5 2018-06-23 stsp prev = te;
3958 ffd1d5e5 2018-06-23 stsp te = SIMPLEQ_NEXT(te, entry);
3959 ffd1d5e5 2018-06-23 stsp }
3960 ffd1d5e5 2018-06-23 stsp *first_displayed_entry = prev;
3961 ffd1d5e5 2018-06-23 stsp te = SIMPLEQ_FIRST(&entries->head);
3962 ffd1d5e5 2018-06-23 stsp }
3963 ffd1d5e5 2018-06-23 stsp if (!isroot && te == SIMPLEQ_FIRST(&entries->head) && i < maxscroll)
3964 ffd1d5e5 2018-06-23 stsp *first_displayed_entry = NULL;
3965 ffd1d5e5 2018-06-23 stsp }
3966 ffd1d5e5 2018-06-23 stsp
3967 768394f3 2019-01-24 stsp static int
3968 ffd1d5e5 2018-06-23 stsp tree_scroll_down(struct got_tree_entry **first_displayed_entry, int maxscroll,
3969 ffd1d5e5 2018-06-23 stsp struct got_tree_entry *last_displayed_entry,
3970 ffd1d5e5 2018-06-23 stsp const struct got_tree_entries *entries)
3971 ffd1d5e5 2018-06-23 stsp {
3972 768394f3 2019-01-24 stsp struct got_tree_entry *next, *last;
3973 ffd1d5e5 2018-06-23 stsp int n = 0;
3974 ffd1d5e5 2018-06-23 stsp
3975 ffd1d5e5 2018-06-23 stsp if (*first_displayed_entry)
3976 ffd1d5e5 2018-06-23 stsp next = SIMPLEQ_NEXT(*first_displayed_entry, entry);
3977 ffd1d5e5 2018-06-23 stsp else
3978 ffd1d5e5 2018-06-23 stsp next = SIMPLEQ_FIRST(&entries->head);
3979 768394f3 2019-01-24 stsp last = last_displayed_entry;
3980 768394f3 2019-01-24 stsp while (next && last && n++ < maxscroll) {
3981 768394f3 2019-01-24 stsp last = SIMPLEQ_NEXT(last, entry);
3982 768394f3 2019-01-24 stsp if (last) {
3983 768394f3 2019-01-24 stsp *first_displayed_entry = next;
3984 768394f3 2019-01-24 stsp next = SIMPLEQ_NEXT(next, entry);
3985 768394f3 2019-01-24 stsp }
3986 ffd1d5e5 2018-06-23 stsp }
3987 768394f3 2019-01-24 stsp return n;
3988 ffd1d5e5 2018-06-23 stsp }
3989 ffd1d5e5 2018-06-23 stsp
3990 ffd1d5e5 2018-06-23 stsp static const struct got_error *
3991 ce52c690 2018-06-23 stsp tree_entry_path(char **path, struct tog_parent_trees *parents,
3992 ce52c690 2018-06-23 stsp struct got_tree_entry *te)
3993 ffd1d5e5 2018-06-23 stsp {
3994 cb2ebc8a 2018-06-23 stsp const struct got_error *err = NULL;
3995 ffd1d5e5 2018-06-23 stsp struct tog_parent_tree *pt;
3996 ffd1d5e5 2018-06-23 stsp size_t len = 2; /* for leading slash and NUL */
3997 ffd1d5e5 2018-06-23 stsp
3998 d9765a41 2018-06-23 stsp TAILQ_FOREACH(pt, parents, entry)
3999 ffd1d5e5 2018-06-23 stsp len += strlen(pt->selected_entry->name) + 1 /* slash */;
4000 ce52c690 2018-06-23 stsp if (te)
4001 ce52c690 2018-06-23 stsp len += strlen(te->name);
4002 ce52c690 2018-06-23 stsp
4003 ce52c690 2018-06-23 stsp *path = calloc(1, len);
4004 ffd1d5e5 2018-06-23 stsp if (path == NULL)
4005 638f9024 2019-05-13 stsp return got_error_from_errno("calloc");
4006 ffd1d5e5 2018-06-23 stsp
4007 ce52c690 2018-06-23 stsp (*path)[0] = '/';
4008 d9765a41 2018-06-23 stsp pt = TAILQ_LAST(parents, tog_parent_trees);
4009 d9765a41 2018-06-23 stsp while (pt) {
4010 ce52c690 2018-06-23 stsp if (strlcat(*path, pt->selected_entry->name, len) >= len) {
4011 cb2ebc8a 2018-06-23 stsp err = got_error(GOT_ERR_NO_SPACE);
4012 cb2ebc8a 2018-06-23 stsp goto done;
4013 cb2ebc8a 2018-06-23 stsp }
4014 ce52c690 2018-06-23 stsp if (strlcat(*path, "/", len) >= len) {
4015 cb2ebc8a 2018-06-23 stsp err = got_error(GOT_ERR_NO_SPACE);
4016 cb2ebc8a 2018-06-23 stsp goto done;
4017 cb2ebc8a 2018-06-23 stsp }
4018 d9765a41 2018-06-23 stsp pt = TAILQ_PREV(pt, tog_parent_trees, entry);
4019 ffd1d5e5 2018-06-23 stsp }
4020 ce52c690 2018-06-23 stsp if (te) {
4021 ce52c690 2018-06-23 stsp if (strlcat(*path, te->name, len) >= len) {
4022 ce52c690 2018-06-23 stsp err = got_error(GOT_ERR_NO_SPACE);
4023 ce52c690 2018-06-23 stsp goto done;
4024 ce52c690 2018-06-23 stsp }
4025 cb2ebc8a 2018-06-23 stsp }
4026 ce52c690 2018-06-23 stsp done:
4027 ce52c690 2018-06-23 stsp if (err) {
4028 ce52c690 2018-06-23 stsp free(*path);
4029 ce52c690 2018-06-23 stsp *path = NULL;
4030 ce52c690 2018-06-23 stsp }
4031 ce52c690 2018-06-23 stsp return err;
4032 ce52c690 2018-06-23 stsp }
4033 ce52c690 2018-06-23 stsp
4034 ce52c690 2018-06-23 stsp static const struct got_error *
4035 0cf4efb1 2018-09-29 stsp blame_tree_entry(struct tog_view **new_view, int begin_x,
4036 e5a0f69f 2018-08-18 stsp struct got_tree_entry *te, struct tog_parent_trees *parents,
4037 8b473291 2019-02-21 stsp struct got_object_id *commit_id, struct got_reflist_head *refs,
4038 8b473291 2019-02-21 stsp struct got_repository *repo)
4039 ce52c690 2018-06-23 stsp {
4040 ce52c690 2018-06-23 stsp const struct got_error *err = NULL;
4041 ce52c690 2018-06-23 stsp char *path;
4042 e5a0f69f 2018-08-18 stsp struct tog_view *blame_view;
4043 a0de39f3 2019-08-09 stsp
4044 a0de39f3 2019-08-09 stsp *new_view = NULL;
4045 69efd4c4 2018-07-18 stsp
4046 ce52c690 2018-06-23 stsp err = tree_entry_path(&path, parents, te);
4047 ce52c690 2018-06-23 stsp if (err)
4048 ce52c690 2018-06-23 stsp return err;
4049 ffd1d5e5 2018-06-23 stsp
4050 669b5ffa 2018-10-07 stsp blame_view = view_open(0, 0, 0, begin_x, TOG_VIEW_BLAME);
4051 83ce39e3 2019-08-12 stsp if (blame_view == NULL) {
4052 83ce39e3 2019-08-12 stsp err = got_error_from_errno("view_open");
4053 83ce39e3 2019-08-12 stsp goto done;
4054 83ce39e3 2019-08-12 stsp }
4055 cdf1ee82 2018-08-01 stsp
4056 8b473291 2019-02-21 stsp err = open_blame_view(blame_view, path, commit_id, refs, repo);
4057 e5a0f69f 2018-08-18 stsp if (err) {
4058 e5a0f69f 2018-08-18 stsp view_close(blame_view);
4059 e5a0f69f 2018-08-18 stsp } else
4060 e5a0f69f 2018-08-18 stsp *new_view = blame_view;
4061 83ce39e3 2019-08-12 stsp done:
4062 83ce39e3 2019-08-12 stsp free(path);
4063 69efd4c4 2018-07-18 stsp return err;
4064 69efd4c4 2018-07-18 stsp }
4065 69efd4c4 2018-07-18 stsp
4066 69efd4c4 2018-07-18 stsp static const struct got_error *
4067 669b5ffa 2018-10-07 stsp log_tree_entry(struct tog_view **new_view, int begin_x,
4068 e5a0f69f 2018-08-18 stsp struct got_tree_entry *te, struct tog_parent_trees *parents,
4069 8b473291 2019-02-21 stsp struct got_object_id *commit_id, struct got_reflist_head *refs,
4070 8b473291 2019-02-21 stsp struct got_repository *repo)
4071 69efd4c4 2018-07-18 stsp {
4072 e5a0f69f 2018-08-18 stsp struct tog_view *log_view;
4073 69efd4c4 2018-07-18 stsp const struct got_error *err = NULL;
4074 69efd4c4 2018-07-18 stsp char *path;
4075 a0de39f3 2019-08-09 stsp
4076 a0de39f3 2019-08-09 stsp *new_view = NULL;
4077 69efd4c4 2018-07-18 stsp
4078 669b5ffa 2018-10-07 stsp log_view = view_open(0, 0, 0, begin_x, TOG_VIEW_LOG);
4079 e5a0f69f 2018-08-18 stsp if (log_view == NULL)
4080 638f9024 2019-05-13 stsp return got_error_from_errno("view_open");
4081 e5a0f69f 2018-08-18 stsp
4082 69efd4c4 2018-07-18 stsp err = tree_entry_path(&path, parents, te);
4083 69efd4c4 2018-07-18 stsp if (err)
4084 69efd4c4 2018-07-18 stsp return err;
4085 69efd4c4 2018-07-18 stsp
4086 d01904d4 2019-06-25 stsp err = open_log_view(log_view, commit_id, refs, repo, NULL, path, 0);
4087 ba4f502b 2018-08-04 stsp if (err)
4088 e5a0f69f 2018-08-18 stsp view_close(log_view);
4089 e5a0f69f 2018-08-18 stsp else
4090 e5a0f69f 2018-08-18 stsp *new_view = log_view;
4091 cb2ebc8a 2018-06-23 stsp free(path);
4092 cb2ebc8a 2018-06-23 stsp return err;
4093 ffd1d5e5 2018-06-23 stsp }
4094 ffd1d5e5 2018-06-23 stsp
4095 ffd1d5e5 2018-06-23 stsp static const struct got_error *
4096 ad80ab7b 2018-08-04 stsp open_tree_view(struct tog_view *view, struct got_tree_object *root,
4097 8b473291 2019-02-21 stsp struct got_object_id *commit_id, struct got_reflist_head *refs,
4098 8b473291 2019-02-21 stsp struct got_repository *repo)
4099 ffd1d5e5 2018-06-23 stsp {
4100 ffd1d5e5 2018-06-23 stsp const struct got_error *err = NULL;
4101 ad80ab7b 2018-08-04 stsp char *commit_id_str = NULL;
4102 fb2756b9 2018-08-04 stsp struct tog_tree_view_state *s = &view->state.tree;
4103 ffd1d5e5 2018-06-23 stsp
4104 fb2756b9 2018-08-04 stsp TAILQ_INIT(&s->parents);
4105 ffd1d5e5 2018-06-23 stsp
4106 ffd1d5e5 2018-06-23 stsp err = got_object_id_str(&commit_id_str, commit_id);
4107 ffd1d5e5 2018-06-23 stsp if (err != NULL)
4108 ffd1d5e5 2018-06-23 stsp goto done;
4109 ffd1d5e5 2018-06-23 stsp
4110 c1124f18 2018-12-23 stsp if (asprintf(&s->tree_label, "commit %s", commit_id_str) == -1) {
4111 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
4112 ffd1d5e5 2018-06-23 stsp goto done;
4113 ffd1d5e5 2018-06-23 stsp }
4114 ffd1d5e5 2018-06-23 stsp
4115 fb2756b9 2018-08-04 stsp s->root = s->tree = root;
4116 fb2756b9 2018-08-04 stsp s->entries = got_object_tree_get_entries(root);
4117 fb2756b9 2018-08-04 stsp s->first_displayed_entry = SIMPLEQ_FIRST(&s->entries->head);
4118 8d0fe45a 2019-08-12 stsp s->selected_entry = SIMPLEQ_FIRST(&s->entries->head);
4119 6484ec90 2018-09-29 stsp s->commit_id = got_object_id_dup(commit_id);
4120 6484ec90 2018-09-29 stsp if (s->commit_id == NULL) {
4121 638f9024 2019-05-13 stsp err = got_error_from_errno("got_object_id_dup");
4122 6484ec90 2018-09-29 stsp goto done;
4123 6484ec90 2018-09-29 stsp }
4124 8b473291 2019-02-21 stsp s->refs = refs;
4125 fb2756b9 2018-08-04 stsp s->repo = repo;
4126 e5a0f69f 2018-08-18 stsp
4127 e5a0f69f 2018-08-18 stsp view->show = show_tree_view;
4128 e5a0f69f 2018-08-18 stsp view->input = input_tree_view;
4129 e5a0f69f 2018-08-18 stsp view->close = close_tree_view;
4130 7c32bd05 2019-06-22 stsp view->search_start = search_start_tree_view;
4131 7c32bd05 2019-06-22 stsp view->search_next = search_next_tree_view;
4132 ad80ab7b 2018-08-04 stsp done:
4133 ad80ab7b 2018-08-04 stsp free(commit_id_str);
4134 6484ec90 2018-09-29 stsp if (err) {
4135 fb2756b9 2018-08-04 stsp free(s->tree_label);
4136 6484ec90 2018-09-29 stsp s->tree_label = NULL;
4137 6484ec90 2018-09-29 stsp }
4138 ad80ab7b 2018-08-04 stsp return err;
4139 ad80ab7b 2018-08-04 stsp }
4140 ad80ab7b 2018-08-04 stsp
4141 e5a0f69f 2018-08-18 stsp static const struct got_error *
4142 ad80ab7b 2018-08-04 stsp close_tree_view(struct tog_view *view)
4143 ad80ab7b 2018-08-04 stsp {
4144 fb2756b9 2018-08-04 stsp struct tog_tree_view_state *s = &view->state.tree;
4145 ad80ab7b 2018-08-04 stsp
4146 fb2756b9 2018-08-04 stsp free(s->tree_label);
4147 6484ec90 2018-09-29 stsp s->tree_label = NULL;
4148 6484ec90 2018-09-29 stsp free(s->commit_id);
4149 6484ec90 2018-09-29 stsp s->commit_id = NULL;
4150 fb2756b9 2018-08-04 stsp while (!TAILQ_EMPTY(&s->parents)) {
4151 ad80ab7b 2018-08-04 stsp struct tog_parent_tree *parent;
4152 fb2756b9 2018-08-04 stsp parent = TAILQ_FIRST(&s->parents);
4153 fb2756b9 2018-08-04 stsp TAILQ_REMOVE(&s->parents, parent, entry);
4154 ad80ab7b 2018-08-04 stsp free(parent);
4155 ad80ab7b 2018-08-04 stsp
4156 ad80ab7b 2018-08-04 stsp }
4157 fb2756b9 2018-08-04 stsp if (s->tree != s->root)
4158 fb2756b9 2018-08-04 stsp got_object_tree_close(s->tree);
4159 e5a0f69f 2018-08-18 stsp got_object_tree_close(s->root);
4160 7c32bd05 2019-06-22 stsp
4161 7c32bd05 2019-06-22 stsp return NULL;
4162 7c32bd05 2019-06-22 stsp }
4163 7c32bd05 2019-06-22 stsp
4164 7c32bd05 2019-06-22 stsp static const struct got_error *
4165 7c32bd05 2019-06-22 stsp search_start_tree_view(struct tog_view *view)
4166 7c32bd05 2019-06-22 stsp {
4167 7c32bd05 2019-06-22 stsp struct tog_tree_view_state *s = &view->state.tree;
4168 7c32bd05 2019-06-22 stsp
4169 7c32bd05 2019-06-22 stsp s->matched_entry = NULL;
4170 7c32bd05 2019-06-22 stsp return NULL;
4171 7c32bd05 2019-06-22 stsp }
4172 7c32bd05 2019-06-22 stsp
4173 7c32bd05 2019-06-22 stsp static int
4174 7c32bd05 2019-06-22 stsp match_tree_entry(struct got_tree_entry *te, regex_t *regex)
4175 7c32bd05 2019-06-22 stsp {
4176 7c32bd05 2019-06-22 stsp regmatch_t regmatch;
4177 7c32bd05 2019-06-22 stsp
4178 7c32bd05 2019-06-22 stsp return regexec(regex, te->name, 1, &regmatch, 0) == 0;
4179 7c32bd05 2019-06-22 stsp }
4180 7c32bd05 2019-06-22 stsp
4181 7c32bd05 2019-06-22 stsp static const struct got_error *
4182 7c32bd05 2019-06-22 stsp search_next_tree_view(struct tog_view *view)
4183 7c32bd05 2019-06-22 stsp {
4184 7c32bd05 2019-06-22 stsp struct tog_tree_view_state *s = &view->state.tree;
4185 a0de39f3 2019-08-09 stsp struct got_tree_entry *entry = NULL, *te;
4186 7c32bd05 2019-06-22 stsp
4187 7c32bd05 2019-06-22 stsp if (!view->searching) {
4188 7c32bd05 2019-06-22 stsp view->search_next_done = 1;
4189 7c32bd05 2019-06-22 stsp return NULL;
4190 7c32bd05 2019-06-22 stsp }
4191 7c32bd05 2019-06-22 stsp
4192 7c32bd05 2019-06-22 stsp if (s->matched_entry) {
4193 7c32bd05 2019-06-22 stsp if (view->searching == TOG_SEARCH_FORWARD) {
4194 7c32bd05 2019-06-22 stsp if (s->selected_entry)
4195 7c32bd05 2019-06-22 stsp entry = SIMPLEQ_NEXT(s->selected_entry, entry);
4196 7c32bd05 2019-06-22 stsp else
4197 7c32bd05 2019-06-22 stsp entry = SIMPLEQ_FIRST(&s->entries->head);
4198 7c32bd05 2019-06-22 stsp }
4199 7c32bd05 2019-06-22 stsp else {
4200 7c32bd05 2019-06-22 stsp if (s->selected_entry == NULL) {
4201 7c32bd05 2019-06-22 stsp SIMPLEQ_FOREACH(te, &s->entries->head, entry)
4202 7c32bd05 2019-06-22 stsp entry = te;
4203 7c32bd05 2019-06-22 stsp } else {
4204 7c32bd05 2019-06-22 stsp SIMPLEQ_FOREACH(te, &s->entries->head, entry) {
4205 7c32bd05 2019-06-22 stsp entry = te;
4206 7c32bd05 2019-06-22 stsp if (SIMPLEQ_NEXT(te, entry) ==
4207 7c32bd05 2019-06-22 stsp s->selected_entry)
4208 7c32bd05 2019-06-22 stsp break;
4209 7c32bd05 2019-06-22 stsp }
4210 7c32bd05 2019-06-22 stsp }
4211 7c32bd05 2019-06-22 stsp }
4212 7c32bd05 2019-06-22 stsp } else {
4213 7c32bd05 2019-06-22 stsp if (view->searching == TOG_SEARCH_FORWARD)
4214 7c32bd05 2019-06-22 stsp entry = SIMPLEQ_FIRST(&s->entries->head);
4215 7c32bd05 2019-06-22 stsp else {
4216 7c32bd05 2019-06-22 stsp SIMPLEQ_FOREACH(te, &s->entries->head, entry)
4217 7c32bd05 2019-06-22 stsp entry = te;
4218 7c32bd05 2019-06-22 stsp }
4219 7c32bd05 2019-06-22 stsp }
4220 7c32bd05 2019-06-22 stsp
4221 7c32bd05 2019-06-22 stsp while (1) {
4222 7c32bd05 2019-06-22 stsp if (entry == NULL) {
4223 ac66afb8 2019-06-24 stsp if (s->matched_entry == NULL) {
4224 ac66afb8 2019-06-24 stsp view->search_next_done = 1;
4225 ac66afb8 2019-06-24 stsp return NULL;
4226 ac66afb8 2019-06-24 stsp }
4227 7c32bd05 2019-06-22 stsp if (view->searching == TOG_SEARCH_FORWARD)
4228 7c32bd05 2019-06-22 stsp entry = SIMPLEQ_FIRST(&s->entries->head);
4229 7c32bd05 2019-06-22 stsp else {
4230 7c32bd05 2019-06-22 stsp SIMPLEQ_FOREACH(te, &s->entries->head, entry)
4231 7c32bd05 2019-06-22 stsp entry = te;
4232 7c32bd05 2019-06-22 stsp }
4233 7c32bd05 2019-06-22 stsp }
4234 7c32bd05 2019-06-22 stsp
4235 7c32bd05 2019-06-22 stsp if (match_tree_entry(entry, &view->regex)) {
4236 7c32bd05 2019-06-22 stsp view->search_next_done = 1;
4237 7c32bd05 2019-06-22 stsp s->matched_entry = entry;
4238 7c32bd05 2019-06-22 stsp break;
4239 7c32bd05 2019-06-22 stsp }
4240 7c32bd05 2019-06-22 stsp
4241 7c32bd05 2019-06-22 stsp if (view->searching == TOG_SEARCH_FORWARD)
4242 7c32bd05 2019-06-22 stsp entry = SIMPLEQ_NEXT(entry, entry);
4243 7c32bd05 2019-06-22 stsp else {
4244 7c32bd05 2019-06-22 stsp if (SIMPLEQ_FIRST(&s->entries->head) == entry)
4245 7c32bd05 2019-06-22 stsp entry = NULL;
4246 7c32bd05 2019-06-22 stsp else {
4247 7c32bd05 2019-06-22 stsp SIMPLEQ_FOREACH(te, &s->entries->head, entry) {
4248 7c32bd05 2019-06-22 stsp if (SIMPLEQ_NEXT(te, entry) == entry) {
4249 7c32bd05 2019-06-22 stsp entry = te;
4250 7c32bd05 2019-06-22 stsp break;
4251 7c32bd05 2019-06-22 stsp }
4252 7c32bd05 2019-06-22 stsp }
4253 7c32bd05 2019-06-22 stsp }
4254 7c32bd05 2019-06-22 stsp }
4255 7c32bd05 2019-06-22 stsp }
4256 e5a0f69f 2018-08-18 stsp
4257 7c32bd05 2019-06-22 stsp if (s->matched_entry) {
4258 7c32bd05 2019-06-22 stsp s->first_displayed_entry = s->matched_entry;
4259 7c32bd05 2019-06-22 stsp s->selected = 0;
4260 7c32bd05 2019-06-22 stsp }
4261 7c32bd05 2019-06-22 stsp
4262 e5a0f69f 2018-08-18 stsp return NULL;
4263 ad80ab7b 2018-08-04 stsp }
4264 ad80ab7b 2018-08-04 stsp
4265 ad80ab7b 2018-08-04 stsp static const struct got_error *
4266 ad80ab7b 2018-08-04 stsp show_tree_view(struct tog_view *view)
4267 ad80ab7b 2018-08-04 stsp {
4268 ad80ab7b 2018-08-04 stsp const struct got_error *err = NULL;
4269 fb2756b9 2018-08-04 stsp struct tog_tree_view_state *s = &view->state.tree;
4270 e5a0f69f 2018-08-18 stsp char *parent_path;
4271 ad80ab7b 2018-08-04 stsp
4272 e5a0f69f 2018-08-18 stsp err = tree_entry_path(&parent_path, &s->parents, NULL);
4273 e5a0f69f 2018-08-18 stsp if (err)
4274 e5a0f69f 2018-08-18 stsp return err;
4275 ffd1d5e5 2018-06-23 stsp
4276 e5a0f69f 2018-08-18 stsp err = draw_tree_entries(view, &s->first_displayed_entry,
4277 e5a0f69f 2018-08-18 stsp &s->last_displayed_entry, &s->selected_entry,
4278 e5a0f69f 2018-08-18 stsp &s->ndisplayed, s->tree_label, s->show_ids, parent_path,
4279 e5a0f69f 2018-08-18 stsp s->entries, s->selected, view->nlines, s->tree == s->root);
4280 e5a0f69f 2018-08-18 stsp free(parent_path);
4281 669b5ffa 2018-10-07 stsp
4282 669b5ffa 2018-10-07 stsp view_vborder(view);
4283 e5a0f69f 2018-08-18 stsp return err;
4284 e5a0f69f 2018-08-18 stsp }
4285 ce52c690 2018-06-23 stsp
4286 e5a0f69f 2018-08-18 stsp static const struct got_error *
4287 e5a0f69f 2018-08-18 stsp input_tree_view(struct tog_view **new_view, struct tog_view **dead_view,
4288 878940b7 2018-09-29 stsp struct tog_view **focus_view, struct tog_view *view, int ch)
4289 e5a0f69f 2018-08-18 stsp {
4290 e5a0f69f 2018-08-18 stsp const struct got_error *err = NULL;
4291 e5a0f69f 2018-08-18 stsp struct tog_tree_view_state *s = &view->state.tree;
4292 669b5ffa 2018-10-07 stsp struct tog_view *log_view;
4293 768394f3 2019-01-24 stsp int begin_x = 0, nscrolled;
4294 ffd1d5e5 2018-06-23 stsp
4295 e5a0f69f 2018-08-18 stsp switch (ch) {
4296 1e37a5c2 2019-05-12 jcs case 'i':
4297 1e37a5c2 2019-05-12 jcs s->show_ids = !s->show_ids;
4298 1e37a5c2 2019-05-12 jcs break;
4299 1e37a5c2 2019-05-12 jcs case 'l':
4300 1e37a5c2 2019-05-12 jcs if (!s->selected_entry)
4301 ffd1d5e5 2018-06-23 stsp break;
4302 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view))
4303 1e37a5c2 2019-05-12 jcs begin_x = view_split_begin_x(view->begin_x);
4304 1e37a5c2 2019-05-12 jcs err = log_tree_entry(&log_view, begin_x,
4305 1e37a5c2 2019-05-12 jcs s->selected_entry, &s->parents,
4306 1e37a5c2 2019-05-12 jcs s->commit_id, s->refs, s->repo);
4307 1e37a5c2 2019-05-12 jcs if (view_is_parent_view(view)) {
4308 1e37a5c2 2019-05-12 jcs err = view_close_child(view);
4309 1e37a5c2 2019-05-12 jcs if (err)
4310 1e37a5c2 2019-05-12 jcs return err;
4311 1e37a5c2 2019-05-12 jcs err = view_set_child(view, log_view);
4312 1e37a5c2 2019-05-12 jcs if (err) {
4313 1e37a5c2 2019-05-12 jcs view_close(log_view);
4314 669b5ffa 2018-10-07 stsp break;
4315 1e37a5c2 2019-05-12 jcs }
4316 1e37a5c2 2019-05-12 jcs *focus_view = log_view;
4317 1e37a5c2 2019-05-12 jcs view->child_focussed = 1;
4318 1e37a5c2 2019-05-12 jcs } else
4319 1e37a5c2 2019-05-12 jcs *new_view = log_view;
4320 1e37a5c2 2019-05-12 jcs break;
4321 1e37a5c2 2019-05-12 jcs case 'k':
4322 1e37a5c2 2019-05-12 jcs case KEY_UP:
4323 1e37a5c2 2019-05-12 jcs if (s->selected > 0) {
4324 1e37a5c2 2019-05-12 jcs s->selected--;
4325 1e37a5c2 2019-05-12 jcs if (s->selected == 0)
4326 1e37a5c2 2019-05-12 jcs break;
4327 1e37a5c2 2019-05-12 jcs }
4328 1e37a5c2 2019-05-12 jcs if (s->selected > 0)
4329 1e37a5c2 2019-05-12 jcs break;
4330 1e37a5c2 2019-05-12 jcs tree_scroll_up(view, &s->first_displayed_entry, 1,
4331 1e37a5c2 2019-05-12 jcs s->entries, s->tree == s->root);
4332 1e37a5c2 2019-05-12 jcs break;
4333 1e37a5c2 2019-05-12 jcs case KEY_PPAGE:
4334 1e37a5c2 2019-05-12 jcs tree_scroll_up(view, &s->first_displayed_entry,
4335 1e37a5c2 2019-05-12 jcs MAX(0, view->nlines - 4 - s->selected), s->entries,
4336 1e37a5c2 2019-05-12 jcs s->tree == s->root);
4337 1e37a5c2 2019-05-12 jcs s->selected = 0;
4338 1e37a5c2 2019-05-12 jcs if (SIMPLEQ_FIRST(&s->entries->head) ==
4339 1e37a5c2 2019-05-12 jcs s->first_displayed_entry && s->tree != s->root)
4340 1e37a5c2 2019-05-12 jcs s->first_displayed_entry = NULL;
4341 1e37a5c2 2019-05-12 jcs break;
4342 1e37a5c2 2019-05-12 jcs case 'j':
4343 1e37a5c2 2019-05-12 jcs case KEY_DOWN:
4344 1e37a5c2 2019-05-12 jcs if (s->selected < s->ndisplayed - 1) {
4345 1e37a5c2 2019-05-12 jcs s->selected++;
4346 1e37a5c2 2019-05-12 jcs break;
4347 1e37a5c2 2019-05-12 jcs }
4348 00ba99a7 2019-05-12 jcs if (SIMPLEQ_NEXT(s->last_displayed_entry, entry) == NULL)
4349 1e37a5c2 2019-05-12 jcs /* can't scroll any further */
4350 1e37a5c2 2019-05-12 jcs break;
4351 1e37a5c2 2019-05-12 jcs tree_scroll_down(&s->first_displayed_entry, 1,
4352 1e37a5c2 2019-05-12 jcs s->last_displayed_entry, s->entries);
4353 1e37a5c2 2019-05-12 jcs break;
4354 1e37a5c2 2019-05-12 jcs case KEY_NPAGE:
4355 1e37a5c2 2019-05-12 jcs if (SIMPLEQ_NEXT(s->last_displayed_entry, entry)
4356 1e37a5c2 2019-05-12 jcs == NULL) {
4357 1e37a5c2 2019-05-12 jcs /* can't scroll any further; move cursor down */
4358 1e37a5c2 2019-05-12 jcs if (s->selected < s->ndisplayed - 1)
4359 1e37a5c2 2019-05-12 jcs s->selected = s->ndisplayed - 1;
4360 1e37a5c2 2019-05-12 jcs break;
4361 1e37a5c2 2019-05-12 jcs }
4362 1e37a5c2 2019-05-12 jcs nscrolled = tree_scroll_down(&s->first_displayed_entry,
4363 1e37a5c2 2019-05-12 jcs view->nlines, s->last_displayed_entry, s->entries);
4364 1e37a5c2 2019-05-12 jcs if (nscrolled < view->nlines) {
4365 1e37a5c2 2019-05-12 jcs int ndisplayed = 0;
4366 1e37a5c2 2019-05-12 jcs struct got_tree_entry *te;
4367 1e37a5c2 2019-05-12 jcs te = s->first_displayed_entry;
4368 1e37a5c2 2019-05-12 jcs do {
4369 1e37a5c2 2019-05-12 jcs ndisplayed++;
4370 1e37a5c2 2019-05-12 jcs te = SIMPLEQ_NEXT(te, entry);
4371 1e37a5c2 2019-05-12 jcs } while (te);
4372 1e37a5c2 2019-05-12 jcs s->selected = ndisplayed - 1;
4373 1e37a5c2 2019-05-12 jcs }
4374 1e37a5c2 2019-05-12 jcs break;
4375 1e37a5c2 2019-05-12 jcs case KEY_ENTER:
4376 1e37a5c2 2019-05-12 jcs case '\r':
4377 1e37a5c2 2019-05-12 jcs case KEY_BACKSPACE:
4378 6f10d58e 2019-05-12 stsp if (s->selected_entry == NULL || ch == KEY_BACKSPACE) {
4379 6f10d58e 2019-05-12 stsp struct tog_parent_tree *parent;
4380 1e37a5c2 2019-05-12 jcs /* user selected '..' */
4381 1e37a5c2 2019-05-12 jcs if (s->tree == s->root)
4382 1e37a5c2 2019-05-12 jcs break;
4383 1e37a5c2 2019-05-12 jcs parent = TAILQ_FIRST(&s->parents);
4384 1e37a5c2 2019-05-12 jcs TAILQ_REMOVE(&s->parents, parent,
4385 1e37a5c2 2019-05-12 jcs entry);
4386 1e37a5c2 2019-05-12 jcs got_object_tree_close(s->tree);
4387 1e37a5c2 2019-05-12 jcs s->tree = parent->tree;
4388 1e37a5c2 2019-05-12 jcs s->entries =
4389 1e37a5c2 2019-05-12 jcs got_object_tree_get_entries(s->tree);
4390 1e37a5c2 2019-05-12 jcs s->first_displayed_entry =
4391 1e37a5c2 2019-05-12 jcs parent->first_displayed_entry;
4392 1e37a5c2 2019-05-12 jcs s->selected_entry =
4393 1e37a5c2 2019-05-12 jcs parent->selected_entry;
4394 1e37a5c2 2019-05-12 jcs s->selected = parent->selected;
4395 1e37a5c2 2019-05-12 jcs free(parent);
4396 1e37a5c2 2019-05-12 jcs } else if (S_ISDIR(s->selected_entry->mode)) {
4397 941e9f74 2019-05-21 stsp struct got_tree_object *subtree;
4398 941e9f74 2019-05-21 stsp err = got_object_open_as_tree(&subtree,
4399 1e37a5c2 2019-05-12 jcs s->repo, s->selected_entry->id);
4400 1e37a5c2 2019-05-12 jcs if (err)
4401 1e37a5c2 2019-05-12 jcs break;
4402 941e9f74 2019-05-21 stsp err = tree_view_visit_subtree(subtree, s);
4403 941e9f74 2019-05-21 stsp if (err) {
4404 941e9f74 2019-05-21 stsp got_object_tree_close(subtree);
4405 1e37a5c2 2019-05-12 jcs break;
4406 1e37a5c2 2019-05-12 jcs }
4407 1e37a5c2 2019-05-12 jcs } else if (S_ISREG(s->selected_entry->mode)) {
4408 1e37a5c2 2019-05-12 jcs struct tog_view *blame_view;
4409 1e37a5c2 2019-05-12 jcs int begin_x = view_is_parent_view(view) ?
4410 1e37a5c2 2019-05-12 jcs view_split_begin_x(view->begin_x) : 0;
4411 1e37a5c2 2019-05-12 jcs
4412 1e37a5c2 2019-05-12 jcs err = blame_tree_entry(&blame_view, begin_x,
4413 669b5ffa 2018-10-07 stsp s->selected_entry, &s->parents,
4414 8b473291 2019-02-21 stsp s->commit_id, s->refs, s->repo);
4415 1e37a5c2 2019-05-12 jcs if (err)
4416 1e37a5c2 2019-05-12 jcs break;
4417 669b5ffa 2018-10-07 stsp if (view_is_parent_view(view)) {
4418 669b5ffa 2018-10-07 stsp err = view_close_child(view);
4419 669b5ffa 2018-10-07 stsp if (err)
4420 669b5ffa 2018-10-07 stsp return err;
4421 1e37a5c2 2019-05-12 jcs err = view_set_child(view, blame_view);
4422 669b5ffa 2018-10-07 stsp if (err) {
4423 1e37a5c2 2019-05-12 jcs view_close(blame_view);
4424 669b5ffa 2018-10-07 stsp break;
4425 669b5ffa 2018-10-07 stsp }
4426 1e37a5c2 2019-05-12 jcs *focus_view = blame_view;
4427 669b5ffa 2018-10-07 stsp view->child_focussed = 1;
4428 669b5ffa 2018-10-07 stsp } else
4429 1e37a5c2 2019-05-12 jcs *new_view = blame_view;
4430 1e37a5c2 2019-05-12 jcs }
4431 1e37a5c2 2019-05-12 jcs break;
4432 1e37a5c2 2019-05-12 jcs case KEY_RESIZE:
4433 1e37a5c2 2019-05-12 jcs if (s->selected > view->nlines)
4434 1e37a5c2 2019-05-12 jcs s->selected = s->ndisplayed - 1;
4435 1e37a5c2 2019-05-12 jcs break;
4436 1e37a5c2 2019-05-12 jcs default:
4437 1e37a5c2 2019-05-12 jcs break;
4438 ffd1d5e5 2018-06-23 stsp }
4439 e5a0f69f 2018-08-18 stsp
4440 ffd1d5e5 2018-06-23 stsp return err;
4441 9f7d7167 2018-04-29 stsp }
4442 9f7d7167 2018-04-29 stsp
4443 ffd1d5e5 2018-06-23 stsp __dead static void
4444 ffd1d5e5 2018-06-23 stsp usage_tree(void)
4445 ffd1d5e5 2018-06-23 stsp {
4446 ffd1d5e5 2018-06-23 stsp endwin();
4447 ffd1d5e5 2018-06-23 stsp fprintf(stderr, "usage: %s tree [-c commit] [repository-path]\n",
4448 ffd1d5e5 2018-06-23 stsp getprogname());
4449 ffd1d5e5 2018-06-23 stsp exit(1);
4450 ffd1d5e5 2018-06-23 stsp }
4451 ffd1d5e5 2018-06-23 stsp
4452 ffd1d5e5 2018-06-23 stsp static const struct got_error *
4453 ffd1d5e5 2018-06-23 stsp cmd_tree(int argc, char *argv[])
4454 ffd1d5e5 2018-06-23 stsp {
4455 ffd1d5e5 2018-06-23 stsp const struct got_error *error;
4456 ffd1d5e5 2018-06-23 stsp struct got_repository *repo = NULL;
4457 8b473291 2019-02-21 stsp struct got_reflist_head refs;
4458 ffd1d5e5 2018-06-23 stsp char *repo_path = NULL;
4459 ffd1d5e5 2018-06-23 stsp struct got_object_id *commit_id = NULL;
4460 ffd1d5e5 2018-06-23 stsp char *commit_id_arg = NULL;
4461 ffd1d5e5 2018-06-23 stsp struct got_commit_object *commit = NULL;
4462 ffd1d5e5 2018-06-23 stsp struct got_tree_object *tree = NULL;
4463 ffd1d5e5 2018-06-23 stsp int ch;
4464 5221c383 2018-08-01 stsp struct tog_view *view;
4465 70ac5f84 2019-03-28 stsp
4466 70ac5f84 2019-03-28 stsp SIMPLEQ_INIT(&refs);
4467 ffd1d5e5 2018-06-23 stsp
4468 ffd1d5e5 2018-06-23 stsp #ifndef PROFILE
4469 d188b9a6 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd unveil",
4470 d188b9a6 2019-01-04 stsp NULL) == -1)
4471 ffd1d5e5 2018-06-23 stsp err(1, "pledge");
4472 ffd1d5e5 2018-06-23 stsp #endif
4473 ffd1d5e5 2018-06-23 stsp
4474 ffd1d5e5 2018-06-23 stsp while ((ch = getopt(argc, argv, "c:")) != -1) {
4475 ffd1d5e5 2018-06-23 stsp switch (ch) {
4476 ffd1d5e5 2018-06-23 stsp case 'c':
4477 ffd1d5e5 2018-06-23 stsp commit_id_arg = optarg;
4478 ffd1d5e5 2018-06-23 stsp break;
4479 ffd1d5e5 2018-06-23 stsp default:
4480 17020d27 2019-03-07 stsp usage_tree();
4481 ffd1d5e5 2018-06-23 stsp /* NOTREACHED */
4482 ffd1d5e5 2018-06-23 stsp }
4483 ffd1d5e5 2018-06-23 stsp }
4484 ffd1d5e5 2018-06-23 stsp
4485 ffd1d5e5 2018-06-23 stsp argc -= optind;
4486 ffd1d5e5 2018-06-23 stsp argv += optind;
4487 ffd1d5e5 2018-06-23 stsp
4488 ffd1d5e5 2018-06-23 stsp if (argc == 0) {
4489 52185f70 2019-02-05 stsp struct got_worktree *worktree;
4490 52185f70 2019-02-05 stsp char *cwd = getcwd(NULL, 0);
4491 52185f70 2019-02-05 stsp if (cwd == NULL)
4492 638f9024 2019-05-13 stsp return got_error_from_errno("getcwd");
4493 52185f70 2019-02-05 stsp error = got_worktree_open(&worktree, cwd);
4494 52185f70 2019-02-05 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4495 52185f70 2019-02-05 stsp goto done;
4496 52185f70 2019-02-05 stsp if (worktree) {
4497 52185f70 2019-02-05 stsp free(cwd);
4498 52185f70 2019-02-05 stsp repo_path =
4499 52185f70 2019-02-05 stsp strdup(got_worktree_get_repo_path(worktree));
4500 52185f70 2019-02-05 stsp got_worktree_close(worktree);
4501 52185f70 2019-02-05 stsp } else
4502 52185f70 2019-02-05 stsp repo_path = cwd;
4503 52185f70 2019-02-05 stsp if (repo_path == NULL) {
4504 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4505 52185f70 2019-02-05 stsp goto done;
4506 52185f70 2019-02-05 stsp }
4507 ffd1d5e5 2018-06-23 stsp } else if (argc == 1) {
4508 ffd1d5e5 2018-06-23 stsp repo_path = realpath(argv[0], NULL);
4509 ffd1d5e5 2018-06-23 stsp if (repo_path == NULL)
4510 638f9024 2019-05-13 stsp return got_error_from_errno2("realpath", argv[0]);
4511 ffd1d5e5 2018-06-23 stsp } else
4512 ffd1d5e5 2018-06-23 stsp usage_log();
4513 a915003a 2019-02-05 stsp
4514 a915003a 2019-02-05 stsp init_curses();
4515 ffd1d5e5 2018-06-23 stsp
4516 c02c541e 2019-03-29 stsp error = got_repo_open(&repo, repo_path);
4517 c02c541e 2019-03-29 stsp if (error != NULL)
4518 52185f70 2019-02-05 stsp goto done;
4519 d188b9a6 2019-01-04 stsp
4520 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), NULL);
4521 c02c541e 2019-03-29 stsp if (error)
4522 52185f70 2019-02-05 stsp goto done;
4523 ffd1d5e5 2018-06-23 stsp
4524 15a94983 2018-12-23 stsp if (commit_id_arg == NULL)
4525 19e70ad6 2019-05-14 stsp error = get_head_commit_id(&commit_id, GOT_REF_HEAD, repo);
4526 f2b6a97d 2019-07-15 stsp else {
4527 f2b6a97d 2019-07-15 stsp error = get_head_commit_id(&commit_id, commit_id_arg, repo);
4528 f2b6a97d 2019-07-15 stsp if (error) {
4529 f2b6a97d 2019-07-15 stsp if (error->code != GOT_ERR_NOT_REF)
4530 f2b6a97d 2019-07-15 stsp goto done;
4531 f2b6a97d 2019-07-15 stsp error = got_repo_match_object_id_prefix(&commit_id,
4532 f2b6a97d 2019-07-15 stsp commit_id_arg, GOT_OBJ_TYPE_COMMIT, repo);
4533 f2b6a97d 2019-07-15 stsp }
4534 f2b6a97d 2019-07-15 stsp }
4535 ffd1d5e5 2018-06-23 stsp if (error != NULL)
4536 ffd1d5e5 2018-06-23 stsp goto done;
4537 ffd1d5e5 2018-06-23 stsp
4538 ffd1d5e5 2018-06-23 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
4539 ffd1d5e5 2018-06-23 stsp if (error != NULL)
4540 ffd1d5e5 2018-06-23 stsp goto done;
4541 ffd1d5e5 2018-06-23 stsp
4542 45d799e2 2018-12-23 stsp error = got_object_open_as_tree(&tree, repo,
4543 45d799e2 2018-12-23 stsp got_object_commit_get_tree_id(commit));
4544 ffd1d5e5 2018-06-23 stsp if (error != NULL)
4545 8b473291 2019-02-21 stsp goto done;
4546 8b473291 2019-02-21 stsp
4547 8b473291 2019-02-21 stsp error = got_ref_list(&refs, repo);
4548 8b473291 2019-02-21 stsp if (error)
4549 ffd1d5e5 2018-06-23 stsp goto done;
4550 ffd1d5e5 2018-06-23 stsp
4551 0cf4efb1 2018-09-29 stsp view = view_open(0, 0, 0, 0, TOG_VIEW_TREE);
4552 5221c383 2018-08-01 stsp if (view == NULL) {
4553 638f9024 2019-05-13 stsp error = got_error_from_errno("view_open");
4554 5221c383 2018-08-01 stsp goto done;
4555 5221c383 2018-08-01 stsp }
4556 8b473291 2019-02-21 stsp error = open_tree_view(view, tree, commit_id, &refs, repo);
4557 ad80ab7b 2018-08-04 stsp if (error)
4558 ad80ab7b 2018-08-04 stsp goto done;
4559 e5a0f69f 2018-08-18 stsp error = view_loop(view);
4560 ffd1d5e5 2018-06-23 stsp done:
4561 52185f70 2019-02-05 stsp free(repo_path);
4562 ffd1d5e5 2018-06-23 stsp free(commit_id);
4563 ffd1d5e5 2018-06-23 stsp if (commit)
4564 ffd1d5e5 2018-06-23 stsp got_object_commit_close(commit);
4565 ffd1d5e5 2018-06-23 stsp if (tree)
4566 ffd1d5e5 2018-06-23 stsp got_object_tree_close(tree);
4567 ffd1d5e5 2018-06-23 stsp if (repo)
4568 ffd1d5e5 2018-06-23 stsp got_repo_close(repo);
4569 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
4570 ffd1d5e5 2018-06-23 stsp return error;
4571 9f7d7167 2018-04-29 stsp }
4572 ce5b7c56 2019-07-09 stsp
4573 ce5b7c56 2019-07-09 stsp static void
4574 ce5b7c56 2019-07-09 stsp list_commands(void)
4575 ce5b7c56 2019-07-09 stsp {
4576 ce5b7c56 2019-07-09 stsp int i;
4577 9f7d7167 2018-04-29 stsp
4578 ce5b7c56 2019-07-09 stsp fprintf(stderr, "commands:");
4579 ce5b7c56 2019-07-09 stsp for (i = 0; i < nitems(tog_commands); i++) {
4580 ce5b7c56 2019-07-09 stsp struct tog_cmd *cmd = &tog_commands[i];
4581 ce5b7c56 2019-07-09 stsp fprintf(stderr, " %s", cmd->name);
4582 ce5b7c56 2019-07-09 stsp }
4583 ce5b7c56 2019-07-09 stsp fputc('\n', stderr);
4584 ce5b7c56 2019-07-09 stsp }
4585 ce5b7c56 2019-07-09 stsp
4586 4ed7e80c 2018-05-20 stsp __dead static void
4587 ce5b7c56 2019-07-09 stsp usage(int hflag)
4588 9f7d7167 2018-04-29 stsp {
4589 53ccebc2 2019-07-30 stsp fprintf(stderr, "usage: %s [-h] [-V] [command] [arg ...]\n",
4590 53ccebc2 2019-07-30 stsp getprogname());
4591 ce5b7c56 2019-07-09 stsp if (hflag)
4592 ce5b7c56 2019-07-09 stsp list_commands();
4593 9f7d7167 2018-04-29 stsp exit(1);
4594 9f7d7167 2018-04-29 stsp }
4595 9f7d7167 2018-04-29 stsp
4596 c2301be8 2018-04-30 stsp static char **
4597 c2301be8 2018-04-30 stsp make_argv(const char *arg0, const char *arg1)
4598 c2301be8 2018-04-30 stsp {
4599 c2301be8 2018-04-30 stsp char **argv;
4600 c2301be8 2018-04-30 stsp int argc = (arg1 == NULL ? 1 : 2);
4601 c2301be8 2018-04-30 stsp
4602 c2301be8 2018-04-30 stsp argv = calloc(argc, sizeof(char *));
4603 c2301be8 2018-04-30 stsp if (argv == NULL)
4604 c2301be8 2018-04-30 stsp err(1, "calloc");
4605 c2301be8 2018-04-30 stsp argv[0] = strdup(arg0);
4606 c2301be8 2018-04-30 stsp if (argv[0] == NULL)
4607 c2301be8 2018-04-30 stsp err(1, "calloc");
4608 c2301be8 2018-04-30 stsp if (arg1) {
4609 c2301be8 2018-04-30 stsp argv[1] = strdup(arg1);
4610 c2301be8 2018-04-30 stsp if (argv[1] == NULL)
4611 c2301be8 2018-04-30 stsp err(1, "calloc");
4612 c2301be8 2018-04-30 stsp }
4613 c2301be8 2018-04-30 stsp
4614 c2301be8 2018-04-30 stsp return argv;
4615 c2301be8 2018-04-30 stsp }
4616 c2301be8 2018-04-30 stsp
4617 9f7d7167 2018-04-29 stsp int
4618 9f7d7167 2018-04-29 stsp main(int argc, char *argv[])
4619 9f7d7167 2018-04-29 stsp {
4620 9f7d7167 2018-04-29 stsp const struct got_error *error = NULL;
4621 9f7d7167 2018-04-29 stsp struct tog_cmd *cmd = NULL;
4622 53ccebc2 2019-07-30 stsp int ch, hflag = 0, Vflag = 0;
4623 c2301be8 2018-04-30 stsp char **cmd_argv = NULL;
4624 9f7d7167 2018-04-29 stsp
4625 289e3cbf 2019-02-04 stsp setlocale(LC_CTYPE, "");
4626 9f7d7167 2018-04-29 stsp
4627 53ccebc2 2019-07-30 stsp while ((ch = getopt(argc, argv, "hV")) != -1) {
4628 9f7d7167 2018-04-29 stsp switch (ch) {
4629 9f7d7167 2018-04-29 stsp case 'h':
4630 9f7d7167 2018-04-29 stsp hflag = 1;
4631 9f7d7167 2018-04-29 stsp break;
4632 53ccebc2 2019-07-30 stsp case 'V':
4633 53ccebc2 2019-07-30 stsp Vflag = 1;
4634 53ccebc2 2019-07-30 stsp break;
4635 9f7d7167 2018-04-29 stsp default:
4636 ce5b7c56 2019-07-09 stsp usage(hflag);
4637 9f7d7167 2018-04-29 stsp /* NOTREACHED */
4638 9f7d7167 2018-04-29 stsp }
4639 9f7d7167 2018-04-29 stsp }
4640 9f7d7167 2018-04-29 stsp
4641 9f7d7167 2018-04-29 stsp argc -= optind;
4642 9f7d7167 2018-04-29 stsp argv += optind;
4643 9f7d7167 2018-04-29 stsp optind = 0;
4644 c2301be8 2018-04-30 stsp optreset = 1;
4645 9f7d7167 2018-04-29 stsp
4646 53ccebc2 2019-07-30 stsp if (Vflag) {
4647 53ccebc2 2019-07-30 stsp got_version_print_str();
4648 53ccebc2 2019-07-30 stsp return 1;
4649 53ccebc2 2019-07-30 stsp }
4650 53ccebc2 2019-07-30 stsp
4651 c2301be8 2018-04-30 stsp if (argc == 0) {
4652 f29d3e89 2018-06-23 stsp if (hflag)
4653 ce5b7c56 2019-07-09 stsp usage(hflag);
4654 c2301be8 2018-04-30 stsp /* Build an argument vector which runs a default command. */
4655 9f7d7167 2018-04-29 stsp cmd = &tog_commands[0];
4656 c2301be8 2018-04-30 stsp cmd_argv = make_argv(cmd->name, NULL);
4657 c2301be8 2018-04-30 stsp argc = 1;
4658 c2301be8 2018-04-30 stsp } else {
4659 9f7d7167 2018-04-29 stsp int i;
4660 9f7d7167 2018-04-29 stsp
4661 c2301be8 2018-04-30 stsp /* Did the user specific a command? */
4662 9f7d7167 2018-04-29 stsp for (i = 0; i < nitems(tog_commands); i++) {
4663 c2301be8 2018-04-30 stsp if (strncmp(tog_commands[i].name, argv[0],
4664 9f7d7167 2018-04-29 stsp strlen(argv[0])) == 0) {
4665 9f7d7167 2018-04-29 stsp cmd = &tog_commands[i];
4666 9f7d7167 2018-04-29 stsp break;
4667 9f7d7167 2018-04-29 stsp }
4668 9f7d7167 2018-04-29 stsp }
4669 3642c4c6 2019-07-09 stsp
4670 9f7d7167 2018-04-29 stsp if (cmd == NULL) {
4671 d70c3147 2019-07-09 stsp fprintf(stderr, "%s: unknown command '%s'\n",
4672 3642c4c6 2019-07-09 stsp getprogname(), argv[0]);
4673 ce5b7c56 2019-07-09 stsp list_commands();
4674 3642c4c6 2019-07-09 stsp return 1;
4675 9f7d7167 2018-04-29 stsp }
4676 9f7d7167 2018-04-29 stsp }
4677 9f7d7167 2018-04-29 stsp
4678 3642c4c6 2019-07-09 stsp if (hflag)
4679 3642c4c6 2019-07-09 stsp cmd->cmd_usage();
4680 3642c4c6 2019-07-09 stsp else
4681 3642c4c6 2019-07-09 stsp error = cmd->cmd_main(argc, cmd_argv ? cmd_argv : argv);
4682 3642c4c6 2019-07-09 stsp
4683 9f7d7167 2018-04-29 stsp endwin();
4684 c2301be8 2018-04-30 stsp free(cmd_argv);
4685 9f7d7167 2018-04-29 stsp if (error)
4686 9f7d7167 2018-04-29 stsp fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
4687 9f7d7167 2018-04-29 stsp return 0;
4688 9f7d7167 2018-04-29 stsp }