Fix tests that passed expected input to assert_equals
[tig.git] / src / line.c
blobff217c8db88400d4b056d9d5ee2120655b6e8391
1 /* Copyright (c) 2006-2015 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/tig.h"
15 #include "tig/types.h"
16 #include "tig/refdb.h"
17 #include "tig/line.h"
18 #include "tig/util.h"
20 static struct line_rule *line_rule;
21 static size_t line_rules;
23 static struct line_info **color_pair;
24 static size_t color_pairs;
26 DEFINE_ALLOCATOR(realloc_line_rule, struct line_rule, 8)
27 DEFINE_ALLOCATOR(realloc_color_pair, struct line_info *, 8)
29 enum line_type
30 get_line_type(const char *line)
32 int linelen = strlen(line);
33 enum line_type type;
35 for (type = 0; type < line_rules; type++) {
36 struct line_rule *rule = &line_rule[type];
38 /* Case insensitive search matches Signed-off-by lines better. */
39 if (rule->linelen && linelen >= rule->linelen &&
40 !strncasecmp(rule->line, line, rule->linelen))
41 return type;
44 return LINE_DEFAULT;
47 enum line_type
48 get_line_type_from_ref(const struct ref *ref)
50 if (ref->type == REFERENCE_HEAD)
51 return LINE_MAIN_HEAD;
52 else if (ref->type == REFERENCE_LOCAL_TAG)
53 return LINE_MAIN_LOCAL_TAG;
54 else if (ref->type == REFERENCE_TAG)
55 return LINE_MAIN_TAG;
56 else if (ref->type == REFERENCE_TRACKED_REMOTE)
57 return LINE_MAIN_TRACKED;
58 else if (ref->type == REFERENCE_REMOTE)
59 return LINE_MAIN_REMOTE;
60 else if (ref->type == REFERENCE_REPLACE)
61 return LINE_MAIN_REPLACE;
63 return LINE_MAIN_REF;
66 struct line_info *
67 get_line_info(const char *prefix, enum line_type type)
69 struct line_info *info;
70 struct line_rule *rule;
72 assert(type < line_rules);
73 rule = &line_rule[type];
74 for (info = &rule->info; info; info = info->next) {
75 if (prefix && info->prefix == prefix)
76 return info;
77 if (!prefix && !info->prefix)
78 return info;
81 return &rule->info;
84 static struct line_info *
85 init_line_info(const char *prefix, const char *name, size_t namelen, const char *line, size_t linelen)
87 struct line_rule *rule;
89 if (!realloc_line_rule(&line_rule, line_rules, 1))
90 die("Failed to allocate line info");
92 rule = &line_rule[line_rules++];
93 rule->name = name;
94 rule->namelen = namelen;
95 rule->line = line;
96 rule->linelen = linelen;
98 rule->info.prefix = prefix;
99 rule->info.fg = COLOR_DEFAULT;
100 rule->info.bg = COLOR_DEFAULT;
102 return &rule->info;
105 #define INIT_BUILTIN_LINE_INFO(type, line) \
106 init_line_info(NULL, #type, STRING_SIZE(#type), (line), STRING_SIZE(line))
108 static struct line_rule *
109 find_line_rule(struct line_rule *query)
111 enum line_type type;
113 if (!line_rules) {
114 LINE_INFO(INIT_BUILTIN_LINE_INFO);
117 for (type = 0; type < line_rules; type++) {
118 struct line_rule *rule = &line_rule[type];
120 if (query->namelen && enum_equals(*rule, query->name, query->namelen))
121 return rule;
123 if (query->linelen && query->linelen == rule->linelen &&
124 !strncasecmp(rule->line, query->line, rule->linelen))
125 return rule;
128 return NULL;
131 struct line_info *
132 add_line_rule(const char *prefix, struct line_rule *query)
134 struct line_rule *rule = find_line_rule(query);
135 struct line_info *info, *last;
137 if (!rule) {
138 if (query->name)
139 return NULL;
141 /* Quoted line. */
142 query->line = strndup(query->line, query->linelen);
143 if (!query->line)
144 return NULL;
145 return init_line_info(prefix, "", 0, query->line, query->linelen);
148 for (info = &rule->info; info; last = info, info = info->next)
149 if (info->prefix == prefix)
150 return info;
152 info = calloc(1, sizeof(*info));
153 if (info)
154 info->prefix = prefix;
155 last->next = info;
156 return info;
159 bool
160 foreach_line_rule(line_rule_visitor_fn visitor, void *data)
162 enum line_type type;
164 for (type = 0; type < line_rules; type++) {
165 struct line_rule *rule = &line_rule[type];
167 if (!visitor(data, rule))
168 return false;
171 return true;
174 static void
175 init_line_info_color_pair(struct line_info *info, enum line_type type,
176 int default_bg, int default_fg)
178 int bg = info->bg == COLOR_DEFAULT ? default_bg : info->bg;
179 int fg = info->fg == COLOR_DEFAULT ? default_fg : info->fg;
180 int i;
182 for (i = 0; i < color_pairs; i++) {
183 if (color_pair[i]->fg == info->fg && color_pair[i]->bg == info->bg) {
184 info->color_pair = i;
185 return;
189 if (!realloc_color_pair(&color_pair, color_pairs, 1))
190 die("Failed to alloc color pair");
192 color_pair[color_pairs] = info;
193 info->color_pair = color_pairs++;
194 init_pair(COLOR_ID(info->color_pair), fg, bg);
197 void
198 init_colors(void)
200 struct line_rule query = { "default", STRING_SIZE("default") };
201 struct line_rule *rule = find_line_rule(&query);
202 int default_bg = rule->info.bg;
203 int default_fg = rule->info.fg;
204 enum line_type type;
206 /* XXX: Even if the terminal does not support colors (e.g.
207 * TERM=dumb) init_colors() must ensure that the built-in rules
208 * have been initialized. This is done by the above call to
209 * find_line_rule(). */
210 if (!has_colors())
211 return;
213 start_color();
215 if (assume_default_colors(default_fg, default_bg) == ERR) {
216 default_bg = COLOR_BLACK;
217 default_fg = COLOR_WHITE;
220 for (type = 0; type < line_rules; type++) {
221 struct line_rule *rule = &line_rule[type];
222 struct line_info *info;
224 for (info = &rule->info; info; info = info->next) {
225 init_line_info_color_pair(info, type, default_bg, default_fg);
230 /* vim: set ts=8 sw=8 noexpandtab: */