[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / tools / gn / standard_out.cc
blob0c5b54f5fd288b30f9e0c065db368df2899f32e4
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_piece.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "build/build_config.h"
15 #include "tools/gn/switches.h"
17 #if defined(OS_WIN)
18 #include <windows.h>
19 #else
20 #include <stdio.h>
21 #include <unistd.h>
22 #endif
24 namespace {
26 bool initialized = false;
28 #if defined(OS_WIN)
29 HANDLE hstdout;
30 WORD default_attributes;
31 #endif
32 bool is_console = false;
34 bool is_markdown = false;
36 void EnsureInitialized() {
37 if (initialized)
38 return;
39 initialized = true;
41 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
42 if (cmdline->HasSwitch(switches::kMarkdown)) {
43 // Output help in Markdown's syntax, not color-highlighted.
44 is_markdown = true;
47 if (cmdline->HasSwitch(switches::kNoColor)) {
48 // Force color off.
49 is_console = false;
50 return;
53 #if defined(OS_WIN)
54 // On Windows, we can't force the color on. If the output handle isn't a
55 // console, there's nothing we can do about it.
56 hstdout = ::GetStdHandle(STD_OUTPUT_HANDLE);
57 CONSOLE_SCREEN_BUFFER_INFO info;
58 is_console = !!::GetConsoleScreenBufferInfo(hstdout, &info);
59 default_attributes = info.wAttributes;
60 #else
61 if (cmdline->HasSwitch(switches::kColor))
62 is_console = true;
63 else
64 is_console = isatty(fileno(stdout));
65 #endif
68 #if !defined(OS_WIN)
69 void WriteToStdOut(const std::string& output) {
70 size_t written_bytes = fwrite(output.data(), 1, output.size(), stdout);
71 DCHECK_EQ(output.size(), written_bytes);
73 #endif // !defined(OS_WIN)
75 void OutputMarkdownDec(TextDecoration dec) {
76 // The markdown rendering turns "dim" text to italics and any
77 // other colored text to bold.
79 #if defined(OS_WIN)
80 DWORD written = 0;
81 if (dec == DECORATION_DIM)
82 ::WriteFile(hstdout, "*", 1, &written, nullptr);
83 else if (dec != DECORATION_NONE)
84 ::WriteFile(hstdout, "**", 2, &written, nullptr);
85 #else
86 if (dec == DECORATION_DIM)
87 WriteToStdOut("*");
88 else if (dec != DECORATION_NONE)
89 WriteToStdOut("**");
90 #endif
93 } // namespace
95 #if defined(OS_WIN)
97 void OutputString(const std::string& output, TextDecoration dec) {
98 EnsureInitialized();
99 DWORD written = 0;
101 if (is_markdown) {
102 OutputMarkdownDec(dec);
103 } else if (is_console) {
104 switch (dec) {
105 case DECORATION_NONE:
106 break;
107 case DECORATION_DIM:
108 ::SetConsoleTextAttribute(hstdout, FOREGROUND_INTENSITY);
109 break;
110 case DECORATION_RED:
111 ::SetConsoleTextAttribute(hstdout,
112 FOREGROUND_RED | FOREGROUND_INTENSITY);
113 break;
114 case DECORATION_GREEN:
115 // Keep green non-bold.
116 ::SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN);
117 break;
118 case DECORATION_BLUE:
119 ::SetConsoleTextAttribute(hstdout,
120 FOREGROUND_BLUE | FOREGROUND_INTENSITY);
121 break;
122 case DECORATION_YELLOW:
123 ::SetConsoleTextAttribute(hstdout,
124 FOREGROUND_RED | FOREGROUND_GREEN);
125 break;
129 std::string tmpstr = output;
130 if (is_markdown && dec == DECORATION_YELLOW) {
131 // https://code.google.com/p/gitiles/issues/detail?id=77
132 // Gitiles will replace "--" with an em dash in non-code text.
133 // Figuring out all instances of this might be difficult, but we can
134 // at least escape the instances where this shows up in a heading.
135 base::ReplaceSubstringsAfterOffset(&tmpstr, 0, "--", "\\--");
137 ::WriteFile(hstdout, tmpstr.c_str(), static_cast<DWORD>(tmpstr.size()),
138 &written, nullptr);
140 if (is_markdown) {
141 OutputMarkdownDec(dec);
142 } else if (is_console) {
143 ::SetConsoleTextAttribute(hstdout, default_attributes);
147 #else
149 void OutputString(const std::string& output, TextDecoration dec) {
150 EnsureInitialized();
151 if (is_markdown) {
152 OutputMarkdownDec(dec);
153 } else if (is_console) {
154 switch (dec) {
155 case DECORATION_NONE:
156 break;
157 case DECORATION_DIM:
158 WriteToStdOut("\e[2m");
159 break;
160 case DECORATION_RED:
161 WriteToStdOut("\e[31m\e[1m");
162 break;
163 case DECORATION_GREEN:
164 WriteToStdOut("\e[32m");
165 break;
166 case DECORATION_BLUE:
167 WriteToStdOut("\e[34m\e[1m");
168 break;
169 case DECORATION_YELLOW:
170 WriteToStdOut("\e[33m\e[1m");
171 break;
175 std::string tmpstr = output;
176 if (is_markdown && dec == DECORATION_YELLOW) {
177 // https://code.google.com/p/gitiles/issues/detail?id=77
178 // Gitiles will replace "--" with an em dash in non-code text.
179 // Figuring out all instances of this might be difficult, but we can
180 // at least escape the instances where this shows up in a heading.
181 base::ReplaceSubstringsAfterOffset(&tmpstr, 0, "--", "\\--");
183 WriteToStdOut(tmpstr.data());
185 if (is_markdown) {
186 OutputMarkdownDec(dec);
187 } else if (is_console && dec != DECORATION_NONE) {
188 WriteToStdOut("\e[0m");
192 #endif
194 void PrintShortHelp(const std::string& line) {
195 EnsureInitialized();
197 size_t colon_offset = line.find(':');
198 size_t first_normal = 0;
199 if (colon_offset != std::string::npos) {
200 OutputString(" " + line.substr(0, colon_offset), DECORATION_YELLOW);
201 first_normal = colon_offset;
204 // See if the colon is followed by a " [" and if so, dim the contents of [ ].
205 if (first_normal > 0 &&
206 line.size() > first_normal + 2 &&
207 line[first_normal + 1] == ' ' && line[first_normal + 2] == '[') {
208 size_t begin_bracket = first_normal + 2;
209 OutputString(": ");
210 first_normal = line.find(']', begin_bracket);
211 if (first_normal == std::string::npos)
212 first_normal = line.size();
213 else
214 first_normal++;
215 OutputString(line.substr(begin_bracket, first_normal - begin_bracket),
216 DECORATION_DIM);
219 OutputString(line.substr(first_normal) + "\n");
222 void PrintLongHelp(const std::string& text) {
223 EnsureInitialized();
225 bool first_header = true;
226 bool in_body = false;
227 for (const std::string& line : base::SplitString(
228 text, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
229 // Check for a heading line.
230 if (!line.empty() && line[0] != ' ') {
231 if (is_markdown) {
232 // GN's block-level formatting is converted to markdown as follows:
233 // * The first heading is treated as an H2.
234 // * Subsequent heading are treated as H3s.
235 // * Any other text is wrapped in a code block and displayed as-is.
237 // Span-level formatting (the decorations) is converted inside
238 // OutputString().
239 if (in_body) {
240 OutputString("```\n\n", DECORATION_NONE);
241 in_body = false;
244 if (first_header) {
245 OutputString("## ", DECORATION_NONE);
246 first_header = false;
247 } else {
248 OutputString("### ", DECORATION_NONE);
252 // Highlight up to the colon (if any).
253 size_t chars_to_highlight = line.find(':');
254 if (chars_to_highlight == std::string::npos)
255 chars_to_highlight = line.size();
257 OutputString(line.substr(0, chars_to_highlight), DECORATION_YELLOW);
258 OutputString(line.substr(chars_to_highlight) + "\n");
259 continue;
260 } else if (is_markdown && !line.empty() && !in_body) {
261 OutputString("```\n", DECORATION_NONE);
262 in_body = true;
265 // Check for a comment.
266 TextDecoration dec = DECORATION_NONE;
267 for (const auto& elem : line) {
268 if (elem == '#' && !is_markdown) {
269 // Got a comment, draw dimmed.
270 dec = DECORATION_DIM;
271 break;
272 } else if (elem != ' ') {
273 break;
277 OutputString(line + "\n", dec);
280 if (is_markdown && in_body)
281 OutputString("\n```\n");