summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-04-24 00:19:32 -0700
committerGitHub <noreply@github.com>2021-04-24 00:19:32 -0700
commit4f83d48b28b417a16d7caa834a9248b1bd50cdb8 (patch)
treed36710d45fc0dcb07f110390c85868cfa2b4f2a5
parent9a5672d7b8a155117a2c3f8375e3b8a5b43d91b7 (diff)
Auto generate interactive table of contents for user-guide. (#1818)
-rw-r--r--.gitignore3
-rw-r--r--docs/_includes/anchor_headings.html137
-rw-r--r--docs/_includes/user-guide-toc.html16
-rw-r--r--docs/_layouts/user-guide.html202
-rw-r--r--docs/user-guide/build_toc.ps19
-rw-r--r--docs/user-guide/index.md2
-rw-r--r--docs/user-guide/scripts/Program.cs164
-rw-r--r--docs/user-guide/user-guide-toc.html87
-rw-r--r--user-guide-toc.html87
9 files changed, 657 insertions, 50 deletions
diff --git a/.gitignore b/.gitignore
index fe322c934..0e40ee660 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,3 +54,6 @@ prelude/*.h.cpp
/source/slang/slang-ref-object-generated-macro.h
/source/slang/slang-ast-generated.h
/source/slang/slang-ast-generated-macro.h
+/docs/_site
+/docs/Gemfile.lock
+/docs/Gemfile
diff --git a/docs/_includes/anchor_headings.html b/docs/_includes/anchor_headings.html
new file mode 100644
index 000000000..3df42b6a6
--- /dev/null
+++ b/docs/_includes/anchor_headings.html
@@ -0,0 +1,137 @@
+{% capture headingsWorkspace %}
+{% comment %}
+Copyright (c) 2018 Vladimir "allejo" Jimenez
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+{% endcomment %}
+{% comment %}
+Version 1.0.9
+https://github.com/allejo/jekyll-anchor-headings
+
+"Be the pull request you wish to see in the world." ~Ben Balter
+
+Usage:
+{% include anchor_headings.html html=content anchorBody="#" %}
+
+Parameters:
+* html (string) - the HTML of compiled markdown generated by kramdown in Jekyll
+
+Optional Parameters:
+* beforeHeading (bool) : false - Set to true if the anchor should be placed _before_ the heading's content
+* headerAttrs (string) : '' - Any custom HTML attributes that will be added to the heading tag; you may NOT use `id`;
+the `%heading%` and `%html_id%` placeholders are available
+* anchorAttrs (string) : '' - Any custom HTML attributes that will be added to the `<a>` tag; you may NOT use `href`,
+ `class` or `title`;
+ the `%heading%` and `%html_id%` placeholders are available
+ * anchorBody (string) : '' - The content that will be placed inside the anchor; the `%heading%` placeholder is
+ available
+ * anchorClass (string) : '' - The class(es) that will be used for each anchor. Separate multiple classes with a
+ space
+ * anchorTitle (string) : '' - The `title` attribute that will be used for anchors
+ * h_min (int) : 1 - The minimum header level to build an anchor for; any header lower than this value will be
+ ignored
+ * h_max (int) : 6 - The maximum header level to build an anchor for; any header greater than this value will be
+ ignored
+ * bodyPrefix (string) : '' - Anything that should be inserted inside of the heading tag _before_ its anchor and
+ content
+ * bodySuffix (string) : '' - Anything that should be inserted inside of the heading tag _after_ its anchor and
+ content
+
+ Output:
+ The original HTML with the addition of anchors inside of all of the h1-h6 headings.
+ {% endcomment %}
+
+ {% assign minHeader = include.h_min | default: 1 %}
+ {% assign maxHeader = include.h_max | default: 2 %}
+ {% assign beforeHeading = include.beforeHeading %}
+ {% assign nodes = include.html | split: '<h' %} {% capture edited_headings %}{% endcapture %} {% for _node in nodes
+ %} {% capture node %}{{ _node | strip }}{% endcapture %} {% if node=="" %} {% continue %} {% endif %} {% assign
+ nextChar=node | replace: '"' , '' | strip | slice: 0, 1 %} {% assign headerLevel=nextChar | times: 1 %} <!-- If
+ the level is cast to 0, it means it's not a h1-h6 tag, so let's see if we need to fix it -->
+ {% if headerLevel == 0 %}
+ <!-- Split up the node based on closing angle brackets and get the first one. -->
+ {% assign firstChunk = node | split: '>' | first %}
+
+ <!-- If the first chunk does NOT contain a '<', that means we've broken another HTML tag that starts with 'h' -->
+ {% unless firstChunk contains '<' %} {% capture node %}<h{{ node }}{% endcapture %} {% endunless %} {% capture
+ edited_headings %}{{ edited_headings }}{{ node }}{% endcapture %} {% continue %} {% endif %} {% capture
+ _closingTag %}</h{{ headerLevel }}>{% endcapture %}
+ {% assign _workspace = node | split: _closingTag %}
+ {% assign _idWorkspace = _workspace[0] | split: 'id="' %}
+ {% assign _idWorkspace = _idWorkspace[1] | split: '"' %}
+ {% assign html_id = _idWorkspace[0] %}
+
+ {% capture _hAttrToStrip %}{{ _workspace[0] | split: '>' | first }}>{% endcapture %}
+ {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %}
+
+ <!-- Build the anchor to inject for our heading -->
+ {% capture anchor %}{% endcapture %}
+
+ {% if html_id and headerLevel >= minHeader and headerLevel <= maxHeader %} {% assign escaped_header=header |
+ strip_html %} {% if include.headerAttrs %} {% capture _hAttrToStrip %}{{ _hAttrToStrip | split: '>' |
+ first }} {{ include.headerAttrs | replace: '%heading%' , escaped_header | replace: '%html_id%' , html_id
+ }}>{% endcapture %}
+ {% endif %}
+
+ {% capture anchor %}href="#{{ html_id }}"{% endcapture %}
+
+ {% if include.anchorClass %}
+ {% capture anchor %}{{ anchor }} class="{{ include.anchorClass }}"{% endcapture %}
+ {% endif %}
+
+ {% if include.anchorTitle %}
+ {% capture anchor %}{{ anchor }} title="{{ include.anchorTitle | replace: '%heading%', escaped_header
+ }}"{% endcapture %}
+ {% endif %}
+
+ {% if include.anchorAttrs %}
+ {% capture anchor %}{{ anchor }} {{ include.anchorAttrs | replace: '%heading%', escaped_header |
+ replace: '%html_id%', html_id }}{% endcapture %}
+ {% endif %}
+
+ {% capture anchor %}<a {{ anchor }}>{{ include.anchorBody | replace: '%heading%', escaped_header |
+ default: '' }}</a>{% endcapture %}
+
+ <!-- In order to prevent adding extra space after a heading, we'll let the 'anchor' value contain it -->
+ {% if beforeHeading %}
+ {% capture anchor %}{{ anchor }} {% endcapture %}
+ {% else %}
+ {% capture anchor %} {{ anchor }}{% endcapture %}
+ {% endif %}
+ {% endif %}
+
+ {% capture new_heading %}
+ <h{{ _hAttrToStrip }} {{ include.bodyPrefix }} {% if beforeHeading %} {{ anchor }}{{ header }} {% else
+ %} {{ header }}{{ anchor }} {% endif %} {{ include.bodySuffix }} </h{{ headerLevel }}>
+ {% endcapture %}
+
+ <!--
+ If we have content after the `</hX>` tag, then we'll want to append that here so we don't lost any content.
+ -->
+ {% assign chunkCount = _workspace | size %}
+ {% if chunkCount > 1 %}
+ {% capture new_heading %}{{ new_heading }}{{ _workspace | last }}{% endcapture %}
+ {% endif %}
+
+ {% capture edited_headings %}{{ edited_headings }}{{ new_heading }}{% endcapture %}
+ {% endfor %}
+ {% endcapture %}{% assign headingsWorkspace = '' %}{{ edited_headings | strip }} \ No newline at end of file
diff --git a/docs/_includes/user-guide-toc.html b/docs/_includes/user-guide-toc.html
deleted file mode 100644
index 511b30aad..000000000
--- a/docs/_includes/user-guide-toc.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-<a href="/slang/user-guide/">Slang User's Guide</a>
-<ol class="toc_list">
- <li><a href="/slang/user-guide/00-introduction.html">Introduction</a></li>
- <li><a href="/slang/user-guide/01-get-started.html">Getting Started</a></li>
- <li><a href="/slang/user-guide/02-conventional-features.html">Conventional Language Features</a></li>
- <li><a href="/slang/user-guide/03-convenience-features.html">Extended language features</a></li>
- <li><a href="/slang/user-guide/04-interfaces-generics.html">Interfaces and Generics</a></li>
- <li><a href="/slang/user-guide/05-compiling.html">Compiling Code with Slang</a></li>
- <li><a href="/slang/user-guide/06-targets.html">Supported Compilation Targets</a></li>
- <li><a href="/slang/user-guide/a1-special-topics.html">Special Topics</a></li>
- <ol class="toc_list">
- <li><a href="/slang/user-guide/a1-01-matrix-layout.html">Matrix Layout</a></li>
- </ol>
-
-</ol>
diff --git a/docs/_layouts/user-guide.html b/docs/_layouts/user-guide.html
index 765ddc40a..ad4ad2cd9 100644
--- a/docs/_layouts/user-guide.html
+++ b/docs/_layouts/user-guide.html
@@ -11,57 +11,193 @@
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<style>
- #dividerContainer {
- height: 98%;
+ #centeringDiv {
+ margin: auto;
+ max-width: 1000px;
+ padding-left: 350px;
}
#tocColumn {
- float: left;
- width: 25%;
- height: 100%;
- overflow: auto;
- margin-right: 20px;
+ width: 350px;
+ position: fixed;
+ overflow-y: auto;
+ box-sizing: border-box;
+ max-height: 100vh;
+ }
+
+ #tocInner {
+ padding: 20px;
}
#rightColumn {
- float: left;
- width: 70%;
- height: 100%;
- overflow: auto;
- padding-left: 20px;
+ padding-left: 40px;
+ padding-right: 40px;
+ padding-top: 20px;
+ border-left-width: 1.5px;
+ border-left-style: solid;
+ border-left-color: #C8C8C8;
}
- .toc_list {
+ .toc_root_list {
list-style-type: none;
- padding-left:20px;
+ list-style-position: outside;
+ background-color: initial;
+ padding-left: 0px;
+ }
+ .toc_list {
+ padding-left: 16px;
+ background-color: initial;
+ list-style-type: none;
+ margin-bottom: 0px;
+ }
+ .toc_item {
+ cursor: pointer;
+ user-select: none;
+ list-style-type: none;
+ padding-left: 0px;
+ padding-top: 5px;
+ }
+ .toc_item_expanded::before {
+ content: "\25be";
+ cursor: pointer;
+ }
+ .toc_item_collapsed::before {
+ content: "\25b8";
+ cursor: pointer;
+ }
+ .toc_item_leaf {
+ padding-left: 14px;
+ cursor: pointer;
+ list-style-type: none;
+ }
+ .toc_span:hover
+ {
+ color: #303080
}
</style>
{% seo %}
</head>
<body>
- <div id="container">
- <div class="inner" style="padding:40px;width:1000px">
- <div id="dividerContainer">
- <div id="tocColumn">
- {% include user-guide-toc.html %}
- </div>
- <div id="rightColumn">
- <section id="main_content">
- {{ content }}
- </section>
+ <div id="tocColumn">
+ <div id="tocInner">
+ {% include_relative user-guide-toc.html %}
+ </div>
+ </div>
+ <div id="centeringDiv">
+ <div id="rightColumn">
+ <section id="main_content">
+ {% include anchor_headings.html html=content anchorBody="" %}
+ </section>
- <footer>
- {% if site.github.is_project_page %}
- {{ site.title | default: site.github.repository_name }} is maintained by <a
- href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a><br>
- {% endif %}
- This page was generated by <a href="https://pages.github.com">GitHub Pages</a>.
- </footer>
- </div>
+ <footer>
+ {% if site.github.is_project_page %}
+ {{ site.title | default: site.github.repository_name }} is maintained by <a
+ href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a><br>
+ {% endif %}
+ This page was generated by <a href="https://pages.github.com">GitHub Pages</a>.
+ </footer>
</div>
</div>
- </div>
+ <script>
+ var tocColumn = document.getElementById("tocColumn");
+ var rightColumn = document.getElementById("rightColumn");
+ function updatePosition()
+ {
+ tocColumn.style.left = (rightColumn.getBoundingClientRect().x - tocColumn.getBoundingClientRect().width) + "px";
+ }
+ window.addEventListener("resize", updatePosition);
+ updatePosition();
+ </script>
+
+ <script>
+ var tocItemsArray = [];
+ var selectedItem = null;
+
+ function expandItem(e) {
+ if (e == selectedItem)
+ e.style["font-weight"] = "bold";
+ var childList = e.getElementsByClassName("toc_list");
+ if (childList.length == 0)
+ return;
+ childList[0].style.display = "block";
+ childList[0].style["font-weight"] = "normal";
+ e.setAttribute("class", "toc_item toc_item_expanded");
+ }
+ function collapseItem(e) {
+ var childList = e.getElementsByClassName("toc_list");
+ if (childList.length == 0)
+ return;
+ childList[0].style.display = "none";
+ e.setAttribute("class", "toc_item toc_item_collapsed");
+ }
+ function tocSpanOnClick(e)
+ {
+ if (event.srcElement != null && event.srcElement.parentElement != null)
+ {
+ var link = event.srcElement.parentElement.getAttribute("data-link");
+ if (link != null)
+ {
+ var poundIndex = link.indexOf("#");
+ if (poundIndex == -1)
+ window.location.href = link + ".html";
+ else
+ window.location.href = link.substr(0, poundIndex) + ".html#" + link.substr(poundIndex+1, link.length - poundIndex - 1);
+ }
+ }
+ event.stopPropagation();
+ }
+ function tocItemOnClick(e)
+ {
+ if (event.srcElement == null) return;
+ // Toggle expanded/collapsed state.
+ if (event.srcElement.getAttribute("class").endsWith("toc_item_collapsed"))
+ expandItem(event.srcElement);
+ else if (event.srcElement.getAttribute("class").endsWith("toc_item_expanded"))
+ collapseItem(event.srcElement);
+ event.stopPropagation();
+ }
+ var path = window.location.pathname;
+ var pageName = path.split("/").pop();
+ var currentPageID = pageName.substr(0, pageName.lastIndexOf("."));
+
+ var tocLists = document.getElementsByClassName("toc_root_list");
+ for (var i = 0; i < tocLists.length; i++) {
+ var tocList = tocLists[i];
+ var items = tocList.getElementsByTagName("li")
+ for (var j = 0; j < items.length; j++)
+ tocItemsArray.push(items[j]);
+ }
+ for (var i = 0; i < tocItemsArray.length; i++) {
+ var item = tocItemsArray[i];
+ if (item.getAttribute("data-link") == currentPageID)
+ selectedItem = item;
+ if (item.getElementsByTagName("li").length != 0) {
+ collapseItem(item);
+ }
+ else {
+ item.setAttribute("class", "toc_item toc_item_leaf");
+ }
+ item.addEventListener("click", tocItemOnClick);
+ var innerSpan = item.getElementsByTagName("span");
+ if (innerSpan.length != 0)
+ {
+ innerSpan[0].addEventListener("click", tocSpanOnClick);
+ innerSpan[0].setAttribute("class", "toc_span");
+ }
+ }
+ var curItem = selectedItem;
+ while (curItem != null) {
+ expandItem(curItem);
+ curItem = curItem.parentElement;
+ if (curItem != null && curItem.getAttribute("class") != null &&
+ curItem.getAttribute("class").startsWith("toc_list"))
+ curItem = curItem.parentElement;
+ if (curItem != null && curItem.getAttribute("class") != null &&
+ curItem.getAttribute("class").startsWith("toc_root_list"))
+ break;
+ }
+ </script>
{% if site.google_analytics %}
<script>
diff --git a/docs/user-guide/build_toc.ps1 b/docs/user-guide/build_toc.ps1
new file mode 100644
index 000000000..15603c8cb
--- /dev/null
+++ b/docs/user-guide/build_toc.ps1
@@ -0,0 +1,9 @@
+$job = Start-Job -ArgumentList $PSScriptRoot -ScriptBlock {
+ Set-Location $args[0]
+ $code = (Get-Content -Raw -Path "scripts/Program.cs").ToString()
+ $assemblies = ("System.Core", "System.IO", "System.Collections")
+ Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $code -Language CSharp
+ [toc.Builder]::Run($args[0])
+}
+Wait-Job $job
+Receive-Job -Job $job
diff --git a/docs/user-guide/index.md b/docs/user-guide/index.md
index 4d82fa8ec..9f5a36e86 100644
--- a/docs/user-guide/index.md
+++ b/docs/user-guide/index.md
@@ -3,7 +3,7 @@ layout: user-guide
---
Slang User's Guide
-------------------
+=============
Welcome to the Slang User's Guide, an introduction to the Slang language, compiler, and API. In this guide, you will learn:
- Slang's language features, including those inherited from HLSL and additional language features to make it easy to work with shaders.
diff --git a/docs/user-guide/scripts/Program.cs b/docs/user-guide/scripts/Program.cs
new file mode 100644
index 000000000..4ed2d18a6
--- /dev/null
+++ b/docs/user-guide/scripts/Program.cs
@@ -0,0 +1,164 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Collections.Generic;
+namespace toc
+{
+ public class Builder
+ {
+ public static string getAnchorId(string title)
+ {
+ StringBuilder sb = new StringBuilder();
+ title = title.Trim().ToLower();
+ foreach (var ch in title)
+ {
+ if (ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9'
+ || ch == '-')
+ sb.Append(ch);
+ else if (ch==' ' || ch =='_')
+ sb.Append('-');
+ }
+ return sb.ToString();
+ }
+
+ public class Node
+ {
+ public List<string> fileNamePrefix = new List<string>();
+ public string title;
+ public string fileID;
+ public List<string> sections = new List<string>();
+ public List<Node> children = new List<Node>();
+ }
+
+ public static void buildTOC(StringBuilder sb, Node n)
+ {
+ sb.AppendFormat("<li data-link=\"{0}\"><span>{1}</span>\n", n.fileID, n.title);
+ if (n.children.Count != 0)
+ {
+ sb.AppendLine("<ul class=\"toc_list\">");
+ foreach(var c in n.children)
+ buildTOC(sb, c);
+ sb.AppendLine("</ul>");
+ }
+ else if (n.sections.Count != 0)
+ {
+ sb.AppendLine("<ul class=\"toc_list\">");
+ foreach (var s in n.sections)
+ {
+ sb.AppendFormat("<li data-link=\"{0}#{1}\"><span>{2}</span></li>\n", n.fileID, getAnchorId(s), s);
+ }
+ sb.AppendLine("</ul>");
+ }
+ sb.AppendLine("</li>");
+ }
+ public static string buildTOC(Node n)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append(@"<ul class=""toc_root_list"">");
+ buildTOC(sb, n);
+ sb.Append(@"</ul>");
+ return sb.ToString();
+ }
+
+ public static bool isChild(Node parent, Node child)
+ {
+ if (parent.fileNamePrefix.Count < child.fileNamePrefix.Count)
+ {
+ bool equal = true;
+ for (int k = 0; k < parent.fileNamePrefix.Count; k++)
+ {
+ if (parent.fileNamePrefix[k] != child.fileNamePrefix[k])
+ {
+ equal = false;
+ break;
+ }
+ }
+ return equal;
+ }
+ return false;
+ }
+ public static string Run(string path)
+ {
+ StringBuilder outputSB = new StringBuilder();
+ outputSB.AppendFormat("Building table of contents from {0}...\n", path);
+ var files = System.IO.Directory.EnumerateFiles(path, "*.md");
+ List<Node> nodes = new List<Node>();
+ foreach (var f in files)
+ {
+ var content = File.ReadAllLines(f);
+ Node node = new Node();
+ node.fileID = Path.GetFileNameWithoutExtension(f);
+ outputSB.AppendFormat(" {0}.md\n", node.fileID);
+ for (int i = 1; i < content.Length; i++)
+ {
+ if (content[i-1].StartsWith("layout: "))
+ continue;
+ if (content[i].StartsWith("==="))
+ node.title = content[i-1];
+ if (content[i].StartsWith("---"))
+ node.sections.Add(content[i-1]);
+ if (content[i].StartsWith("#") && !content[i].StartsWith("##") && node.title == null)
+ node.title = content[i].Substring(1, content[i].Length - 1).Trim();
+ if (content[i].StartsWith("##") && !content[i].StartsWith("###"))
+ node.sections.Add(content[i].Substring(2, content[i].Length - 2).Trim());
+ }
+ if (node.title == null)
+ {
+ outputSB.AppendFormat("Error: {0} does not define a title.", f);
+ node.title = "Untitiled";
+ }
+ var titleSecs = Path.GetFileName(f).Split('-');
+ foreach (var s in titleSecs)
+ {
+ if (s.Length == 2 && s[1]>='0' && s[1] <= '9')
+ {
+ node.fileNamePrefix.Add(s);
+ }
+ else
+ {
+ break;
+ }
+ }
+ // Find parent node.
+ Node parent=null;
+ for (int l = nodes.Count-1; l>=0; l--)
+ {
+ var n = nodes[l];
+ if (isChild(n, node))
+ {
+ parent = n;
+ break;
+ }
+ }
+ if (parent != null)
+ parent.children.Add(node);
+ else
+ {
+ // find child
+ foreach (var other in nodes)
+ {
+ if (isChild(node, other))
+ {
+ node.children.Add(other);
+ }
+ }
+ foreach (var c in node.children)
+ {
+ nodes.Remove(c);
+
+ }
+ nodes.Add(node);
+ }
+ }
+ var root = nodes.Find(x=>x.fileID=="index");
+ if (root != null)
+ {
+ var html = buildTOC(root);
+ var outPath = Path.Combine(path, "user-guide-toc.html");
+ File.WriteAllText(outPath, html);
+ outputSB.AppendFormat("Output written to: {0}\n", outPath);
+ }
+ return outputSB.ToString();
+ }
+ }
+} \ No newline at end of file
diff --git a/docs/user-guide/user-guide-toc.html b/docs/user-guide/user-guide-toc.html
new file mode 100644
index 000000000..0847fcc3e
--- /dev/null
+++ b/docs/user-guide/user-guide-toc.html
@@ -0,0 +1,87 @@
+<ul class="toc_root_list"><li data-link="index"><span>Slang User's Guide</span>
+<ul class="toc_list">
+<li data-link="00-introduction"><span>Introduction</span>
+<ul class="toc_list">
+<li data-link="00-introduction#why-use-slang"><span>Why use Slang?</span></li>
+<li data-link="00-introduction#who-is-slang-for"><span>Who is Slang for?</span></li>
+<li data-link="00-introduction#who-is-this-guide-for"><span>Who is this guide for?</span></li>
+<li data-link="00-introduction#goals-and-non-goals"><span>Goals and Non-Goals</span></li>
+</ul>
+</li>
+<li data-link="01-get-started"><span>Getting Started with Slang</span>
+<ul class="toc_list">
+<li data-link="01-get-started#installation"><span>Installation</span></li>
+<li data-link="01-get-started#your-first-slang-shader"><span>Your first Slang shader</span></li>
+<li data-link="01-get-started#the-full-example"><span>The full example</span></li>
+</ul>
+</li>
+<li data-link="02-conventional-features"><span>Conventional Language Features</span>
+<ul class="toc_list">
+<li data-link="02-conventional-features#types"><span>Types</span></li>
+<li data-link="02-conventional-features#expressions"><span>Expressions</span></li>
+<li data-link="02-conventional-features#statements"><span>Statements</span></li>
+<li data-link="02-conventional-features#functions"><span>Functions</span></li>
+<li data-link="02-conventional-features#preprocessor"><span>Preprocessor</span></li>
+<li data-link="02-conventional-features#attributes"><span>Attributes</span></li>
+<li data-link="02-conventional-features#global-variables-and-shader-parameters"><span>Global Variables and Shader Parameters</span></li>
+<li data-link="02-conventional-features#shader-entry-points"><span>Shader Entry Points</span></li>
+</ul>
+</li>
+<li data-link="03-convenience-features"><span>Basic Convenience Features</span>
+<ul class="toc_list">
+<li data-link="03-convenience-features#type-inference-in-variable-definitions"><span>Type Inference in Variable Definitions</span></li>
+<li data-link="03-convenience-features#immutable-values"><span>Immutable Values</span></li>
+<li data-link="03-convenience-features#member-functions"><span>Member functions</span></li>
+<li data-link="03-convenience-features#properties"><span>Properties</span></li>
+<li data-link="03-convenience-features#initializers"><span>Initializers</span></li>
+<li data-link="03-convenience-features#operator-overloading"><span>Operator Overloading</span></li>
+<li data-link="03-convenience-features#struct-inheritance-limited"><span>`struct` inheritance (limited)</span></li>
+<li data-link="03-convenience-features#extensions"><span>Extensions</span></li>
+<li data-link="03-convenience-features#modules"><span>Modules</span></li>
+</ul>
+</li>
+<li data-link="04-interfaces-generics"><span>Interfaces and Generics</span>
+<ul class="toc_list">
+<li data-link="04-interfaces-generics#interfaces"><span>Interfaces</span></li>
+<li data-link="04-interfaces-generics#generics"><span>Generics</span></li>
+<li data-link="04-interfaces-generics#supported-constructs-in-interface-definitions"><span>Supported Constructs in Interface Definitions</span></li>
+<li data-link="04-interfaces-generics#associated-types"><span>Associated Types</span></li>
+<li data-link="04-interfaces-generics#generic-value-parameters"><span>Generic Value Parameters</span></li>
+<li data-link="04-interfaces-generics#interface-typed-values"><span>Interface-typed Values</span></li>
+<li data-link="04-interfaces-generics#extending-a-type-with-additional-interface-conformances"><span>Extending a Type with Additional Interface Conformances</span></li>
+<li data-link="04-interfaces-generics#extensions-to-interfaces"><span>Extensions to Interfaces</span></li>
+</ul>
+</li>
+<li data-link="05-compiling"><span>Compiling Code with Slang</span>
+<ul class="toc_list">
+<li data-link="05-compiling#concepts"><span>Concepts</span></li>
+<li data-link="05-compiling#command-line-compilation-with-slangc"><span>Command-Line Compilation with `slangc`</span></li>
+<li data-link="05-compiling#using-the-compilation-api"><span>Using the Compilation API</span></li>
+</ul>
+</li>
+<li data-link="06-targets"><span>Suported Compilation Targets</span>
+<ul class="toc_list">
+<li data-link="06-targets#background-and-terminology"><span>Background and Terminology</span></li>
+<li data-link="06-targets#direct3d-11"><span>Direct3D 11</span></li>
+<li data-link="06-targets#direct3d-12"><span>Direct3D 12</span></li>
+<li data-link="06-targets#vulkan"><span>Vulkan</span></li>
+<li data-link="06-targets#opengl"><span>OpenGL</span></li>
+<li data-link="06-targets#cuda-and-optix"><span>CUDA and OptiX</span></li>
+<li data-link="06-targets#cpu-compute"><span>CPU Compute</span></li>
+<li data-link="06-targets#summary"><span>Summary</span></li>
+</ul>
+</li>
+<li data-link="a1-special-topics"><span>Special Topics</span>
+<ul class="toc_list">
+<li data-link="a1-01-matrix-layout"><span>Handling Matrix Layout Differences on Different Platforms</span>
+<ul class="toc_list">
+<li data-link="a1-01-matrix-layout#two-conventions-of-matrix-transform-math"><span>Two conventions of matrix transform math</span></li>
+<li data-link="a1-01-matrix-layout#overriding-default-matrix-layout"><span>Overriding default matrix layout</span></li>
+<li data-link="a1-01-matrix-layout#summary"><span>Summary</span></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul> \ No newline at end of file
diff --git a/user-guide-toc.html b/user-guide-toc.html
new file mode 100644
index 000000000..0847fcc3e
--- /dev/null
+++ b/user-guide-toc.html
@@ -0,0 +1,87 @@
+<ul class="toc_root_list"><li data-link="index"><span>Slang User's Guide</span>
+<ul class="toc_list">
+<li data-link="00-introduction"><span>Introduction</span>
+<ul class="toc_list">
+<li data-link="00-introduction#why-use-slang"><span>Why use Slang?</span></li>
+<li data-link="00-introduction#who-is-slang-for"><span>Who is Slang for?</span></li>
+<li data-link="00-introduction#who-is-this-guide-for"><span>Who is this guide for?</span></li>
+<li data-link="00-introduction#goals-and-non-goals"><span>Goals and Non-Goals</span></li>
+</ul>
+</li>
+<li data-link="01-get-started"><span>Getting Started with Slang</span>
+<ul class="toc_list">
+<li data-link="01-get-started#installation"><span>Installation</span></li>
+<li data-link="01-get-started#your-first-slang-shader"><span>Your first Slang shader</span></li>
+<li data-link="01-get-started#the-full-example"><span>The full example</span></li>
+</ul>
+</li>
+<li data-link="02-conventional-features"><span>Conventional Language Features</span>
+<ul class="toc_list">
+<li data-link="02-conventional-features#types"><span>Types</span></li>
+<li data-link="02-conventional-features#expressions"><span>Expressions</span></li>
+<li data-link="02-conventional-features#statements"><span>Statements</span></li>
+<li data-link="02-conventional-features#functions"><span>Functions</span></li>
+<li data-link="02-conventional-features#preprocessor"><span>Preprocessor</span></li>
+<li data-link="02-conventional-features#attributes"><span>Attributes</span></li>
+<li data-link="02-conventional-features#global-variables-and-shader-parameters"><span>Global Variables and Shader Parameters</span></li>
+<li data-link="02-conventional-features#shader-entry-points"><span>Shader Entry Points</span></li>
+</ul>
+</li>
+<li data-link="03-convenience-features"><span>Basic Convenience Features</span>
+<ul class="toc_list">
+<li data-link="03-convenience-features#type-inference-in-variable-definitions"><span>Type Inference in Variable Definitions</span></li>
+<li data-link="03-convenience-features#immutable-values"><span>Immutable Values</span></li>
+<li data-link="03-convenience-features#member-functions"><span>Member functions</span></li>
+<li data-link="03-convenience-features#properties"><span>Properties</span></li>
+<li data-link="03-convenience-features#initializers"><span>Initializers</span></li>
+<li data-link="03-convenience-features#operator-overloading"><span>Operator Overloading</span></li>
+<li data-link="03-convenience-features#struct-inheritance-limited"><span>`struct` inheritance (limited)</span></li>
+<li data-link="03-convenience-features#extensions"><span>Extensions</span></li>
+<li data-link="03-convenience-features#modules"><span>Modules</span></li>
+</ul>
+</li>
+<li data-link="04-interfaces-generics"><span>Interfaces and Generics</span>
+<ul class="toc_list">
+<li data-link="04-interfaces-generics#interfaces"><span>Interfaces</span></li>
+<li data-link="04-interfaces-generics#generics"><span>Generics</span></li>
+<li data-link="04-interfaces-generics#supported-constructs-in-interface-definitions"><span>Supported Constructs in Interface Definitions</span></li>
+<li data-link="04-interfaces-generics#associated-types"><span>Associated Types</span></li>
+<li data-link="04-interfaces-generics#generic-value-parameters"><span>Generic Value Parameters</span></li>
+<li data-link="04-interfaces-generics#interface-typed-values"><span>Interface-typed Values</span></li>
+<li data-link="04-interfaces-generics#extending-a-type-with-additional-interface-conformances"><span>Extending a Type with Additional Interface Conformances</span></li>
+<li data-link="04-interfaces-generics#extensions-to-interfaces"><span>Extensions to Interfaces</span></li>
+</ul>
+</li>
+<li data-link="05-compiling"><span>Compiling Code with Slang</span>
+<ul class="toc_list">
+<li data-link="05-compiling#concepts"><span>Concepts</span></li>
+<li data-link="05-compiling#command-line-compilation-with-slangc"><span>Command-Line Compilation with `slangc`</span></li>
+<li data-link="05-compiling#using-the-compilation-api"><span>Using the Compilation API</span></li>
+</ul>
+</li>
+<li data-link="06-targets"><span>Suported Compilation Targets</span>
+<ul class="toc_list">
+<li data-link="06-targets#background-and-terminology"><span>Background and Terminology</span></li>
+<li data-link="06-targets#direct3d-11"><span>Direct3D 11</span></li>
+<li data-link="06-targets#direct3d-12"><span>Direct3D 12</span></li>
+<li data-link="06-targets#vulkan"><span>Vulkan</span></li>
+<li data-link="06-targets#opengl"><span>OpenGL</span></li>
+<li data-link="06-targets#cuda-and-optix"><span>CUDA and OptiX</span></li>
+<li data-link="06-targets#cpu-compute"><span>CPU Compute</span></li>
+<li data-link="06-targets#summary"><span>Summary</span></li>
+</ul>
+</li>
+<li data-link="a1-special-topics"><span>Special Topics</span>
+<ul class="toc_list">
+<li data-link="a1-01-matrix-layout"><span>Handling Matrix Layout Differences on Different Platforms</span>
+<ul class="toc_list">
+<li data-link="a1-01-matrix-layout#two-conventions-of-matrix-transform-math"><span>Two conventions of matrix transform math</span></li>
+<li data-link="a1-01-matrix-layout#overriding-default-matrix-layout"><span>Overriding default matrix layout</span></li>
+<li data-link="a1-01-matrix-layout#summary"><span>Summary</span></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul> \ No newline at end of file