// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "tools/gn/standard_out.h" #include <vector> #include "base/command_line.h" #include "base/logging.h" #include "base/strings/string_split.h" #include "build/build_config.h" #if defined(OS_WIN) #include <windows.h> #else #include <stdio.h> #include <unistd.h> #endif namespace { bool initialized = false; static const char kSwitchColor[] = "color"; static const char kSwitchNoColor[] = "nocolor"; #if defined(OS_WIN) HANDLE hstdout; WORD default_attributes; #endif bool is_console = false; void EnsureInitialized() { if (initialized) return; initialized = true; const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); if (cmdline->HasSwitch(kSwitchNoColor)) { // Force color off. is_console = false; return; } #if defined(OS_WIN) // On Windows, we can't force the color on. If the output handle isn't a // console, there's nothing we can do about it. hstdout = ::GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO info; is_console = !!::GetConsoleScreenBufferInfo(hstdout, &info); default_attributes = info.wAttributes; #else if (cmdline->HasSwitch(kSwitchColor)) is_console = true; else is_console = isatty(fileno(stdout)); #endif } void WriteToStdOut(const std::string& output) { size_t written_bytes = fwrite(output.data(), 1, output.size(), stdout); DCHECK_EQ(output.size(), written_bytes); } } // namespace #if defined(OS_WIN) void OutputString(const std::string& output, TextDecoration dec) { EnsureInitialized(); if (is_console) { switch (dec) { case DECORATION_NONE: break; case DECORATION_DIM: ::SetConsoleTextAttribute(hstdout, FOREGROUND_INTENSITY); break; case DECORATION_RED: ::SetConsoleTextAttribute(hstdout, FOREGROUND_RED | FOREGROUND_INTENSITY); break; case DECORATION_GREEN: // Keep green non-bold. ::SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN); break; case DECORATION_BLUE: ::SetConsoleTextAttribute(hstdout, FOREGROUND_BLUE | FOREGROUND_INTENSITY); break; case DECORATION_YELLOW: ::SetConsoleTextAttribute(hstdout, FOREGROUND_RED | FOREGROUND_GREEN); break; } } DWORD written = 0; ::WriteFile(hstdout, output.c_str(), static_cast<DWORD>(output.size()), &written, NULL); if (is_console) ::SetConsoleTextAttribute(hstdout, default_attributes); } #else void OutputString(const std::string& output, TextDecoration dec) { EnsureInitialized(); if (is_console) { switch (dec) { case DECORATION_NONE: break; case DECORATION_DIM: WriteToStdOut("\e[2m"); break; case DECORATION_RED: WriteToStdOut("\e[31m\e[1m"); break; case DECORATION_GREEN: WriteToStdOut("\e[32m"); break; case DECORATION_BLUE: WriteToStdOut("\e[34m\e[1m"); break; case DECORATION_YELLOW: WriteToStdOut("\e[33m\e[1m"); break; } } WriteToStdOut(output.data()); if (is_console && dec != DECORATION_NONE) WriteToStdOut("\e[0m"); } #endif void PrintShortHelp(const std::string& line) { size_t colon_offset = line.find(':'); size_t first_normal = 0; if (colon_offset != std::string::npos) { OutputString(" " + line.substr(0, colon_offset), DECORATION_YELLOW); first_normal = colon_offset; } // See if the colon is followed by a " [" and if so, dim the contents of [ ]. if (first_normal > 0 && line.size() > first_normal + 2 && line[first_normal + 1] == ' ' && line[first_normal + 2] == '[') { size_t begin_bracket = first_normal + 2; OutputString(": "); first_normal = line.find(']', begin_bracket); if (first_normal == std::string::npos) first_normal = line.size(); else first_normal++; OutputString(line.substr(begin_bracket, first_normal - begin_bracket), DECORATION_DIM); } OutputString(line.substr(first_normal) + "\n"); } void PrintLongHelp(const std::string& text) { std::vector<std::string> lines; base::SplitStringDontTrim(text, '\n', &lines); for (size_t i = 0; i < lines.size(); i++) { const std::string& line = lines[i]; // Check for a heading line. if (!line.empty() && line[0] != ' ') { // Highlight up to the colon (if any). size_t chars_to_highlight = line.find(':'); if (chars_to_highlight == std::string::npos) chars_to_highlight = line.size(); OutputString(line.substr(0, chars_to_highlight), DECORATION_YELLOW); OutputString(line.substr(chars_to_highlight) + "\n"); continue; } // Check for a comment. TextDecoration dec = DECORATION_NONE; for (size_t char_i = 0; char_i < line.size(); char_i++) { if (line[char_i] == '#') { // Got a comment, draw dimmed. dec = DECORATION_DIM; break; } else if (line[char_i] != ' ') { break; } } OutputString(line + "\n", dec); } }