Home | History | Annotate | Download | only in gn
      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