Escape < and > in non-code markdown output.
Bug: gn:8
Change-Id: I0689922ffc7677913d0afb64c6c15c476c04f358
Reviewed-on: https://gn-review.googlesource.com/2703
Commit-Queue: Brett Wilson <brettw@chromium.org>
Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/docs/reference.md b/docs/reference.md
index cb9632b..d73a94f 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -150,7 +150,7 @@
## <a name="commands"></a>Commands
-### <a name="analyze"></a>**gn analyze <out_dir> <input_path> <output_path>**
+### <a name="analyze"></a>**gn analyze <out_dir> <input_path> <output_path>**
```
Analyze which targets are affected by a list of files.
@@ -220,7 +220,7 @@
tries really hard to always write something to the output JSON and convey
errors that way rather than via return codes.
```
-### <a name="args"></a>**gn args <out_dir> [\--list] [\--short] [\--args] [\--overrides-only]**
+### <a name="args"></a>**gn args <out_dir> [\--list] [\--short] [\--args] [\--overrides-only]**
```
See also "gn help buildargs" for a more high-level overview of how
@@ -305,7 +305,7 @@
given arguments set (which may affect the values of other
arguments).
```
-### <a name="check"></a>**gn check <out_dir> [<label_pattern>] [\--force]**
+### <a name="check"></a>**gn check <out_dir> [<label_pattern>] [\--force]**
```
GN's include header checker validates that the includes for C-like source
@@ -420,13 +420,13 @@
gn check out/Default "//foo/*
Check only the files in targets in the //foo directory tree.
```
-### <a name="clean"></a>**gn clean <out_dir>**
+### <a name="clean"></a>**gn clean <out_dir>**
```
Deletes the contents of the output directory except for args.gn and
creates a Ninja build environment sufficient to regenerate the build.
```
-### <a name="desc"></a>**gn desc <out_dir> <label or pattern> [<what to show>] [\--blame] "**
+### <a name="desc"></a>**gn desc <out_dir> <label or pattern> [<what to show>] [\--blame] "**
#### **[\--format=json]**
```
@@ -438,7 +438,7 @@
targets.
```
-#### **Possibilities for <what to show>**
+#### **Possibilities for <what to show>**
```
(If unspecified an overall summary will be displayed.)
@@ -585,7 +585,7 @@
Shows defines set for the //base:base target, annotated by where
each one was set from.
```
-### <a name="format"></a>**gn format [\--dump-tree] (\--stdin | <build_file>)**
+### <a name="format"></a>**gn format [\--dump-tree] (\--stdin | <build_file>)**
```
Formats .gn file to a standard format.
@@ -628,7 +628,7 @@
gn format /abspath/some/BUILD.gn
gn format --stdin
```
-### <a name="gen"></a>**gn gen [\--check] [<ide options>] <out_dir>**
+### <a name="gen"></a>**gn gen [\--check] [<ide options>] <out_dir>**
```
Generates ninja files from the current tree and puts them in the given output
@@ -758,7 +758,7 @@
used for various Clang-based tooling, allowing for the replay of individual
compilations independent of the build system.
```
-### <a name="help"></a>**gn help <anything>**
+### <a name="help"></a>**gn help <anything>**
```
Yo dawg, I heard you like help on your help so I put help on the help in the
@@ -780,7 +780,7 @@
gn help --markdown all
Dump all help to stdout in markdown format.
```
-### <a name="ls"></a>**gn ls <out_dir> [<label_pattern>] [\--all-toolchains] [\--as=...]**
+### <a name="ls"></a>**gn ls <out_dir> [<label_pattern>] [\--all-toolchains] [\--as=...]**
```
[--type=...] [--testonly=...]
@@ -853,7 +853,7 @@
Lists all variants of the target //base:base (it may be referenced
in multiple toolchains).
```
-### <a name="path"></a>**gn path <out_dir> <target_one> <target_two>**
+### <a name="path"></a>**gn path <out_dir> <target_one> <target_two>**
```
Finds paths of dependencies between two targets. Each unique path will be
@@ -898,7 +898,7 @@
```
gn path out/Default //base //tools/gn
```
-### <a name="refs"></a>**gn refs <out_dir> (<label_pattern>|<label>|<file>|@<response_file>)***
+### <a name="refs"></a>**gn refs <out_dir> (<label_pattern>|<label>|<file>|@<response_file>)***
```
[--all] [--all-toolchains] [--as=...] [--testonly=...] [--type=...]
diff --git a/tools/gn/command_help.cc b/tools/gn/command_help.cc
index cff2052..6e816ce 100644
--- a/tools/gn/command_help.cc
+++ b/tools/gn/command_help.cc
@@ -120,20 +120,26 @@
OutputString("\n");
- if (is_markdown)
- OutputString("## <a name=\"commands\"></a>Commands\n\n");
+ if (is_markdown) {
+ OutputString("## <a name=\"commands\"></a>Commands\n\n", DECORATION_NONE,
+ NO_ESCAPING);
+ }
for (const auto& c : commands::GetCommands())
PrintLongHelp(c.second.help);
- if (is_markdown)
- OutputString("## <a name=\"targets\"></a>Target declarations\n\n");
+ if (is_markdown) {
+ OutputString("## <a name=\"targets\"></a>Target declarations\n\n",
+ DECORATION_NONE, NO_ESCAPING);
+ }
for (const auto& f : functions::GetFunctions()) {
if (f.second.is_target)
PrintLongHelp(f.second.help);
}
- if (is_markdown)
- OutputString("## <a name=\"functions\"></a>Buildfile functions\n\n");
+ if (is_markdown) {
+ OutputString("## <a name=\"functions\"></a>Buildfile functions\n\n",
+ DECORATION_NONE, NO_ESCAPING);
+ }
for (const auto& f : functions::GetFunctions()) {
if (!f.second.is_target)
PrintLongHelp(f.second.help);
@@ -142,7 +148,8 @@
if (is_markdown) {
OutputString(
"## <a name=\"predefined_variables\"></a>"
- "Built-in predefined variables\n\n");
+ "Built-in predefined variables\n\n",
+ DECORATION_NONE, NO_ESCAPING);
}
for (const auto& v : variables::GetBuiltinVariables())
PrintLongHelp(v.second.help);
@@ -150,13 +157,16 @@
if (is_markdown) {
OutputString(
"## <a name=\"target_variables\"></a>"
- "Variables you set in targets\n\n");
+ "Variables you set in targets\n\n",
+ DECORATION_NONE, NO_ESCAPING);
}
for (const auto& v : variables::GetTargetVariables())
PrintLongHelp(v.second.help);
- if (is_markdown)
- OutputString("## <a name=\"other\"></a>Other help topics\n\n");
+ if (is_markdown) {
+ OutputString("## <a name=\"other\"></a>Other help topics\n\n",
+ DECORATION_NONE, NO_ESCAPING);
+ }
PrintLongHelp(kBuildArgs_Help, "buildargs");
PrintLongHelp(kDotfile_Help, "dotfile");
PrintLongHelp(kExecution_Help, "execution");
@@ -170,8 +180,10 @@
PrintLongHelp(kRuntimeDeps_Help, "runtime_deps");
PrintLongHelp(kSourceExpansion_Help, "source_expansion");
- if (is_markdown)
- OutputString("## <a name=\"switches\"></a>Command Line Switches\n\n");
+ if (is_markdown) {
+ OutputString("## <a name=\"switches\"></a>Command Line Switches\n\n",
+ DECORATION_NONE, NO_ESCAPING);
+ }
PrintSwitchHelp();
}
diff --git a/tools/gn/standard_out.cc b/tools/gn/standard_out.cc
index 6dd6a6a..d2ff52e 100644
--- a/tools/gn/standard_out.cc
+++ b/tools/gn/standard_out.cc
@@ -35,6 +35,9 @@
bool is_markdown = false;
+// True while output is going into a markdown ```...``` code block.
+bool in_body = false;
+
void EnsureInitialized() {
if (initialized)
return;
@@ -96,7 +99,9 @@
#if defined(OS_WIN)
-void OutputString(const std::string& output, TextDecoration dec) {
+void OutputString(const std::string& output,
+ TextDecoration dec,
+ HtmlEscaping escaping) {
EnsureInitialized();
DWORD written = 0;
@@ -135,6 +140,12 @@
// at least escape the instances where this shows up in a heading.
base::ReplaceSubstringsAfterOffset(&tmpstr, 0, "--", "\\--");
}
+ if (is_markdown && !in_body && escaping == DEFAULT_ESCAPING) {
+ // Markdown auto-escapes < and > in code sections (and converts < to
+ // &tl; there), but not elsewhere.
+ base::ReplaceSubstringsAfterOffset(&tmpstr, 0, "<", "<");
+ base::ReplaceSubstringsAfterOffset(&tmpstr, 0, ">", ">");
+ }
::WriteFile(hstdout, tmpstr.c_str(), static_cast<DWORD>(tmpstr.size()),
&written, nullptr);
@@ -147,7 +158,9 @@
#else
-void OutputString(const std::string& output, TextDecoration dec) {
+void OutputString(const std::string& output,
+ TextDecoration dec,
+ HtmlEscaping escaping) {
EnsureInitialized();
if (is_markdown) {
OutputMarkdownDec(dec);
@@ -181,6 +194,12 @@
// at least escape the instances where this shows up in a heading.
base::ReplaceSubstringsAfterOffset(&tmpstr, 0, "--", "\\--");
}
+ if (is_markdown && !in_body && escaping == DEFAULT_ESCAPING) {
+ // Markdown auto-escapes < and > in code sections (and converts < to
+ // &tl; there), but not elsewhere.
+ base::ReplaceSubstringsAfterOffset(&tmpstr, 0, "<", "<");
+ base::ReplaceSubstringsAfterOffset(&tmpstr, 0, ">", ">");
+ }
WriteToStdOut(tmpstr.data());
if (is_markdown) {
@@ -248,7 +267,7 @@
EnsureInitialized();
bool first_header = true;
- bool in_body = false;
+ in_body = false;
std::size_t empty_lines = 0;
for (const std::string& line : base::SplitString(
text, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
@@ -279,7 +298,8 @@
the_tag = line.substr(0, line.find(':'));
}
}
- OutputString("### <a name=\"" + the_tag + "\"></a>", DECORATION_NONE);
+ OutputString("### <a name=\"" + the_tag + "\"></a>", DECORATION_NONE,
+ NO_ESCAPING);
first_header = false;
} else {
OutputString("#### ", DECORATION_NONE);
diff --git a/tools/gn/standard_out.h b/tools/gn/standard_out.h
index f2bb733..c793b29 100644
--- a/tools/gn/standard_out.h
+++ b/tools/gn/standard_out.h
@@ -16,8 +16,17 @@
DECORATION_YELLOW
};
+enum HtmlEscaping {
+ NO_ESCAPING,
+
+ // Convert < and > to < and > when writing markdown output in non-code
+ // sections.
+ DEFAULT_ESCAPING,
+};
+
void OutputString(const std::string& output,
- TextDecoration dec = DECORATION_NONE);
+ TextDecoration dec = DECORATION_NONE,
+ HtmlEscaping = DEFAULT_ESCAPING);
// If printing markdown, this generates table-of-contents entries with
// links to the actual help; otherwise, prints a one-line description.