Skip to content

Commit 08030ae

Browse files
committed
color: Delay the case_sensitive decision
1 parent 4bc7914 commit 08030ae

3 files changed

Lines changed: 112 additions & 90 deletions

File tree

src/color.c

Lines changed: 84 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -214,57 +214,26 @@ static void ext_tolower(char *ext, size_t len) {
214214
}
215215
}
216216

217-
/**
218-
* The "smart case" algorithm.
219-
*
220-
* @param ext
221-
* The current extension being added.
222-
* @param prev
223-
* The previous case-sensitive match, if any, for the same extension.
224-
* @param iprev
225-
* The previous case-insensitive match, if any, for the same extension.
226-
* @return
227-
* Whether this extension should become case-sensitive.
228-
*/
229-
static bool ext_case_sensitive(struct ext_color *ext, struct ext_color *prev, struct ext_color *iprev) {
230-
// This is the first case-insensitive occurrence of this extension, e.g.
231-
//
232-
// *.gz=01;31:*.tar.gz=01;33
233-
if (!iprev) {
234-
bfs_assert(!prev);
235-
return false;
236-
}
237-
238-
// If the last version of this extension is already case-sensitive,
239-
// this one should be too, e.g.
240-
//
241-
// *.tar.gz=01;31:*.TAR.GZ=01;32:*.TAR.GZ=01;33
242-
if (iprev->case_sensitive) {
243-
return true;
244-
}
245-
246-
// The case matches the last occurrence exactly, e.g.
247-
//
248-
// *.tar.gz=01;31:*.tar.gz=01;33
249-
if (iprev == prev) {
250-
return false;
217+
/** Insert an extension into a trie. */
218+
static int insert_ext(struct trie *trie, struct ext_color *ext) {
219+
// A later *.x should override any earlier *.x, *.y.x, etc.
220+
struct trie_leaf *leaf;
221+
while ((leaf = trie_find_postfix(trie, ext->ext))) {
222+
trie_remove(trie, leaf);
251223
}
252224

253-
// Different case, but same value, e.g.
254-
//
255-
// *.tar.gz=01;31:*.TAR.GZ=01;31
256-
if (esc_eq(iprev->esc, ext->esc->seq, ext->esc->len)) {
257-
return false;
225+
size_t len = ext->len + 1;
226+
leaf = trie_insert_mem(trie, ext->ext, len);
227+
if (!leaf) {
228+
return -1;
258229
}
259230

260-
// Different case, different value, e.g.
261-
//
262-
// *.tar.gz=01;31:*.TAR.GZ=01;33
263-
return true;
231+
leaf->value = ext;
232+
return 0;
264233
}
265234

266235
/** Set the color for an extension. */
267-
static int set_ext(struct colors *colors, char *key, char *value) {
236+
static int set_ext(struct colors *colors, dchar *key, dchar *value) {
268237
size_t len = dstrlen(key);
269238
struct ext_color *ext = varena_alloc(&colors->ext_arena, len + 1);
270239
if (!ext) {
@@ -279,45 +248,19 @@ static int set_ext(struct colors *colors, char *key, char *value) {
279248
goto fail;
280249
}
281250

282-
key = memcpy(ext->ext, key, len + 1);
251+
memcpy(ext->ext, key, len + 1);
283252

284253
// Reverse the extension (`*.y.x` -> `x.y.*`) so we can use trie_find_prefix()
285-
ext_reverse(key, len);
286-
287-
// Find any pre-existing exact match
288-
struct ext_color *prev = NULL;
289-
struct trie_leaf *leaf = trie_find_str(&colors->ext_trie, key);
290-
if (leaf) {
291-
prev = leaf->value;
292-
trie_remove(&colors->ext_trie, leaf);
293-
}
294-
295-
// A later *.x should override any earlier *.x, *.y.x, etc.
296-
while ((leaf = trie_find_postfix(&colors->ext_trie, key))) {
297-
trie_remove(&colors->ext_trie, leaf);
298-
}
254+
ext_reverse(ext->ext, len);
299255

300256
// Insert the extension into the case-sensitive trie
301-
leaf = trie_insert_str(&colors->ext_trie, key);
302-
if (!leaf) {
303-
goto fail;
304-
}
305-
leaf->value = ext;
306-
307-
// "Smart case": if the same extension is given with two different
308-
// capitalizations (e.g. `*.y.x=31:*.Y.Z=32:`), make it case-sensitive
309-
ext_tolower(key, len);
310-
leaf = trie_insert_str(&colors->iext_trie, key);
311-
if (!leaf) {
257+
if (insert_ext(&colors->ext_trie, ext) != 0) {
312258
goto fail;
313259
}
314260

315-
struct ext_color *iprev = leaf->value;
316-
if (ext_case_sensitive(ext, prev, iprev)) {
317-
iprev->case_sensitive = true;
318-
ext->case_sensitive = true;
261+
if (colors->ext_len < len) {
262+
colors->ext_len = len;
319263
}
320-
leaf->value = ext;
321264

322265
return 0;
323266

@@ -329,32 +272,83 @@ static int set_ext(struct colors *colors, char *key, char *value) {
329272
return -1;
330273
}
331274

332-
/** Rebuild the case-insensitive trie after all extensions have been parsed. */
333-
static int build_iext_trie(struct colors *colors) {
334-
trie_clear(&colors->iext_trie);
275+
/**
276+
* The "smart case" algorithm.
277+
*
278+
* @param ext
279+
* The current extension being added.
280+
* @param iext
281+
* The previous case-insensitive match, if any, for the same extension.
282+
* @return
283+
* Whether this extension should become case-sensitive.
284+
*/
285+
static bool ext_case_sensitive(struct ext_color *ext, struct ext_color *iext) {
286+
// This is the first case-insensitive occurrence of this extension, e.g.
287+
//
288+
// *.gz=01;31:*.tar.gz=01;33
289+
if (!iext) {
290+
return false;
291+
}
335292

293+
// If the last version of this extension is already case-sensitive,
294+
// this one should be too, e.g.
295+
//
296+
// *.tar.gz=01;31:*.TAR.GZ=01;32:*.TAR.GZ=01;33
297+
if (iext->case_sensitive) {
298+
return true;
299+
}
300+
301+
// Different case, but same value, e.g.
302+
//
303+
// *.tar.gz=01;31:*.TAR.GZ=01;31
304+
if (esc_eq(iext->esc, ext->esc->seq, ext->esc->len)) {
305+
return false;
306+
}
307+
308+
// Different case, different value, e.g.
309+
//
310+
// *.tar.gz=01;31:*.TAR.GZ=01;33
311+
return true;
312+
}
313+
314+
/** Build the case-insensitive trie, after all extensions have been parsed. */
315+
static int build_iext_trie(struct colors *colors) {
316+
// Find which extensions should be case-sensitive
336317
for_trie (leaf, &colors->ext_trie) {
337-
size_t len = leaf->length - 1;
338-
if (colors->ext_len < len) {
339-
colors->ext_len = len;
318+
struct ext_color *ext = leaf->value;
319+
320+
// "Smart case": if the same extension is given with two different
321+
// capitalizations (e.g. `*.y.x=31:*.Y.Z=32:`), make it case-sensitive
322+
ext_tolower(ext->ext, ext->len);
323+
324+
size_t len = ext->len + 1;
325+
struct trie_leaf *ileaf = trie_insert_mem(&colors->iext_trie, ext->ext, len);
326+
if (!ileaf) {
327+
return -1;
340328
}
341329

330+
struct ext_color *iext = ileaf->value;
331+
if (ext_case_sensitive(ext, iext)) {
332+
ext->case_sensitive = true;
333+
iext->case_sensitive = true;
334+
}
335+
336+
ileaf->value = ext;
337+
}
338+
339+
// Rebuild the trie with only the case-insensitive ones
340+
trie_clear(&colors->iext_trie);
341+
342+
for_trie (leaf, &colors->ext_trie) {
342343
struct ext_color *ext = leaf->value;
343344
if (ext->case_sensitive) {
344345
continue;
345346
}
346347

347-
// set_ext() already reversed and lowercased the extension
348-
struct trie_leaf *ileaf;
349-
while ((ileaf = trie_find_postfix(&colors->iext_trie, ext->ext))) {
350-
trie_remove(&colors->iext_trie, ileaf);
351-
}
352-
353-
ileaf = trie_insert_str(&colors->iext_trie, ext->ext);
354-
if (!ileaf) {
348+
// We already lowercased the extension above
349+
if (insert_ext(&colors->iext_trie, ext) != 0) {
355350
return -1;
356351
}
357-
ileaf->value = ext;
358352
}
359353

360354
return 0;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
$'rainbow/\e[1m'
2+
$'rainbow/\e[1m/'$'\e[0m'
3+
rainbow
4+
rainbow/exec.sh
5+
rainbow/lower.tar.gz
6+
rainbow/lu.tar.GZ
7+
rainbow/ul.TAR.gz
8+
rainbow/upper.TAR.GZ
9+
rainbow/socket
10+
rainbow/broken
11+
rainbow/chardev_link
12+
rainbow/link.txt
13+
rainbow/sticky_ow
14+
rainbow/sgid
15+
rainbow/pipe
16+
rainbow/ow
17+
rainbow/sugid
18+
rainbow/suid
19+
rainbow/sticky
20+
rainbow/file.dat
21+
rainbow/file.txt
22+
rainbow/lower.gz
23+
rainbow/lower.tar
24+
rainbow/mh1
25+
rainbow/mh2
26+
rainbow/upper.GZ
27+
rainbow/upper.TAR
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
LS_COLORS="*.tar.gz=01;31:*.TAR.GZ=01;32:*.TAR.GZ=01;33:*.tar.gz=01;33:" bfs_diff rainbow -color

0 commit comments

Comments
 (0)