Page MenuHomeFreeBSD

diff(1): Add --color support
ClosedPublic

Authored by me_cameronkatri.com on May 29 2021, 5:16 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, Jun 25, 3:51 AM
Unknown Object (File)
Fri, Jun 21, 3:59 AM
Unknown Object (File)
Thu, Jun 20, 7:18 PM
Unknown Object (File)
Wed, Jun 12, 5:50 PM
Unknown Object (File)
May 29 2024, 5:18 AM
Unknown Object (File)
May 7 2024, 12:49 PM
Unknown Object (File)
May 7 2024, 12:29 PM
Unknown Object (File)
May 7 2024, 12:29 PM

Details

Summary

Adds a --color flag to diff(1) that supports the same options as GNU's diff(1). The colors are customizable with the env var DIFFCOLORS in a format similar to grep(1)'s GREPCOLORS. An example would be 04;36:41 for additions to be underlined light blue, and deletions have a red background.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Respect CLICOLOR and COLORTERM variables.

Remove leftover printf from testing.

I want to test this soon, but for now I'll just make a style-related note.

usr.bin/diff/diffreg.c
1153

This binary operator and the few below will need spaces around it.

Add spaces around binary operators.
Test color using operator.

Apart from inline comments I would like to ask you to consider adding at least one test case.

usr.bin/diff/diff.c
40–41

I would move these to diff.h.
In any case they should be defined to distinct values.

45

They are all initialized to 0 anyway.

648

What is the intention of this part? Would it be possible to avoid the strdup? This is not a hard requirement but maybe there's a more elegant way to do this.

usr.bin/diff/diffreg.c
1163

Purely for stylistic reasons I would rewrite this as \033[m

usr.bin/diff/diff.c
648

getenv(3) says:

The application should not modify the string pointed to by the getenv() function.

So I'm copying it, because strsep(3) modifies the string passed to it.

usr.bin/diff/diff.c
647

This is unimportant so feel free to ignore, but I would parse both substrings with strtonum() and handle possible errors. Then store that as char in del_code and add_code. That change would of course require the printfs to use %c instead of %s.

usr.bin/diff/diff.h
96

I asked about this before so maybe I'm wrong and they need to be defined as the same value? If so, why?

usr.bin/diff/diff.c
647

Ah, I assumed the format is as simple as "A:B" where A and B are unsigned integers, but that's not (always) the case.

Fix COLORFLAG_* values.
Fix init_code() to return proper value.

usr.bin/diff/diff.h
96

Whoops, that's a mistake, they should all be different.

usr.bin/diff/diff.1
343

DIFFCOLOR or DIFFCOLORS?

usr.bin/diff/diff.1
343

The format should be explained here if only shortly. I'd also make it clear that it's ok not to set it and in that case the colors will be set to default red and green.

Describe DIFFCOLORS in the manpage.

jrtc27 added inline comments.
usr.bin/diff/diff.1
341

Should this not be .It Fl -color= for consistency? Also style for this manpage seems to be to not include the =.

usr.bin/diff/diff.c
627

This case is only actually use for COLORFLAG_UNSET, right? Would be clearer to have this as a case below rather than almost always override the variable and make it look like dead code. Especially if you reorder the cases below you can have this and the COLORFLAG_AUTO case share the isatty call and make it clearer when things are equivalent.

628

Doesn't isatty already always return either 1 or 0?

637

return (ret) is the correct style (issue repeated throughout)

And I'm leaning towards never being the default here, like in ls(1).

Fix return styling.
Default to never
auto only applies when COLORTERM or CLICOLOR is set (the same as ls(1)).

me_cameronkatri.com added inline comments.
usr.bin/diff/diff.1
341

Optional arguments don't support arguments without a =, so removing it from the manpage wouldn't make sense.

usr.bin/diff/diff.c
336–340

I would do it like this:

	if (do_color()) {
		char *p;
		char const *env;

		color = 1;
		add_code = "32";
		del_code = "31";
		env = getenv("DIFFCOLORS");
		if (env != NULL && *env != '\0' && (p = strdup(env))) {
			add_code = p;
			strsep(&p, ":");
			if (p != NULL)
				del_code = p;
		}
	}

and abandon init_code(). The function is not easy to write in a way that doesn't leak memory.

599

When I commit this, I really want to do return (0) and return (1) where appropriate, instead of returning this pascal-style variable ret.

me_cameronkatri.com marked an inline comment as done.

Remove init_code()
Don't use ret variable.

This revision is now accepted and ready to land.Sep 4 2021, 8:26 PM

I made some stylistic changes and rebased this patch on top of it. I also modified it to clear color (especially background color) before newlines.
Are you OK with me committing your change like this?

I made some stylistic changes and rebased this patch on top of it. I also modified it to clear color (especially background color) before newlines.
Are you OK with me committing your change like this?

Yep.

This revision was automatically updated to reflect the committed changes.