1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "tools/gn/standard_out.h" 6 7 #include <vector> 8 9 #include "base/logging.h" 10 #include "base/strings/string_split.h" 11 #include "build/build_config.h" 12 13 #if defined(OS_WIN) 14 #include <windows.h> 15 #else 16 #include <stdio.h> 17 #include <unistd.h> 18 #endif 19 20 namespace { 21 22 bool initialized = false; 23 24 #if defined(OS_WIN) 25 HANDLE hstdout; 26 WORD default_attributes; 27 #endif 28 bool is_console = false; 29 30 void EnsureInitialized() { 31 if (initialized) 32 return; 33 initialized = true; 34 35 #if defined(OS_WIN) 36 hstdout = ::GetStdHandle(STD_OUTPUT_HANDLE); 37 CONSOLE_SCREEN_BUFFER_INFO info; 38 is_console = !!::GetConsoleScreenBufferInfo(hstdout, &info); 39 default_attributes = info.wAttributes; 40 #else 41 is_console = isatty(fileno(stdout)); 42 #endif 43 } 44 45 void WriteToStdOut(const std::string& output) { 46 size_t written_bytes = fwrite(output.data(), 1, output.size(), stdout); 47 DCHECK_EQ(output.size(), written_bytes); 48 } 49 50 } // namespace 51 52 #if defined(OS_WIN) 53 54 void OutputString(const std::string& output, TextDecoration dec) { 55 EnsureInitialized(); 56 if (is_console) { 57 switch (dec) { 58 case DECORATION_NONE: 59 break; 60 case DECORATION_DIM: 61 ::SetConsoleTextAttribute(hstdout, FOREGROUND_INTENSITY); 62 break; 63 case DECORATION_RED: 64 ::SetConsoleTextAttribute(hstdout, 65 FOREGROUND_RED | FOREGROUND_INTENSITY); 66 break; 67 case DECORATION_GREEN: 68 // Keep green non-bold. 69 ::SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN); 70 break; 71 case DECORATION_BLUE: 72 ::SetConsoleTextAttribute(hstdout, 73 FOREGROUND_BLUE | FOREGROUND_INTENSITY); 74 break; 75 case DECORATION_YELLOW: 76 ::SetConsoleTextAttribute(hstdout, 77 FOREGROUND_RED | FOREGROUND_GREEN); 78 break; 79 } 80 } 81 82 DWORD written = 0; 83 ::WriteFile(hstdout, output.c_str(), static_cast<DWORD>(output.size()), 84 &written, NULL); 85 86 if (is_console) 87 ::SetConsoleTextAttribute(hstdout, default_attributes); 88 } 89 90 #else 91 92 void OutputString(const std::string& output, TextDecoration dec) { 93 EnsureInitialized(); 94 if (is_console) { 95 switch (dec) { 96 case DECORATION_NONE: 97 break; 98 case DECORATION_DIM: 99 WriteToStdOut("\e[2m"); 100 break; 101 case DECORATION_RED: 102 WriteToStdOut("\e[31m\e[1m"); 103 break; 104 case DECORATION_GREEN: 105 WriteToStdOut("\e[32m"); 106 break; 107 case DECORATION_BLUE: 108 WriteToStdOut("\e[34m\e[1m"); 109 break; 110 case DECORATION_YELLOW: 111 WriteToStdOut("\e[33m\e[1m"); 112 break; 113 } 114 } 115 116 WriteToStdOut(output.data()); 117 118 if (dec != DECORATION_NONE) 119 WriteToStdOut("\e[0m"); 120 } 121 122 #endif 123 124 void PrintShortHelp(const std::string& line) { 125 size_t colon_offset = line.find(':'); 126 size_t first_normal = 0; 127 if (colon_offset != std::string::npos) { 128 OutputString(" " + line.substr(0, colon_offset), DECORATION_YELLOW); 129 first_normal = colon_offset; 130 } 131 132 // See if the colon is followed by a " [" and if so, dim the contents of [ ]. 133 if (first_normal > 0 && 134 line.size() > first_normal + 2 && 135 line[first_normal + 1] == ' ' && line[first_normal + 2] == '[') { 136 size_t begin_bracket = first_normal + 2; 137 OutputString(": "); 138 first_normal = line.find(']', begin_bracket); 139 if (first_normal == std::string::npos) 140 first_normal = line.size(); 141 else 142 first_normal++; 143 OutputString(line.substr(begin_bracket, first_normal - begin_bracket), 144 DECORATION_DIM); 145 } 146 147 OutputString(line.substr(first_normal) + "\n"); 148 } 149 150 void PrintLongHelp(const std::string& text) { 151 std::vector<std::string> lines; 152 base::SplitStringDontTrim(text, '\n', &lines); 153 154 for (size_t i = 0; i < lines.size(); i++) { 155 const std::string& line = lines[i]; 156 157 // Check for a heading line. 158 if (!line.empty() && line[0] != ' ') { 159 // Highlight up to the colon (if any). 160 size_t chars_to_highlight = line.find(':'); 161 if (chars_to_highlight == std::string::npos) 162 chars_to_highlight = line.size(); 163 OutputString(line.substr(0, chars_to_highlight), DECORATION_YELLOW); 164 OutputString(line.substr(chars_to_highlight) + "\n"); 165 continue; 166 } 167 168 // Check for a comment. 169 TextDecoration dec = DECORATION_NONE; 170 for (size_t char_i = 0; char_i < line.size(); char_i++) { 171 if (line[char_i] == '#') { 172 // Got a comment, draw dimmed. 173 dec = DECORATION_DIM; 174 break; 175 } else if (line[char_i] != ' ') { 176 break; 177 } 178 } 179 180 OutputString(line + "\n", dec); 181 } 182 } 183 184