1 /* Copyright (c) 2006-2015 Jonas Fonseca <jonas.fonseca@gmail.com>
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License as
5  * published by the Free Software Foundation; either version 2 of
6  * the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13 
14 #ifndef TIG_VIEW_H
15 #define TIG_VIEW_H
16 
17 #include "tig/tig.h"
18 #include "tig/types.h"
19 #include "tig/argv.h"
20 #include "tig/watch.h"
21 #include "tig/io.h"
22 #include "tig/line.h"
23 #include "tig/keys.h"
24 #include "tig/options.h"
25 
26 struct view_ops;
27 
28 struct box_cell {
29 	enum line_type type;
30 	size_t length;
31 };
32 
33 struct box {
34 	const char *text;
35 	size_t cells;
36 	struct box_cell cell[1];
37 };
38 
39 struct line {
40 	enum line_type type;
41 	unsigned int lineno:24;
42 
43 	/* State flags */
44 	unsigned int selected:1;
45 	unsigned int dirty:1;
46 	unsigned int cleareol:1;
47 	unsigned int wrapped:1;
48 	unsigned int commit_title:1;
49 	unsigned int no_commit_refs:1;
50 	unsigned int graph_indent:1;
51 	unsigned int search_result:1;
52 
53 	void *data;		/* User data */
54 };
55 
56 enum view_flag {
57 	VIEW_NO_FLAGS = 0,
58 	VIEW_CUSTOM_STATUS	= 1 << 1,
59 	VIEW_ADD_DESCRIBE_REF	= 1 << 2,
60 	VIEW_ADD_PAGER_REFS	= 1 << 3,
61 	VIEW_OPEN_DIFF		= 1 << 4,
62 	VIEW_NO_REF		= 1 << 5,
63 	VIEW_NO_GIT_DIR		= 1 << 6,
64 	VIEW_DIFF_LIKE		= 1 << 7,
65 	VIEW_BLAME_LIKE		= 1 << 8,
66 	VIEW_SEND_CHILD_ENTER	= 1 << 9,
67 	VIEW_FILE_FILTER	= 1 << 10,
68 	VIEW_LOG_LIKE		= 1 << 11,
69 	VIEW_STATUS_LIKE	= 1 << 12,
70 	VIEW_REFRESH		= 1 << 13,
71 	VIEW_GREP_LIKE		= 1 << 14,
72 	VIEW_SORTABLE		= 1 << 15,
73 	VIEW_FLEX_WIDTH		= 1 << 16,
74 	VIEW_RESET_DISPLAY	= 1 << 17,
75 };
76 
77 #define view_has_flags(view, flag)	((view)->ops->flags & (flag))
78 #define view_can_refresh(view) \
79 	(view_has_flags(view, VIEW_REFRESH) && !(view)->unrefreshable)
80 
81 struct position {
82 	unsigned long offset;	/* Offset of the window top */
83 	unsigned long col;	/* Offset from the window side. */
84 	unsigned long lineno;	/* Current line number */
85 };
86 
87 struct sort_state {
88 	struct view_column *current;
89 	bool reverse;
90 };
91 
92 struct view_column {
93 	struct view_column *next;
94 	enum view_column_type type;
95 	int width;
96 	union view_column_options prev_opt;
97 	union view_column_options opt;
98 	bool hidden;
99 };
100 
101 struct view {
102 	const char *name;	/* View name */
103 
104 	struct view_ops *ops;	/* View operations */
105 	struct argv_env *env;	/* View variables. */
106 
107 	char ref[SIZEOF_REF];	/* Hovered commit reference */
108 	char vid[SIZEOF_REF];	/* View ID. Set to id member when updating. */
109 
110 	int height, width;	/* The width and height of the main window */
111 	WINDOW *win;		/* The main window */
112 	WINDOW *title;		/* The title window */
113 
114 	struct keymap *keymap;	/* What keymap does this view have */
115 	struct sort_state sort;	/* Sorting information. */
116 
117 	/* Navigation */
118 	struct position pos;	/* Current position. */
119 	struct position prev_pos; /* Previous position. */
120 
121 	/* View columns rendering state */
122 	struct view_column *columns;
123 
124 	/* Searching */
125 	char grep[SIZEOF_STR];	/* Search string */
126 	regex_t *regex;		/* Pre-compiled regexp */
127 	unsigned int *matched_line;
128 	size_t matched_lines;
129 
130 	/* If non-NULL, points to the view that opened this view. If this view
131 	 * is closed tig will switch back to the parent view. */
132 	struct view *parent;
133 	struct view *prev;
134 
135 	/* Buffering */
136 	size_t lines;		/* Total number of lines */
137 	struct line *line;	/* Line index */
138 
139 	/* Number of lines with custom status, not to be counted in the
140 	 * view title. */
141 	unsigned int custom_lines;
142 
143 	/* Drawing */
144 	struct line *curline;	/* Line currently being drawn. */
145 	enum line_type curtype;	/* Attribute currently used for drawing. */
146 	unsigned long col;	/* Column when drawing. */
147 	bool has_scrolled;	/* View was scrolled. */
148 	bool force_redraw;	/* Whether to force a redraw after reading. */
149 
150 	/* Loading */
151 	const char **argv;	/* Shell command arguments. */
152 	const char *dir;	/* Directory from which to execute. */
153 	struct io io;
154 	struct io *pipe;
155 	time_t start_time;
156 	time_t update_secs;
157 	struct encoding *encoding;
158 	bool unrefreshable;
159 	struct watch watch;
160 
161 	/* Private data */
162 	void *private;
163 };
164 
165 #define DEFINE_VIEW(name) struct view name ##_view = { #name, &name##_ops, &argv_env }
166 
167 enum open_flags {
168 	OPEN_DEFAULT = 0,	/* Use default view switching. */
169 	OPEN_STDIN = 1,		/* Open in pager mode. */
170 	OPEN_FORWARD_STDIN = 2,	/* Forward stdin to I/O process. */
171 	OPEN_SPLIT = 4,		/* Split current view. */
172 	OPEN_RELOAD = 8,	/* Reload view even if it is the current. */
173 	OPEN_REFRESH = 16,	/* Refresh view using previous command. */
174 	OPEN_PREPARED = 32,	/* Open already prepared command. */
175 	OPEN_EXTRA = 64,	/* Open extra data from command. */
176 	OPEN_WITH_STDERR = 128,	/* Redirect stderr to stdin. */
177 
178 	OPEN_PAGER_MODE = OPEN_STDIN | OPEN_FORWARD_STDIN,
179 	OPEN_ALWAYS_LOAD = OPEN_RELOAD | OPEN_REFRESH | OPEN_PREPARED | OPEN_EXTRA | OPEN_PAGER_MODE,
180 };
181 
182 #define open_in_pager_mode(flags) ((flags) & OPEN_PAGER_MODE)
183 #define open_from_stdin(flags) ((flags) & OPEN_STDIN)
184 
185 struct view_column_data {
186 	struct view_column *section;
187 	const struct ident *author;
188 	const char *commit_title;
189 	const struct time *date;
190 	const char *file_name;
191 	const unsigned long *file_size;
192 	const struct graph *graph;
193 	const struct graph_canvas *graph_canvas;
194 	const char *id;
195 	const unsigned long *line_number;
196 	const mode_t *mode;
197 	const struct ref *ref;
198 	const struct ref *refs;
199 	const char *status;
200 	const char *text;
201 	const struct box *box;
202 };
203 
204 #define view_column_bit(id) (1 << VIEW_COLUMN_##id)
205 #define view_has_column(view, id) ((view)->ops->column_bits & view_column_bit(id))
206 
207 #define view_column_name(id) enum_name(view_column_type_map->entries[id].name)
208 
209 struct view_ops {
210 	/* What type of content being displayed. Used in the title bar. */
211 	const char *type;
212 	/* Points to either of ref_{head,commit,blob} */
213 	const char *id;
214 	/* Flags to control the view behavior. */
215 	enum view_flag flags;
216 	/* Size of private data. */
217 	size_t private_size;
218 	/* Open and reads in all view content. */
219 	enum status_code (*open)(struct view *view, enum open_flags flags);
220 	/* Read one line; updates view->line. */
221 	bool (*read)(struct view *view, struct buffer *buf, bool force_stop);
222 	/* Draw one line; @lineno must be < view->height. */
223 	bool (*draw)(struct view *view, struct line *line, unsigned int lineno);
224 	/* Depending on view handle a special requests. */
225 	enum request (*request)(struct view *view, enum request request, struct line *line);
226 	/* Search for regexp in a line. */
227 	bool (*grep)(struct view *view, struct line *line);
228 	/* Select line */
229 	void (*select)(struct view *view, struct line *line);
230 	/* Release resources when reloading the view */
231 	void (*done)(struct view *view);
232 	/* Supported view columns. */
233 	unsigned long column_bits;
234 	/* Extract line information. */
235 	bool (*get_column_data)(struct view *view, const struct line *line, struct view_column_data *column_data);
236 };
237 
238 /*
239  * Global view state.
240  */
241 
242 struct view *get_view(int index);
243 
244 #define foreach_view(view, i) \
245 	for (i = 0; (view = get_view(i)); i++)
246 
247 #define view_has_line(view, line_) \
248 	((view)->line <= (line_) && (line_) < (view)->line + (view)->lines)
249 
250 /*
251  * Navigation
252  */
253 
254 bool goto_view_line(struct view *view, unsigned long offset, unsigned long lineno);
255 void select_view_line(struct view *view, unsigned long lineno);
256 void do_scroll_view(struct view *view, int lines);
257 void scroll_view(struct view *view, enum request request);
258 void move_view(struct view *view, enum request request);
259 void goto_id(struct view *view, const char *expression, bool from_start, bool save_search);
260 
261 /*
262  * View history
263  */
264 
265 struct view_state {
266 	struct view_state *prev;	/* Entry below this in the stack */
267 	struct position position;	/* View position to restore */
268 	void *data;			/* View specific state */
269 };
270 
271 struct view_history {
272 	size_t state_alloc;
273 	struct view_state *stack;
274 	struct position position;
275 };
276 
277 struct view_state *push_view_history_state(struct view_history *history, struct position *position, void *data);
278 bool pop_view_history_state(struct view_history *history, struct position *position, void *data);
279 void reset_view_history(struct view_history *history);
280 
281 /*
282  * View opening
283  */
284 
285 void split_view(struct view *prev, struct view *view);
286 void maximize_view(struct view *view, bool redraw);
287 void load_view(struct view *view, struct view *prev, enum open_flags flags);
288 
289 #define refresh_view(view) load_view(view, NULL, OPEN_REFRESH)
290 #define reload_view(view) load_view(view, NULL, OPEN_RELOAD)
291 
292 void open_view(struct view *prev, struct view *view, enum open_flags flags);
293 void open_argv(struct view *prev, struct view *view, const char *argv[], const char *dir, enum open_flags flags);
294 bool view_exec(struct view *view, enum open_flags flags);
295 
296 /*
297  * Various utilities.
298  */
299 
300 #define get_sort_field(view) ((view)->sort.current->type)
301 void resort_view(struct view *view, bool renumber);
302 void sort_view(struct view *view, bool change_field);
303 
304 struct view_column *get_view_column(struct view *view, enum view_column_type type);
305 bool view_column_grep(struct view *view, struct line *line);
306 bool view_column_info_changed(struct view *view, bool update);
307 void view_column_reset(struct view *view);
308 bool view_column_info_update(struct view *view, struct line *line);
309 enum status_code parse_view_config(struct view_column **column, const char *view_name, const char *argv[]);
310 enum status_code parse_view_column_config(const char *view_name, enum view_column_type type, const char *option_name, const char *argv[]);
311 enum status_code format_view_config(struct view_column *column, char buf[], size_t bufsize);
312 bool view_has_wrapped_lines(struct view *view);
313 
314 struct line *
315 find_line_by_type(struct view *view, struct line *line, enum line_type type, int direction);
316 
317 #define find_prev_line_by_type(view, line, type) \
318 	find_line_by_type(view, line, type, -1)
319 
320 #define find_next_line_by_type(view, line, type) \
321 	find_line_by_type(view, line, type, 1)
322 
323 #define is_initial_view(view) (!(view)->prev && !(view)->argv)
324 #define failed_to_load_initial_view(view) (!(view)->prev && !(view)->lines)
325 
326 #define get_view_color(view, type)	get_line_color((view)->keymap->name, type)
327 #define get_view_attr(view, type)	get_line_attr((view)->keymap->name, type)
328 
329 /*
330  * Incremental updating
331  */
332 
333 static inline bool
check_position(struct position * pos)334 check_position(struct position *pos)
335 {
336 	return pos->lineno || pos->col || pos->offset;
337 }
338 
339 static inline void
clear_position(struct position * pos)340 clear_position(struct position *pos)
341 {
342 	memset(pos, 0, sizeof(*pos));
343 }
344 
345 void reset_view(struct view *view);
346 enum status_code begin_update(struct view *view, const char *dir, const char **argv, enum open_flags flags);
347 void end_update(struct view *view, bool force);
348 bool update_view(struct view *view);
349 void update_view_title(struct view *view);
350 
351 /*
352  * Line utilities.
353  */
354 
355 static inline const char *
box_text(const struct line * line)356 box_text(const struct line *line)
357 {
358 	const struct box *box = line->data;
359 
360 	return box->text;
361 }
362 
363 static inline size_t
box_text_length(const struct box * box)364 box_text_length(const struct box *box)
365 {
366 	size_t i, length = 0;
367 
368 	for (i = 0; i < box->cells; i++)
369 		length += box->cell[i].length;
370 
371 	return length;
372 }
373 
374 static inline size_t
box_sizeof(const struct box * box,size_t extra_cells,size_t extra_textlen)375 box_sizeof(const struct box *box, size_t extra_cells, size_t extra_textlen)
376 {
377 	size_t textlen = (box ? box_text_length(box) : 0) + extra_textlen;
378 	size_t cells = (box ? box->cells : 0) + extra_cells;
379 	size_t cells_size = cells > 1 ? sizeof(box->cell) * (cells - 1) : 0;
380 
381 	return sizeof(*box) + cells_size + textlen + 1;
382 }
383 
384 void box_text_copy(struct box *box, size_t cells, const char *src, size_t srclen);
385 
386 struct line *add_line_at(struct view *view, unsigned long pos, const void *data, enum line_type type, size_t data_size, bool custom);
387 struct line *add_line(struct view *view, const void *data, enum line_type type, size_t data_size, bool custom);
388 struct line *add_line_alloc_(struct view *view, void **ptr, enum line_type type, size_t data_size, bool custom);
389 
390 #define add_line_alloc(view, data_ptr, type, extra_size, custom) \
391 	add_line_alloc_(view, (void **) data_ptr, type, sizeof(**data_ptr) + extra_size, custom)
392 
393 struct line *add_line_nodata(struct view *view, enum line_type type);
394 struct line *add_line_text(struct view *view, const char *text, enum line_type type);
395 struct line *add_line_text_at(struct view *view, unsigned long pos, const char *text, enum line_type type, size_t cells);
396 struct line *add_line_text_at_(struct view *view, unsigned long pos, const char *text, size_t textlen, enum line_type type, size_t cells, bool custom);
397 struct line * PRINTF_LIKE(3, 4) add_line_format(struct view *view, enum line_type type, const char *fmt, ...);
398 bool append_line_format(struct view *view, struct line *line, const char *fmt, ...);
399 
400 #endif
401 /* vim: set ts=8 sw=8 noexpandtab: */
402