Rework the help view to not use line->other
[tig.git] / tig.h
blobe6fadc36fa169ec7d2af2822cc9bfaaff7f9c069
1 /* Copyright (c) 2006-2010 Jonas Fonseca <fonseca@diku.dk>
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 #ifndef TIG_H
15 #define TIG_H
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
21 #ifndef TIG_VERSION
22 #define TIG_VERSION "unknown-version"
23 #endif
25 #ifndef DEBUG
26 #define NDEBUG
27 #endif
29 /* necessary on Snow Leopard to use WINDOW struct */
30 #ifdef NCURSES_OPAQUE
31 #undef NCURSES_OPAQUE
32 #endif
33 #define NCURSES_OPAQUE 0
36 #include <assert.h>
37 #include <errno.h>
38 #include <ctype.h>
39 #include <signal.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <sys/stat.h>
47 #include <sys/select.h>
48 #include <unistd.h>
49 #include <sys/time.h>
50 #include <time.h>
51 #include <fcntl.h>
53 #include <regex.h>
55 #include <locale.h>
56 #include <langinfo.h>
57 #include <iconv.h>
59 /* ncurses(3): Must be defined to have extended wide-character functions. */
60 #define _XOPEN_SOURCE_EXTENDED
62 #ifdef HAVE_NCURSESW_H
63 #include <ncursesw/ncurses.h>
64 #else
65 #include <ncurses.h>
66 #endif
68 #if __GNUC__ >= 3
69 #define __NORETURN __attribute__((__noreturn__))
70 #else
71 #define __NORETURN
72 #endif
74 #define ABS(x) ((x) >= 0 ? (x) : -(x))
75 #define MIN(x, y) ((x) < (y) ? (x) : (y))
76 #define MAX(x, y) ((x) > (y) ? (x) : (y))
78 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
79 #define STRING_SIZE(x) (sizeof(x) - 1)
81 #define SIZEOF_STR 1024 /* Default string size. */
82 #define SIZEOF_REF 256 /* Size of symbolic or SHA1 ID. */
83 #define SIZEOF_REV 41 /* Holds a SHA-1 and an ending NUL. */
84 #define SIZEOF_ARG 32 /* Default argument array size. */
86 /* This color name can be used to refer to the default term colors. */
87 #define COLOR_DEFAULT (-1)
89 #define ENCODING_UTF8 "UTF-8"
90 #define ENCODING_SEP ": encoding: "
91 #define ENCODING_ARG "--encoding=" ENCODING_UTF8
93 #define ICONV_NONE ((iconv_t) -1)
94 #ifndef ICONV_CONST
95 #define ICONV_CONST /* nothing */
96 #endif
97 #define ICONV_TRANSLIT "//TRANSLIT"
99 /* The format and size of the date column in the main view. */
100 #define DATE_FORMAT "%Y-%m-%d %H:%M"
101 #define DATE_COLS STRING_SIZE("2006-04-29 14:21 ")
102 #define DATE_SHORT_COLS STRING_SIZE("2006-04-29 ")
104 #define ID_COLS 8
105 #define AUTHOR_COLS 19
106 #define FILENAME_COLS 19
108 #define MIN_VIEW_HEIGHT 4
110 #define NULL_ID "0000000000000000000000000000000000000000"
112 #define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
114 /* Some ASCII-shorthands fitted into the ncurses namespace. */
115 #define KEY_CTL(x) ((x) & 0x1f) /* KEY_CTL(A) == ^A == \1 */
116 #define KEY_TAB '\t'
117 #define KEY_RETURN '\r'
118 #define KEY_ESC 27
121 * Allocation helpers ... Entering macro hell to never be seen again.
124 #define DEFINE_ALLOCATOR(name, type, chunk_size) \
125 static type * \
126 name(type **mem, size_t size, size_t increase) \
128 size_t num_chunks = (size + chunk_size - 1) / chunk_size; \
129 size_t num_chunks_new = (size + increase + chunk_size - 1) / chunk_size;\
130 type *tmp = *mem; \
132 if (mem == NULL || num_chunks != num_chunks_new) { \
133 tmp = realloc(tmp, num_chunks_new * chunk_size * sizeof(type)); \
134 if (tmp) \
135 *mem = tmp; \
138 return tmp; \
142 * Strings.
145 #define prefixcmp(str1, str2) \
146 strncmp(str1, str2, STRING_SIZE(str2))
148 static inline bool
149 string_isnumber(const char *str)
151 int pos;
153 for (pos = 0; str[pos]; pos++) {
154 if (!isdigit(str[pos]))
155 return FALSE;
158 return pos > 0;
161 static inline bool
162 iscommit(char *str)
164 int pos;
166 for (pos = 0; str[pos]; pos++) {
167 if (!isxdigit(str[pos]))
168 return FALSE;
171 return 7 <= pos && pos < SIZEOF_REV;
174 static inline int
175 ascii_toupper(int c)
177 if (c >= 'a' && c <= 'z')
178 c &= ~0x20;
179 return c;
182 static inline int
183 ascii_tolower(int c)
185 if (c >= 'A' && c <= 'Z')
186 c |= 0x20;
187 return c;
190 static inline int
191 suffixcmp(const char *str, int slen, const char *suffix)
193 size_t len = slen >= 0 ? slen : strlen(str);
194 size_t suffixlen = strlen(suffix);
196 return suffixlen < len ? strcmp(str + len - suffixlen, suffix) : -1;
199 static inline void
200 string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
202 if (srclen > dstlen - 1)
203 srclen = dstlen - 1;
205 strncpy(dst, src, srclen);
206 dst[srclen] = 0;
209 /* Shorthands for safely copying into a fixed buffer. */
211 #define FORMAT_BUFFER(buf, bufsize, fmt, retval, allow_truncate) \
212 do { \
213 va_list args; \
214 va_start(args, fmt); \
215 retval = vsnprintf(buf, bufsize, fmt, args); \
216 va_end(args); \
217 if (retval >= (bufsize) && allow_truncate) { \
218 (buf)[(bufsize) - 1] = 0; \
219 (buf)[(bufsize) - 2] = '.'; \
220 (buf)[(bufsize) - 3] = '.'; \
221 (buf)[(bufsize) - 4] = '.'; \
222 retval = (bufsize) - 1; \
223 } else if (retval < 0 || retval >= (bufsize)) { \
224 retval = -1; \
226 } while (0)
228 #define string_copy(dst, src) \
229 string_ncopy_do(dst, sizeof(dst), src, sizeof(src))
231 #define string_ncopy(dst, src, srclen) \
232 string_ncopy_do(dst, sizeof(dst), src, srclen)
234 static inline void
235 string_copy_rev(char *dst, const char *src)
237 size_t srclen;
239 for (srclen = 0; srclen < SIZEOF_REV; srclen++)
240 if (isspace(src[srclen]))
241 break;
243 string_ncopy_do(dst, SIZEOF_REV, src, srclen);
246 #define string_add(dst, from, src) \
247 string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src))
249 static inline size_t
250 string_expand(char *dst, size_t dstlen, const char *src, int tabsize)
252 size_t size, pos;
254 for (size = pos = 0; size < dstlen - 1 && src[pos]; pos++) {
255 if (src[pos] == '\t') {
256 size_t expanded = tabsize - (size % tabsize);
258 if (expanded + size >= dstlen - 1)
259 expanded = dstlen - size - 1;
260 memcpy(dst + size, " ", expanded);
261 size += expanded;
262 } else {
263 dst[size++] = src[pos];
267 dst[size] = 0;
268 return pos;
271 static inline char *
272 chomp_string(char *name)
274 int namelen;
276 while (isspace(*name))
277 name++;
279 namelen = strlen(name) - 1;
280 while (namelen > 0 && isspace(name[namelen]))
281 name[namelen--] = 0;
283 return name;
286 static inline bool
287 string_nformat(char *buf, size_t bufsize, size_t *bufpos, const char *fmt, ...)
289 size_t pos = bufpos ? *bufpos : 0;
290 int retval;
292 FORMAT_BUFFER(buf + pos, bufsize - pos, fmt, retval, FALSE);
293 if (bufpos && retval > 0)
294 *bufpos = pos + retval;
296 return pos >= bufsize ? FALSE : TRUE;
299 #define string_format(buf, fmt, args...) \
300 string_nformat(buf, sizeof(buf), NULL, fmt, args)
302 #define string_format_from(buf, from, fmt, args...) \
303 string_nformat(buf, sizeof(buf), from, fmt, args)
305 static inline int
306 strcmp_null(const char *s1, const char *s2)
308 if (!s1 || !s2) {
309 return (!!s1) - (!!s2);
312 return strcmp(s1, s2);
316 * Enumerations
319 struct enum_map {
320 const char *name;
321 int namelen;
322 int value;
325 #define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
327 #define ENUM_SYM_MACRO(prefix, name) prefix##_##name
328 #define ENUM_MAP_MACRO(prefix, name) ENUM_MAP(#name, ENUM_SYM_MACRO(prefix, name))
330 #define DEFINE_ENUM(name, info) \
331 enum name { info(ENUM_SYM_MACRO) }; \
332 static const struct enum_map name##_map[] = { info(ENUM_MAP_MACRO) }
334 static inline int
335 string_enum_compare(const char *str1, const char *str2, int len)
337 size_t i;
339 #define string_enum_sep(x) ((x) == '-' || (x) == '_' || (x) == '.')
341 /* Diff-Header == DIFF_HEADER */
342 for (i = 0; i < len; i++) {
343 if (ascii_toupper(str1[i]) == ascii_toupper(str2[i]))
344 continue;
346 if (string_enum_sep(str1[i]) &&
347 string_enum_sep(str2[i]))
348 continue;
350 return str1[i] - str2[i];
353 return 0;
356 #define enum_equals(entry, str, len) \
357 ((entry).namelen == (len) && !string_enum_compare((entry).name, str, len))
359 static inline char *
360 enum_map_name(const char *name, size_t namelen)
362 static char buf[SIZEOF_STR];
363 int bufpos;
365 for (bufpos = 0; bufpos <= namelen; bufpos++) {
366 buf[bufpos] = ascii_tolower(name[bufpos]);
367 if (buf[bufpos] == '_')
368 buf[bufpos] = '-';
371 buf[bufpos] = 0;
372 return buf;
375 #define enum_name(entry) enum_map_name((entry).name, (entry).namelen)
377 static inline bool
378 map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
380 size_t namelen = strlen(name);
381 int i;
383 for (i = 0; i < map_size; i++)
384 if (enum_equals(map[i], name, namelen)) {
385 *value = map[i].value;
386 return TRUE;
389 return FALSE;
392 #define map_enum(attr, map, name) \
393 map_enum_do(map, ARRAY_SIZE(map), attr, name)
396 * Unicode / UTF-8 handling
398 * NOTE: Much of the following code for dealing with Unicode is derived from
399 * ELinks' UTF-8 code developed by Scrool <scroolik@gmail.com>. Origin file is
400 * src/intl/charset.c from the UTF-8 branch commit elinks-0.11.0-g31f2c28.
403 static inline int
404 unicode_width(unsigned long c, int tab_size)
406 if (c >= 0x1100 &&
407 (c <= 0x115f /* Hangul Jamo */
408 || c == 0x2329
409 || c == 0x232a
410 || (c >= 0x2e80 && c <= 0xa4cf && c != 0x303f)
411 /* CJK ... Yi */
412 || (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
413 || (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility Ideographs */
414 || (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
415 || (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
416 || (c >= 0xffe0 && c <= 0xffe6)
417 || (c >= 0x20000 && c <= 0x2fffd)
418 || (c >= 0x30000 && c <= 0x3fffd)))
419 return 2;
421 if (c == '\t')
422 return tab_size;
424 return 1;
427 /* Number of bytes used for encoding a UTF-8 character indexed by first byte.
428 * Illegal bytes are set one. */
429 static const unsigned char utf8_bytes[256] = {
430 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
431 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
432 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
433 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
434 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
435 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
436 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
437 3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1,
440 static inline unsigned char
441 utf8_char_length(const char *string, const char *end)
443 int c = *(unsigned char *) string;
445 return utf8_bytes[c];
448 /* Decode UTF-8 multi-byte representation into a Unicode character. */
449 static inline unsigned long
450 utf8_to_unicode(const char *string, size_t length)
452 unsigned long unicode;
454 switch (length) {
455 case 1:
456 unicode = string[0];
457 break;
458 case 2:
459 unicode = (string[0] & 0x1f) << 6;
460 unicode += (string[1] & 0x3f);
461 break;
462 case 3:
463 unicode = (string[0] & 0x0f) << 12;
464 unicode += ((string[1] & 0x3f) << 6);
465 unicode += (string[2] & 0x3f);
466 break;
467 case 4:
468 unicode = (string[0] & 0x0f) << 18;
469 unicode += ((string[1] & 0x3f) << 12);
470 unicode += ((string[2] & 0x3f) << 6);
471 unicode += (string[3] & 0x3f);
472 break;
473 case 5:
474 unicode = (string[0] & 0x0f) << 24;
475 unicode += ((string[1] & 0x3f) << 18);
476 unicode += ((string[2] & 0x3f) << 12);
477 unicode += ((string[3] & 0x3f) << 6);
478 unicode += (string[4] & 0x3f);
479 break;
480 case 6:
481 unicode = (string[0] & 0x01) << 30;
482 unicode += ((string[1] & 0x3f) << 24);
483 unicode += ((string[2] & 0x3f) << 18);
484 unicode += ((string[3] & 0x3f) << 12);
485 unicode += ((string[4] & 0x3f) << 6);
486 unicode += (string[5] & 0x3f);
487 break;
488 default:
489 return 0;
492 /* Invalid characters could return the special 0xfffd value but NUL
493 * should be just as good. */
494 return unicode > 0xffff ? 0 : unicode;
497 /* Calculates how much of string can be shown within the given maximum width
498 * and sets trimmed parameter to non-zero value if all of string could not be
499 * shown. If the reserve flag is TRUE, it will reserve at least one
500 * trailing character, which can be useful when drawing a delimiter.
502 * Returns the number of bytes to output from string to satisfy max_width. */
503 static inline size_t
504 utf8_length(const char **start, size_t skip, int *width, size_t max_width, int *trimmed, bool reserve, int tab_size)
506 const char *string = *start;
507 const char *end = strchr(string, '\0');
508 unsigned char last_bytes = 0;
509 size_t last_ucwidth = 0;
511 *width = 0;
512 *trimmed = 0;
514 while (string < end) {
515 unsigned char bytes = utf8_char_length(string, end);
516 size_t ucwidth;
517 unsigned long unicode;
519 if (string + bytes > end)
520 break;
522 /* Change representation to figure out whether
523 * it is a single- or double-width character. */
525 unicode = utf8_to_unicode(string, bytes);
526 /* FIXME: Graceful handling of invalid Unicode character. */
527 if (!unicode)
528 break;
530 ucwidth = unicode_width(unicode, tab_size);
531 if (skip > 0) {
532 skip -= ucwidth <= skip ? ucwidth : skip;
533 *start += bytes;
535 *width += ucwidth;
536 if (*width > max_width) {
537 *trimmed = 1;
538 *width -= ucwidth;
539 if (reserve && *width == max_width) {
540 string -= last_bytes;
541 *width -= last_ucwidth;
543 break;
546 string += bytes;
547 last_bytes = ucwidth ? bytes : 0;
548 last_ucwidth = ucwidth;
551 return string - *start;
554 #endif