Add ICU message format support
[chromium-blink-merge.git] / tools / gn / standard_out.cc
bloba059e17e91af82b584bab775aa79c51e3236ef23
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.
5 #include "tools/gn/standard_out.h"
7 #include <vector>
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/strings/string_split.h"
12 #include "build/build_config.h"
13 #include "tools/gn/switches.h"
15 #if defined(OS_WIN)
16 #include <windows.h>
17 #else
18 #include <stdio.h>
19 #include <unistd.h>
20 #endif
22 namespace {
24 bool initialized = false;
26 #if defined(OS_WIN)
27 HANDLE hstdout;
28 WORD default_attributes;
29 #endif
30 bool is_console = false;
32 bool is_markdown = false;
34 void EnsureInitialized() {
35 if (initialized)
36 return;
37 initialized = true;
39 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
40 if (cmdline->HasSwitch(switches::kMarkdown)) {
41 // Output help in Markdown's syntax, not color-highlighted.
42 is_markdown = true;
45 if (cmdline->HasSwitch(switches::kNoColor)) {
46 // Force color off.
47 is_console = false;
48 return;
51 #if defined(OS_WIN)
52 // On Windows, we can't force the color on. If the output handle isn't a
53 // console, there's nothing we can do about it.
54 hstdout = ::GetStdHandle(STD_OUTPUT_HANDLE);
55 CONSOLE_SCREEN_BUFFER_INFO info;
56 is_console = !!::GetConsoleScreenBufferInfo(hstdout, &info);
57 default_attributes = info.wAttributes;
58 #else
59 if (cmdline->HasSwitch(switches::kColor))
60 is_console = true;
61 else
62 is_console = isatty(fileno(stdout));
63 #endif
66 void WriteToStdOut(const std::string& output) {
67 size_t written_bytes = fwrite(output.data(), 1, output.size(), stdout);
68 DCHECK_EQ(output.size(), written_bytes);
71 void OutputMarkdownDec(TextDecoration dec) {
72 // The markdown rendering turns "dim" text to italics and any
73 // other colored text to bold.
75 #if defined(OS_WIN)
76 DWORD written = 0;
77 if (dec == DECORATION_DIM)
78 ::WriteFile(hstdout, "*", 1, &written, nullptr);
79 else if (dec != DECORATION_NONE)
80 ::WriteFile(hstdout, "**", 2, &written, nullptr);
81 #else
82 if (dec == DECORATION_DIM)
83 WriteToStdOut("*");
84 else if (dec != DECORATION_NONE)
85 WriteToStdOut("**");
86 #endif
89 } // namespace
91 #if defined(OS_WIN)
93 void OutputString(const std::string& output, TextDecoration dec) {
94 EnsureInitialized();
95 DWORD written = 0;
97 if (is_markdown) {
98 OutputMarkdownDec(dec);
99 } else if (is_console) {
100 switch (dec) {
101 case DECORATION_NONE:
102 break;
103 case DECORATION_DIM:
104 ::SetConsoleTextAttribute(hstdout, FOREGROUND_INTENSITY);
105 break;
106 case DECORATION_RED:
107 ::SetConsoleTextAttribute(hstdout,
108 FOREGROUND_RED | FOREGROUND_INTENSITY);
109 break;
110 case DECORATION_GREEN:
111 // Keep green non-bold.
112 ::SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN);
113 break;
114 case DECORATION_BLUE:
115 ::SetConsoleTextAttribute(hstdout,
116 FOREGROUND_BLUE | FOREGROUND_INTENSITY);
117 break;
118 case DECORATION_YELLOW:
119 ::SetConsoleTextAttribute(hstdout,
120 FOREGROUND_RED | FOREGROUND_GREEN);
121 break;
125 ::WriteFile(hstdout, output.c_str(), static_cast<DWORD>(output.size()),
126 &written, nullptr);
128 if (is_markdown) {
129 OutputMarkdownDec(dec);
130 } else if (is_console) {
131 ::SetConsoleTextAttribute(hstdout, default_attributes);
135 #else
137 void OutputString(const std::string& output, TextDecoration dec) {
138 EnsureInitialized();
139 if (is_markdown) {
140 OutputMarkdownDec(dec);
141 } else if (is_console) {
142 switch (dec) {
143 case DECORATION_NONE:
144 break;
145 case DECORATION_DIM:
146 WriteToStdOut("\e[2m");
147 break;
148 case DECORATION_RED:
149 WriteToStdOut("\e[31m\e[1m");
150 break;
151 case DECORATION_GREEN:
152 WriteToStdOut("\e[32m");
153 break;
154 case DECORATION_BLUE:
155 WriteToStdOut("\e[34m\e[1m");
156 break;
157 case DECORATION_YELLOW:
158 WriteToStdOut("\e[33m\e[1m");
159 break;
163 WriteToStdOut(output.data());
165 if (is_markdown) {
166 OutputMarkdownDec(dec);
167 } else if (is_console && dec != DECORATION_NONE) {
168 WriteToStdOut("\e[0m");
172 #endif
174 void PrintShortHelp(const std::string& line) {
175 EnsureInitialized();
177 size_t colon_offset = line.find(':');
178 size_t first_normal = 0;
179 if (colon_offset != std::string::npos) {
180 OutputString(" " + line.substr(0, colon_offset), DECORATION_YELLOW);
181 first_normal = colon_offset;
184 // See if the colon is followed by a " [" and if so, dim the contents of [ ].
185 if (first_normal > 0 &&
186 line.size() > first_normal + 2 &&
187 line[first_normal + 1] == ' ' && line[first_normal + 2] == '[') {
188 size_t begin_bracket = first_normal + 2;
189 OutputString(": ");
190 first_normal = line.find(']', begin_bracket);
191 if (first_normal == std::string::npos)
192 first_normal = line.size();
193 else
194 first_normal++;
195 OutputString(line.substr(begin_bracket, first_normal - begin_bracket),
196 DECORATION_DIM);
199 OutputString(line.substr(first_normal) + "\n");
202 void PrintLongHelp(const std::string& text) {
203 EnsureInitialized();
205 std::vector<std::string> lines;
206 base::SplitStringDontTrim(text, '\n', &lines);
208 bool first_header = true;
209 bool in_body = false;
210 for (const auto& line : lines) {
211 // Check for a heading line.
212 if (!line.empty() && line[0] != ' ') {
213 if (is_markdown) {
214 // GN's block-level formatting is converted to markdown as follows:
215 // * The first heading is treated as an H2.
216 // * Subsequent heading are treated as H3s.
217 // * Any other text is wrapped in a code block and displayed as-is.
219 // Span-level formatting (the decorations) is converted inside
220 // OutputString().
221 if (in_body) {
222 OutputString("```\n\n", DECORATION_NONE);
223 in_body = false;
226 if (first_header) {
227 OutputString("## ", DECORATION_NONE);
228 first_header = false;
229 } else {
230 OutputString("### ", DECORATION_NONE);
234 // Highlight up to the colon (if any).
235 size_t chars_to_highlight = line.find(':');
236 if (chars_to_highlight == std::string::npos)
237 chars_to_highlight = line.size();
239 OutputString(line.substr(0, chars_to_highlight), DECORATION_YELLOW);
240 OutputString(line.substr(chars_to_highlight) + "\n");
241 continue;
242 } else if (is_markdown && !line.empty() && !in_body) {
243 OutputString("```\n", DECORATION_NONE);
244 in_body = true;
247 // Check for a comment.
248 TextDecoration dec = DECORATION_NONE;
249 for (const auto& elem : line) {
250 if (elem == '#' && !is_markdown) {
251 // Got a comment, draw dimmed.
252 dec = DECORATION_DIM;
253 break;
254 } else if (elem != ' ') {
255 break;
259 OutputString(line + "\n", dec);
262 if (is_markdown && in_body)
263 OutputString("\n```\n");