Skip to content

Commit

Permalink
Support ANSI escape color codes in NINJA_STATUS
Browse files Browse the repository at this point in the history
Adds support for ANSI escape sequences used for colorization to the job
status indicator, and updates `ElideMiddle()` to account for the
non-obvious change in text width.

As an example, the following will now emit the job status in green:

   env NINJA_STATUS="\\033[32m[%f/%t] \\033[0m" ninja;

Invalid color escape codes are treated as plain text (as before). ANSI
escape sequences apart from `\033...m` are not supported.

Closes ninja-build#713. Closes ninja-build#912.
  • Loading branch information
mqudsi committed Jul 30, 2018
1 parent ca041d8 commit 75e818c
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
16 changes: 15 additions & 1 deletion src/build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,21 @@ string BuildStatus::FormatProgressStatus(
char buf[32];
int percent;
for (const char* s = progress_status_format; *s != '\0'; ++s) {
if (*s == '%') {
// Support ANSI color escape codes in NINJA_STATUS
if (strncmp(s, "\\033[", 5) == 0) {
const char *end = strchr(s + 5, 'm');
if (end == nullptr) {
// Not a valid ANSI color sequence, treat as regular text
} else {
out.append("\x1B[");
for (const char *t = s + 5; t <= end; ++t) {
out.push_back(*t);
}
s = end;
continue;
}
}
else if (*s == '%') {
++s;
switch (*s) {
case '%':
Expand Down
15 changes: 14 additions & 1 deletion src/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,23 @@ double GetLoadAverage() {
}
#endif // _WIN32

// Calculate the width of a string accounting for ANSI escape codes
size_t CalculateWidth(const string& str) {
const int initial_width = str.size();
size_t zero_width_start = str.find("\x1B[");
if (zero_width_start != string::npos) {
size_t zero_width_end = str.find("m", zero_width_start);
if (zero_width_end != string::npos) {
return initial_width - (zero_width_end - zero_width_start) - 1;
}
}
return initial_width;
}

string ElideMiddle(const string& str, size_t width) {
const int kMargin = 3; // Space for "...".
string result = str;
if (result.size() + kMargin > width) {
if (CalculateWidth(result) + kMargin > width) {
size_t elide_size = (width - kMargin) / 2;
result = result.substr(0, elide_size)
+ "..."
Expand Down

0 comments on commit 75e818c

Please sign in to comment.