Move format_argv to argv module
[tig.git] / src / draw.c
blob7a3b9c399228aad91af997420e5402f6798b978f
1 /* Copyright (c) 2006-2014 Jonas Fonseca <jonas.fonseca@gmail.com>
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.
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.
14 #include "tig.h"
15 #include "draw.h"
16 #include "options.h"
19 * View drawing.
22 static inline void
23 set_view_attr(struct view *view, enum line_type type)
25 if (!view->curline->selected && view->curtype != type) {
26 (void) wattrset(view->win, get_line_attr(type));
27 wchgat(view->win, -1, 0, get_line_color(type), NULL);
28 view->curtype = type;
32 #define VIEW_MAX_LEN(view) ((view)->width + (view)->pos.col - (view)->col)
34 static bool
35 draw_chars(struct view *view, enum line_type type, const char *string,
36 int max_len, bool use_tilde)
38 int len = 0;
39 int col = 0;
40 int trimmed = FALSE;
41 size_t skip = view->pos.col > view->col ? view->pos.col - view->col : 0;
43 if (max_len <= 0)
44 return VIEW_MAX_LEN(view) <= 0;
46 if (opt_iconv_out != ICONV_NONE) {
47 string = encoding_iconv(opt_iconv_out, string);
48 if (!string)
49 return VIEW_MAX_LEN(view) <= 0;
52 len = utf8_length(&string, skip, &col, max_len, &trimmed, use_tilde, opt_tab_size);
54 set_view_attr(view, type);
55 if (len > 0) {
56 waddnstr(view->win, string, len);
58 if (trimmed && use_tilde) {
59 set_view_attr(view, LINE_DELIMITER);
60 waddch(view->win, '~');
61 col++;
65 view->col += col;
66 return VIEW_MAX_LEN(view) <= 0;
69 static bool
70 draw_space(struct view *view, enum line_type type, int max, int spaces)
72 static char space[] = " ";
74 spaces = MIN(max, spaces);
76 while (spaces > 0) {
77 int len = MIN(spaces, sizeof(space) - 1);
79 if (draw_chars(view, type, space, len, FALSE))
80 return TRUE;
81 spaces -= len;
84 return VIEW_MAX_LEN(view) <= 0;
87 static bool
88 draw_text_expanded(struct view *view, enum line_type type, const char *string, int max_len, bool use_tilde)
90 static char text[SIZEOF_STR];
92 do {
93 size_t pos = string_expand(text, sizeof(text), string, opt_tab_size);
95 if (draw_chars(view, type, text, max_len, use_tilde))
96 return TRUE;
97 string += pos;
98 } while (*string);
100 return VIEW_MAX_LEN(view) <= 0;
103 bool
104 draw_text(struct view *view, enum line_type type, const char *string)
106 return draw_text_expanded(view, type, string, VIEW_MAX_LEN(view), TRUE);
109 bool
110 draw_text_overflow(struct view *view, const char *text, bool on, int overflow, enum line_type type)
112 if (on) {
113 int max = MIN(VIEW_MAX_LEN(view), overflow);
114 int len = strlen(text);
116 if (draw_text_expanded(view, type, text, max, max < overflow))
117 return TRUE;
119 text = len > overflow ? text + overflow : "";
120 type = LINE_OVERFLOW;
123 if (*text && draw_text(view, type, text))
124 return TRUE;
126 return VIEW_MAX_LEN(view) <= 0;
129 bool PRINTF_LIKE(3, 4)
130 draw_formatted(struct view *view, enum line_type type, const char *format, ...)
132 char text[SIZEOF_STR];
133 int retval;
135 FORMAT_BUFFER(text, sizeof(text), format, retval, TRUE);
136 return retval >= 0 ? draw_text(view, type, text) : VIEW_MAX_LEN(view) <= 0;
139 bool
140 draw_graphic(struct view *view, enum line_type type, const chtype graphic[], size_t size, bool separator)
142 size_t skip = view->pos.col > view->col ? view->pos.col - view->col : 0;
143 int max = VIEW_MAX_LEN(view);
144 int i;
146 if (max < size)
147 size = max;
149 set_view_attr(view, type);
150 /* Using waddch() instead of waddnstr() ensures that
151 * they'll be rendered correctly for the cursor line. */
152 for (i = skip; i < size; i++)
153 waddch(view->win, graphic[i]);
155 view->col += size;
156 if (separator) {
157 if (size < max && skip <= size)
158 waddch(view->win, ' ');
159 view->col++;
162 return VIEW_MAX_LEN(view) <= 0;
165 bool
166 draw_field(struct view *view, enum line_type type, const char *text, int width, enum align align, bool trim)
168 int max = MIN(VIEW_MAX_LEN(view), width + 1);
169 int col = view->col;
171 if (!text)
172 return draw_space(view, type, max, max);
174 if (align == ALIGN_RIGHT) {
175 int textlen = strlen(text);
176 int leftpad = max - textlen - 1;
178 if (leftpad > 0) {
179 if (draw_space(view, type, leftpad, leftpad))
180 return TRUE;
181 max -= leftpad;
182 col += leftpad;;
186 return draw_chars(view, type, text, max - 1, trim)
187 || draw_space(view, LINE_DEFAULT, max - (view->col - col), max);
190 bool
191 draw_date(struct view *view, struct time *time)
193 const char *date = mkdate(time, opt_show_date);
194 int cols = opt_show_date == DATE_SHORT ? DATE_SHORT_WIDTH : DATE_WIDTH;
196 if (opt_show_date == DATE_NO)
197 return FALSE;
199 return draw_field(view, LINE_DATE, date, cols, ALIGN_LEFT, FALSE);
202 bool
203 draw_author(struct view *view, const struct ident *author)
205 bool trim = author_trim(opt_author_width);
206 const char *text = mkauthor(author, opt_author_width, opt_show_author);
208 if (opt_show_author == AUTHOR_NO)
209 return FALSE;
211 return draw_field(view, LINE_AUTHOR, text, opt_author_width, ALIGN_LEFT, trim);
214 bool
215 draw_id_custom(struct view *view, enum line_type type, const char *id, int width)
217 return draw_field(view, type, id, width, ALIGN_LEFT, FALSE);
220 bool
221 draw_id(struct view *view, const char *id)
223 if (!opt_show_id)
224 return FALSE;
226 return draw_id_custom(view, LINE_ID, id, opt_id_width);
229 bool
230 draw_filename(struct view *view, const char *filename, bool auto_enabled)
232 bool trim = filename && strlen(filename) >= opt_show_filename_width;
234 if (opt_show_filename == FILENAME_NO)
235 return FALSE;
237 if (opt_show_filename == FILENAME_AUTO && !auto_enabled)
238 return FALSE;
240 return draw_field(view, LINE_FILENAME, filename, opt_show_filename_width, ALIGN_LEFT, trim);
243 bool
244 draw_file_size(struct view *view, unsigned long size, int width, bool pad)
246 const char *str = pad ? NULL : mkfilesize(size, opt_show_file_size);
248 if (!width || opt_show_file_size == FILE_SIZE_NO)
249 return FALSE;
251 return draw_field(view, LINE_FILE_SIZE, str, width, ALIGN_RIGHT, FALSE);
254 bool
255 draw_mode(struct view *view, mode_t mode)
257 const char *str = mkmode(mode);
259 return draw_field(view, LINE_MODE, str, STRING_SIZE("-rw-r--r--"), ALIGN_LEFT, FALSE);
262 bool
263 draw_lineno(struct view *view, unsigned int lineno)
265 char number[10];
266 int digits3 = view->digits < 3 ? 3 : view->digits;
267 int max = MIN(VIEW_MAX_LEN(view), digits3);
268 char *text = NULL;
269 chtype separator = opt_line_graphics ? ACS_VLINE : '|';
271 if (!opt_show_line_numbers)
272 return FALSE;
274 lineno += view->pos.offset + 1;
275 if (lineno == 1 || (lineno % opt_line_number_interval) == 0) {
276 static char fmt[] = "%1ld";
278 fmt[1] = '0' + (view->digits <= 9 ? digits3 : 1);
279 if (string_format(number, fmt, lineno))
280 text = number;
282 if (text)
283 draw_chars(view, LINE_LINE_NUMBER, text, max, TRUE);
284 else
285 draw_space(view, LINE_LINE_NUMBER, max, digits3);
286 return draw_graphic(view, LINE_DEFAULT, &separator, 1, TRUE);
289 bool
290 draw_refs(struct view *view, struct ref_list *refs)
292 size_t i;
294 if (!opt_show_refs || !refs)
295 return FALSE;
297 for (i = 0; i < refs->size; i++) {
298 struct ref *ref = refs->refs[i];
299 enum line_type type = get_line_type_from_ref(ref);
301 if (draw_formatted(view, type, "[%s]", ref->name))
302 return TRUE;
304 if (draw_text(view, LINE_DEFAULT, " "))
305 return TRUE;
308 return FALSE;
311 bool
312 draw_view_line(struct view *view, unsigned int lineno)
314 struct line *line;
315 bool selected = (view->pos.offset + lineno == view->pos.lineno);
317 /* FIXME: Disabled during code split.
318 assert(view_is_displayed(view));
321 if (view->pos.offset + lineno >= view->lines)
322 return FALSE;
324 line = &view->line[view->pos.offset + lineno];
326 wmove(view->win, lineno, 0);
327 if (line->cleareol)
328 wclrtoeol(view->win);
329 view->col = 0;
330 view->curline = line;
331 view->curtype = LINE_NONE;
332 line->selected = FALSE;
333 line->dirty = line->cleareol = 0;
335 if (selected) {
336 set_view_attr(view, LINE_CURSOR);
337 line->selected = TRUE;
338 view->ops->select(view, line);
341 return view->ops->draw(view, line, lineno);
344 void
345 redraw_view_dirty(struct view *view)
347 bool dirty = FALSE;
348 int lineno;
350 for (lineno = 0; lineno < view->height; lineno++) {
351 if (view->pos.offset + lineno >= view->lines)
352 break;
353 if (!view->line[view->pos.offset + lineno].dirty)
354 continue;
355 dirty = TRUE;
356 if (!draw_view_line(view, lineno))
357 break;
360 if (!dirty)
361 return;
362 wnoutrefresh(view->win);
365 void
366 redraw_view_from(struct view *view, int lineno)
368 assert(0 <= lineno && lineno < view->height);
370 for (; lineno < view->height; lineno++) {
371 if (!draw_view_line(view, lineno))
372 break;
375 wnoutrefresh(view->win);
378 void
379 redraw_view(struct view *view)
381 werase(view->win);
382 redraw_view_from(view, 0);
385 /* vim: set ts=8 sw=8 noexpandtab: */