tig(1): document the Git commands supported by the pager mode
[tig.git] / tig.h
blob9b4aa1106216f54e4b4b2f59d13347375351ecf0
1 /* Copyright (c) 2006-2013 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 #include "compat/compat.h"
23 #ifndef TIG_VERSION
24 #define TIG_VERSION "unknown-version"
25 #endif
27 #ifndef DEBUG
28 #define NDEBUG
29 #endif
31 /* necessary on Snow Leopard to use WINDOW struct */
32 #ifdef NCURSES_OPAQUE
33 #undef NCURSES_OPAQUE
34 #endif
35 #define NCURSES_OPAQUE 0
38 #include <assert.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <signal.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/types.h>
47 #include <sys/wait.h>
48 #include <sys/stat.h>
49 #include <sys/select.h>
50 #include <unistd.h>
51 #include <sys/time.h>
52 #include <time.h>
53 #include <fcntl.h>
55 #include <regex.h>
57 #include <locale.h>
58 #include <langinfo.h>
59 #include <iconv.h>
61 /* ncurses(3): Must be defined to have extended wide-character functions. */
62 #define _XOPEN_SOURCE_EXTENDED
64 #if defined HAVE_NCURSESW_CURSES_H
65 # include <ncursesw/curses.h>
66 #elif defined HAVE_NCURSESW_H
67 # include <ncursesw.h>
68 #elif defined HAVE_NCURSES_CURSES_H
69 # include <ncurses/curses.h>
70 #elif defined HAVE_NCURSES_H
71 # include <ncurses.h>
72 #elif defined HAVE_CURSES_H
73 # include <curses.h>
74 #else
75 #ifdef WARN_MISSING_CURSES_CONFIGURATION
76 # warning SysV or X/Open-compatible Curses installation is required.
77 # warning Will assume Curses is found in default include and library path.
78 # warning To fix any build issues please use autotools to configure Curses.
79 # warning See INSTALL file for instructions.
80 #endif
81 # include <curses.h>
82 #endif
84 #if __GNUC__ >= 3
85 #define TIG_NORETURN __attribute__((__noreturn__))
86 #define PRINTF_LIKE(fmt, args) __attribute__((format (printf, fmt, args)))
87 #else
88 #define TIG_NORETURN
89 #define PRINTF_LIKE(fmt, args)
90 #endif
92 #define ABS(x) ((x) >= 0 ? (x) : -(x))
93 #define MIN(x, y) ((x) < (y) ? (x) : (y))
94 #define MAX(x, y) ((x) > (y) ? (x) : (y))
96 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
97 #define STRING_SIZE(x) (sizeof(x) - 1)
99 #define SIZEOF_STR 1024 /* Default string size. */
100 #define SIZEOF_REF 256 /* Size of symbolic or SHA1 ID. */
101 #define SIZEOF_REV 41 /* Holds a SHA-1 and an ending NUL. */
102 #define SIZEOF_ARG 32 /* Default argument array size. */
104 /* This color name can be used to refer to the default term colors. */
105 #define COLOR_DEFAULT (-1)
107 #define ENCODING_UTF8 "UTF-8"
108 #define ENCODING_SEP ": encoding: "
109 #define ENCODING_ARG "--encoding=" ENCODING_UTF8
111 #define ICONV_NONE ((iconv_t) -1)
112 #ifndef ICONV_CONST
113 #define ICONV_CONST /* nothing */
114 #endif
115 #define ICONV_TRANSLIT "//TRANSLIT//IGNORE"
117 /* The format and size of the date column in the main view. */
118 #define DATE_FORMAT "%Y-%m-%d %H:%M"
119 #define DATE_WIDTH STRING_SIZE("2006-04-29 14:21")
120 #define DATE_SHORT_WIDTH STRING_SIZE("2006-04-29")
122 #define ID_WIDTH 7
123 #define AUTHOR_WIDTH 18
124 #define FILENAME_WIDTH 18
126 #define MIN_VIEW_HEIGHT 4
127 #define MIN_VIEW_WIDTH 4
129 #define NULL_ID "0000000000000000000000000000000000000000"
131 #define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
133 /* Some ASCII-shorthands fitted into the ncurses namespace. */
134 #define KEY_CTL(x) ((x) & 0x1f) /* KEY_CTL(A) == ^A == \1 */
135 #define KEY_TAB '\t'
136 #define KEY_RETURN '\r'
137 #define KEY_ESC 27
140 * Allocation helpers ... Entering macro hell to never be seen again.
143 #define DEFINE_ALLOCATOR(name, type, chunk_size) \
144 static type * \
145 name(type **mem, size_t size, size_t increase) \
147 size_t num_chunks = (size + chunk_size - 1) / chunk_size; \
148 size_t num_chunks_new = (size + increase + chunk_size - 1) / chunk_size;\
149 type *tmp = *mem; \
151 if (mem == NULL || num_chunks != num_chunks_new) { \
152 size_t newsize = num_chunks_new * chunk_size * sizeof(type); \
154 tmp = realloc(tmp, newsize); \
155 if (tmp) { \
156 *mem = tmp; \
157 if (num_chunks_new > num_chunks) { \
158 size_t offset = num_chunks * chunk_size; \
159 size_t oldsize = offset * sizeof(type); \
161 memset(tmp + offset, 0, newsize - oldsize); \
166 return tmp; \
169 static inline int
170 count_digits(unsigned long i)
172 int digits;
174 for (digits = 0; i; digits++)
175 i /= 10;
176 return digits;
180 * Strings.
183 #define prefixcmp(str1, str2) \
184 strncmp(str1, str2, STRING_SIZE(str2))
186 static inline bool
187 string_isnumber(const char *str)
189 int pos;
191 for (pos = 0; str[pos]; pos++) {
192 if (!isdigit(str[pos]))
193 return FALSE;
196 return pos > 0;
199 static inline bool
200 iscommit(char *str)
202 int pos;
204 for (pos = 0; str[pos]; pos++) {
205 if (!isxdigit(str[pos]))
206 return FALSE;
209 return 7 <= pos && pos < SIZEOF_REV;
212 static inline int
213 ascii_toupper(int c)
215 if (c >= 'a' && c <= 'z')
216 c &= ~0x20;
217 return c;
220 static inline int
221 ascii_tolower(int c)
223 if (c >= 'A' && c <= 'Z')
224 c |= 0x20;
225 return c;
228 static inline int
229 suffixcmp(const char *str, int slen, const char *suffix)
231 size_t len = slen >= 0 ? slen : strlen(str);
232 size_t suffixlen = strlen(suffix);
234 return suffixlen < len ? strcmp(str + len - suffixlen, suffix) : -1;
237 static inline void
238 string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
240 if (srclen > dstlen - 1)
241 srclen = dstlen - 1;
243 strncpy(dst, src, srclen);
244 dst[srclen] = 0;
247 /* Shorthands for safely copying into a fixed buffer. */
249 #define FORMAT_BUFFER(buf, bufsize, fmt, retval, allow_truncate) \
250 do { \
251 va_list args; \
252 va_start(args, fmt); \
253 retval = vsnprintf(buf, bufsize, fmt, args); \
254 va_end(args); \
255 if (retval >= (bufsize) && allow_truncate) { \
256 (buf)[(bufsize) - 1] = 0; \
257 (buf)[(bufsize) - 2] = '.'; \
258 (buf)[(bufsize) - 3] = '.'; \
259 (buf)[(bufsize) - 4] = '.'; \
260 retval = (bufsize) - 1; \
261 } else if (retval < 0 || retval >= (bufsize)) { \
262 retval = -1; \
264 } while (0)
266 #define string_copy(dst, src) \
267 string_ncopy_do(dst, sizeof(dst), src, sizeof(src))
269 #define string_ncopy(dst, src, srclen) \
270 string_ncopy_do(dst, sizeof(dst), src, srclen)
272 static inline void
273 string_copy_rev(char *dst, const char *src)
275 size_t srclen;
277 if (!*src)
278 return;
280 for (srclen = 0; srclen < SIZEOF_REV; srclen++)
281 if (isspace(src[srclen]))
282 break;
284 string_ncopy_do(dst, SIZEOF_REV, src, srclen);
287 static inline void
288 string_copy_rev_from_commit_line(char *dst, const char *src)
290 string_copy_rev(dst, src + STRING_SIZE("commit "));
293 #define string_rev_is_null(rev) !strncmp(rev, NULL_ID, STRING_SIZE(NULL_ID))
295 #define string_add(dst, from, src) \
296 string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src))
298 static inline size_t
299 string_expanded_length(const char *src, size_t srclen, size_t tabsize, size_t max_size)
301 size_t size, pos;
303 for (size = pos = 0; pos < srclen && size < max_size; pos++) {
304 if (src[pos] == '\t') {
305 size_t expanded = tabsize - (size % tabsize);
307 size += expanded;
308 } else {
309 size++;
313 return pos;
316 static inline size_t
317 string_expand(char *dst, size_t dstlen, const char *src, int tabsize)
319 size_t size, pos;
321 for (size = pos = 0; size < dstlen - 1 && src[pos]; pos++) {
322 if (src[pos] == '\t') {
323 size_t expanded = tabsize - (size % tabsize);
325 if (expanded + size >= dstlen - 1)
326 expanded = dstlen - size - 1;
327 memcpy(dst + size, " ", expanded);
328 size += expanded;
329 } else {
330 dst[size++] = src[pos];
334 dst[size] = 0;
335 return pos;
338 static inline char *
339 chomp_string(char *name)
341 int namelen;
343 while (isspace(*name))
344 name++;
346 namelen = strlen(name) - 1;
347 while (namelen > 0 && isspace(name[namelen]))
348 name[namelen--] = 0;
350 return name;
353 static inline bool PRINTF_LIKE(4, 5)
354 string_nformat(char *buf, size_t bufsize, size_t *bufpos, const char *fmt, ...)
356 size_t pos = bufpos ? *bufpos : 0;
357 int retval;
359 FORMAT_BUFFER(buf + pos, bufsize - pos, fmt, retval, FALSE);
360 if (bufpos && retval > 0)
361 *bufpos = pos + retval;
363 return pos >= bufsize ? FALSE : TRUE;
366 #define string_format(buf, fmt, args...) \
367 string_nformat(buf, sizeof(buf), NULL, fmt, args)
369 #define string_format_size(buf, size, fmt, args...) \
370 string_nformat(buf, size, NULL, fmt, args)
372 #define string_format_from(buf, from, fmt, args...) \
373 string_nformat(buf, sizeof(buf), from, fmt, args)
375 static inline int
376 strcmp_null(const char *s1, const char *s2)
378 if (!s1 || !s2) {
379 return (!!s1) - (!!s2);
382 return strcmp(s1, s2);
386 * Enumerations
389 struct enum_map {
390 const char *name;
391 int namelen;
392 int value;
395 #define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
397 #define ENUM_SYM_MACRO(prefix, name) prefix##_##name
398 #define ENUM_MAP_MACRO(prefix, name) ENUM_MAP(#name, ENUM_SYM_MACRO(prefix, name))
400 #define DEFINE_ENUM(name, info) \
401 enum name { info(ENUM_SYM_MACRO) }; \
402 static const struct enum_map name##_map[] = { info(ENUM_MAP_MACRO) }
404 static inline int
405 string_enum_compare(const char *str1, const char *str2, int len)
407 size_t i;
409 #define string_enum_sep(x) ((x) == '-' || (x) == '_' || (x) == '.')
411 /* Diff-Header == DIFF_HEADER */
412 for (i = 0; i < len; i++) {
413 if (ascii_toupper(str1[i]) == ascii_toupper(str2[i]))
414 continue;
416 if (string_enum_sep(str1[i]) &&
417 string_enum_sep(str2[i]))
418 continue;
420 return str1[i] - str2[i];
423 return 0;
426 #define enum_equals(entry, str, len) \
427 ((entry).namelen == (len) && !string_enum_compare((entry).name, str, len))
429 static inline char *
430 enum_map_name(const char *name, size_t namelen)
432 static char buf[SIZEOF_STR];
433 int bufpos;
435 for (bufpos = 0; bufpos <= namelen; bufpos++) {
436 buf[bufpos] = ascii_tolower(name[bufpos]);
437 if (buf[bufpos] == '_')
438 buf[bufpos] = '-';
441 buf[bufpos] = 0;
442 return buf;
445 #define enum_name(entry) enum_map_name((entry).name, (entry).namelen)
447 static inline bool
448 map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
450 size_t namelen = strlen(name);
451 int i;
453 for (i = 0; i < map_size; i++)
454 if (enum_equals(map[i], name, namelen)) {
455 *value = map[i].value;
456 return TRUE;
459 return FALSE;
462 #define map_enum(attr, map, name) \
463 map_enum_do(map, ARRAY_SIZE(map), attr, name)
466 * Unicode / UTF-8 handling
468 * NOTE: Much of the following code for dealing with Unicode is derived from
469 * ELinks' UTF-8 code developed by Scrool <scroolik@gmail.com>. Origin file is
470 * src/intl/charset.c from the UTF-8 branch commit elinks-0.11.0-g31f2c28.
473 static inline int
474 unicode_width(unsigned long c, int tab_size)
476 if (c >= 0x1100 &&
477 (c <= 0x115f /* Hangul Jamo */
478 || c == 0x2329
479 || c == 0x232a
480 || (c >= 0x2e80 && c <= 0xa4cf && c != 0x303f)
481 /* CJK ... Yi */
482 || (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
483 || (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility Ideographs */
484 || (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
485 || (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
486 || (c >= 0xffe0 && c <= 0xffe6)
487 || (c >= 0x20000 && c <= 0x2fffd)
488 || (c >= 0x30000 && c <= 0x3fffd)))
489 return 2;
491 if ((c >= 0x0300 && c <= 0x036f) /* combining diacretical marks */
492 || (c >= 0x1dc0 && c <= 0x1dff) /* combining diacretical marks supplement */
493 || (c >= 0x20d0 && c <= 0x20ff) /* combining diacretical marks for symbols */
494 || (c >= 0xfe20 && c <= 0xfe2f)) /* combining half marks */
495 return 0;
497 if (c == '\t')
498 return tab_size;
500 return 1;
503 /* Number of bytes used for encoding a UTF-8 character indexed by first byte.
504 * Illegal bytes are set one. */
505 static const unsigned char utf8_bytes[256] = {
506 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,
507 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,
508 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,
509 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,
510 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,
511 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,
512 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,
513 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,
516 static inline unsigned char
517 utf8_char_length(const char *string, const char *end)
519 int c = *(unsigned char *) string;
521 return utf8_bytes[c];
524 /* Decode UTF-8 multi-byte representation into a Unicode character. */
525 static inline unsigned long
526 utf8_to_unicode(const char *string, size_t length)
528 unsigned long unicode;
530 switch (length) {
531 case 1:
532 unicode = string[0];
533 break;
534 case 2:
535 unicode = (string[0] & 0x1f) << 6;
536 unicode += (string[1] & 0x3f);
537 break;
538 case 3:
539 unicode = (string[0] & 0x0f) << 12;
540 unicode += ((string[1] & 0x3f) << 6);
541 unicode += (string[2] & 0x3f);
542 break;
543 case 4:
544 unicode = (string[0] & 0x0f) << 18;
545 unicode += ((string[1] & 0x3f) << 12);
546 unicode += ((string[2] & 0x3f) << 6);
547 unicode += (string[3] & 0x3f);
548 break;
549 case 5:
550 unicode = (string[0] & 0x0f) << 24;
551 unicode += ((string[1] & 0x3f) << 18);
552 unicode += ((string[2] & 0x3f) << 12);
553 unicode += ((string[3] & 0x3f) << 6);
554 unicode += (string[4] & 0x3f);
555 break;
556 case 6:
557 unicode = (string[0] & 0x01) << 30;
558 unicode += ((string[1] & 0x3f) << 24);
559 unicode += ((string[2] & 0x3f) << 18);
560 unicode += ((string[3] & 0x3f) << 12);
561 unicode += ((string[4] & 0x3f) << 6);
562 unicode += (string[5] & 0x3f);
563 break;
564 default:
565 return 0;
568 /* Invalid characters could return the special 0xfffd value but NUL
569 * should be just as good. */
570 return unicode > 0xffff ? 0 : unicode;
573 /* Calculates how much of string can be shown within the given maximum width
574 * and sets trimmed parameter to non-zero value if all of string could not be
575 * shown. If the reserve flag is TRUE, it will reserve at least one
576 * trailing character, which can be useful when drawing a delimiter.
578 * Returns the number of bytes to output from string to satisfy max_width. */
579 static inline size_t
580 utf8_length(const char **start, size_t skip, int *width, size_t max_width, int *trimmed, bool reserve, int tab_size)
582 const char *string = *start;
583 const char *end = strchr(string, '\0');
584 unsigned char last_bytes = 0;
585 size_t last_ucwidth = 0;
587 *width = 0;
588 *trimmed = 0;
590 while (string < end) {
591 unsigned char bytes = utf8_char_length(string, end);
592 size_t ucwidth;
593 unsigned long unicode;
595 if (string + bytes > end)
596 break;
598 /* Change representation to figure out whether
599 * it is a single- or double-width character. */
601 unicode = utf8_to_unicode(string, bytes);
602 /* FIXME: Graceful handling of invalid Unicode character. */
603 if (!unicode)
604 break;
606 ucwidth = unicode_width(unicode, tab_size);
607 if (skip > 0) {
608 skip -= ucwidth <= skip ? ucwidth : skip;
609 *start += bytes;
611 *width += ucwidth;
612 if (*width > max_width) {
613 *trimmed = 1;
614 *width -= ucwidth;
615 if (reserve && *width == max_width) {
616 string -= last_bytes;
617 *width -= last_ucwidth;
619 break;
622 string += bytes;
623 last_bytes = ucwidth ? bytes : 0;
624 last_ucwidth = ucwidth;
627 return string - *start;
630 #endif
632 /* vim: set ts=8 sw=8 noexpandtab: */