diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -72,7 +72,7 @@
     'rsrc/css/application/differential/table-of-contents.css' => 'bba788b9',
     'rsrc/css/application/diffusion/diffusion-icons.css' => '23b31a1b',
     'rsrc/css/application/diffusion/diffusion-readme.css' => 'b68a76e4',
-    'rsrc/css/application/diffusion/diffusion-repository.css' => 'b89e8c6c',
+    'rsrc/css/application/diffusion/diffusion-repository.css' => '06b98eb8',
     'rsrc/css/application/diffusion/diffusion.css' => 'e46232d6',
     'rsrc/css/application/feed/feed.css' => 'd8b6e3f8',
     'rsrc/css/application/files/global-drag-and-drop.css' => '1d2713a4',
@@ -394,6 +394,7 @@
     'rsrc/js/application/diffusion/behavior-commit-graph.js' => 'ac10c917',
     'rsrc/js/application/diffusion/behavior-locate-file.js' => '87428eb2',
     'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'c715c123',
+    'rsrc/js/application/diffusion/collapsible-container.js' => '750a3731',
     'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '6a85bc5a',
     'rsrc/js/application/drydock/drydock-live-operation-status.js' => '47a0728b',
     'rsrc/js/application/fact/Chart.js' => '52e3ff03',
@@ -570,7 +571,7 @@
     'diffusion-css' => 'e46232d6',
     'diffusion-icons-css' => '23b31a1b',
     'diffusion-readme-css' => 'b68a76e4',
-    'diffusion-repository-css' => 'b89e8c6c',
+    'diffusion-repository-css' => '06b98eb8',
     'diviner-shared-css' => '4bd263b0',
     'font-fontawesome' => '3883938a',
     'font-lato' => '23631304',
@@ -618,6 +619,7 @@
     'javelin-behavior-device' => 'ac2b1e01',
     'javelin-behavior-differential-diff-radios' => '925fe8cd',
     'javelin-behavior-differential-populate' => 'b86ef6c2',
+    'javelin-behavior-diffusion-collapsible-container' => '750a3731',
     'javelin-behavior-diffusion-commit-branches' => '4b671572',
     'javelin-behavior-diffusion-commit-graph' => 'ac10c917',
     'javelin-behavior-diffusion-locate-file' => '87428eb2',
@@ -1616,6 +1618,10 @@
       'phabricator-drag-and-drop-file-upload',
       'javelin-workboard-board',
     ),
+    '750a3731' => array(
+      'javelin-behavior',
+      'javelin-dom',
+    ),
     '78bc5d94' => array(
       'javelin-behavior',
       'javelin-uri',
diff --git a/src/applications/diffusion/controller/DiffusionBrowseController.php b/src/applications/diffusion/controller/DiffusionBrowseController.php
--- a/src/applications/diffusion/controller/DiffusionBrowseController.php
+++ b/src/applications/diffusion/controller/DiffusionBrowseController.php
@@ -190,6 +190,10 @@
           ->setRequest($request)
           ->setDiffusionRequest($drequest);
 
+        if ($engine instanceof PHUIRemarkupView) {
+          $engine->setGenerateTableOfContents(true);
+        }
+
         $corpus = $engine->newDocumentView($ref);
 
         $this->corpusButtons[] = $this->renderFileButton();
diff --git a/src/applications/files/document/PhabricatorRemarkupDocumentEngine.php b/src/applications/files/document/PhabricatorRemarkupDocumentEngine.php
--- a/src/applications/files/document/PhabricatorRemarkupDocumentEngine.php
+++ b/src/applications/files/document/PhabricatorRemarkupDocumentEngine.php
@@ -36,6 +36,7 @@
     $content = phutil_utf8ize($content);
 
     $remarkup = new PHUIRemarkupView($viewer, $content);
+    $remarkup->setGenerateTableOfContents(true);
 
     $container = phutil_tag(
       'div',
diff --git a/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php b/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php
--- a/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php
+++ b/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php
@@ -208,12 +208,12 @@
     $this->activeEngine = $engine;
 
     $encode_setting = $request->getStr('encode');
-    if (strlen($encode_setting)) {
+    if (phutil_nonempty_string($encode_setting)) {
       $engine->setEncodingConfiguration($encode_setting);
     }
 
     $highlight_setting = $request->getStr('highlight');
-    if (strlen($highlight_setting)) {
+    if (phutil_nonempty_string($highlight_setting)) {
       $engine->setHighlightingConfiguration($highlight_setting);
     }
 
diff --git a/src/infrastructure/markup/PhabricatorMarkupEngine.php b/src/infrastructure/markup/PhabricatorMarkupEngine.php
--- a/src/infrastructure/markup/PhabricatorMarkupEngine.php
+++ b/src/infrastructure/markup/PhabricatorMarkupEngine.php
@@ -459,6 +459,10 @@
         $engine = self::newMarkupEngine(array());
         $engine->setConfig('pygments.enabled', false);
         break;
+      case 'remarkupField':
+        $engine = self::newMarkupEngine(array());
+        $engine->setConfig('header.generate-toc', true);
+        break;
       default:
         throw new Exception(pht('Unknown engine ruleset: %s!', $ruleset));
     }
diff --git a/src/infrastructure/markup/PhabricatorMarkupOneOff.php b/src/infrastructure/markup/PhabricatorMarkupOneOff.php
--- a/src/infrastructure/markup/PhabricatorMarkupOneOff.php
+++ b/src/infrastructure/markup/PhabricatorMarkupOneOff.php
@@ -97,7 +97,11 @@
     if ($this->engineRuleset) {
       return PhabricatorMarkupEngine::getEngine($this->engineRuleset);
     } else if ($this->preserveLinebreaks) {
-      return PhabricatorMarkupEngine::getEngine();
+      $engine = PhabricatorMarkupEngine::getEngine();
+      if ($this->generateTableOfContents) {
+        $engine->setConfig('header.generate-toc', true);
+      }
+      return $engine;
     } else {
       return PhabricatorMarkupEngine::getEngine('nolinebreaks');
     }
@@ -115,6 +119,41 @@
     if ($this->getGenerateTableOfContents()) {
       $toc = PhutilRemarkupHeaderBlockRule::renderTableOfContents($engine);
       $this->tableOfContents = $toc;
+      $collapsible_button_id = 'toc-index-button-toggler-1';
+      $collapsible_container_id = 'toc-index-container-1';
+      $collapsible_icon = id(new PHUIIconView())
+        ->addSigil('collapsible-toggler-label')
+        ->setIcon('fa-list')
+        ->setText(pht('Open Index')); // Keep this in sync with below.
+      $collapsible_button = phutil_tag(
+        'button',
+        array(
+          'type' => 'button',
+          'class' => 'collapsible',
+          'id' => $collapsible_button_id,
+        ),
+        $collapsible_icon);
+      $toc_div = phutil_tag(
+        'div',
+        array(
+          'class' => 'collapsible-content',
+          'id' => $collapsible_container_id,
+        ),
+        $toc);
+
+      $output = phutil_implode_html(
+        "\n",
+        array($collapsible_button, $toc_div, $output));
+      Javelin::initBehavior(
+        'diffusion-collapsible-container',
+        array(
+        'toggle_button_id' => $collapsible_button_id,
+        'container_id' => $collapsible_container_id,
+        'i18n' => array(
+          'btn_open' => pht('Open Index'), // Keep this in sync with above.
+          'btn_close' => pht('Close Index'),
+        ),
+        ));
     }
 
     require_celerity_resource('phabricator-remarkup-css');
diff --git a/src/infrastructure/markup/blockrule/PhutilRemarkupHeaderBlockRule.php b/src/infrastructure/markup/blockrule/PhutilRemarkupHeaderBlockRule.php
--- a/src/infrastructure/markup/blockrule/PhutilRemarkupHeaderBlockRule.php
+++ b/src/infrastructure/markup/blockrule/PhutilRemarkupHeaderBlockRule.php
@@ -134,7 +134,7 @@
       list($level, $name) = $info;
 
       while ($depth < $level) {
-        $toc[] = hsprintf('<ul>');
+        $toc[] = hsprintf('<ul class="remarkup-list">');
         $depth++;
       }
       while ($depth > $level) {
diff --git a/src/infrastructure/markup/remarkup/__tests__/remarkup/interpreter-test.txt b/src/infrastructure/markup/remarkup/__tests__/remarkup/interpreter-test.txt
--- a/src/infrastructure/markup/remarkup/__tests__/remarkup/interpreter-test.txt
+++ b/src/infrastructure/markup/remarkup/__tests__/remarkup/interpreter-test.txt
@@ -30,9 +30,7 @@
 Content: (content)
 Argv: (x=y)
 
-
-
-<div class="remarkup-interpreter-error">No interpreter found: phutil_fake_test_block_interpreter</div>
+<p>phutil_fake_test_block_interpreter {{{ content }}}</p>
 ~~~~~~~~~~
 Content: (content)
 Argv: (foo=bar)
@@ -53,6 +51,4 @@
 Content: (content)
 Argv: (x=y)
 
-
-
-(No interpreter found: phutil_fake_test_block_interpreter)
+phutil_fake_test_block_interpreter {{{ content }}}
diff --git a/src/infrastructure/markup/view/PHUIRemarkupView.php b/src/infrastructure/markup/view/PHUIRemarkupView.php
--- a/src/infrastructure/markup/view/PHUIRemarkupView.php
+++ b/src/infrastructure/markup/view/PHUIRemarkupView.php
@@ -85,7 +85,7 @@
 
     $content = PhabricatorMarkupEngine::renderOneObject(
       $oneoff,
-      'default',
+      'remarkupField',
       $viewer,
       $context);
 
diff --git a/webroot/rsrc/css/application/diffusion/diffusion-repository.css b/webroot/rsrc/css/application/diffusion/diffusion-repository.css
--- a/webroot/rsrc/css/application/diffusion/diffusion-repository.css
+++ b/webroot/rsrc/css/application/diffusion/diffusion-repository.css
@@ -11,3 +11,40 @@
   .diffusion-panel-header-view.phui-header-shell {
     padding: 8px 4px 8px 16px;
 }
+
+.collapsible {
+  background-color: {$blue.button.color};
+  border: none;
+  color: {$alphawhite};
+  cursor: pointer;
+  font-size: {$biggerfontsize};
+  outline: none;
+  padding: 18px;
+  text-align: left;
+  width: 100%;
+}
+
+.collapsible:hover {
+  background-color: {$blue.button.hover};
+}
+
+.collapsible-content {
+  background-color: {$lightgreybackground};
+  display: none;
+  overflow: hidden;
+  padding: 0 18px;
+}
+
+.collapsible-content.collapsible-content-open {
+  display: block;
+}
+
+/* The "first element" in a Remarkup page receives a "margin-top: 0".
+   This is normally OK, but ugly for the TOC, so we restore it.
+   That "first element" selector is very specific, so, it's aggressive,
+   so, we need important.
+   The "margin-bottom" is copied since the inherited value may change. */
+.collapsible-content > ul.remarkup-list {
+  margin-top: 12px !important;
+  margin-bottom: 12px;
+}
diff --git a/webroot/rsrc/externals/javelin/docs/concepts/behaviors.diviner b/webroot/rsrc/externals/javelin/docs/concepts/behaviors.diviner
--- a/webroot/rsrc/externals/javelin/docs/concepts/behaviors.diviner
+++ b/webroot/rsrc/externals/javelin/docs/concepts/behaviors.diviner
@@ -38,7 +38,7 @@
 
   lang=php
   $config = array('hogName' => 'Ethel');
-  JavelinHelper::initBehaviors('win-a-hog', $config);
+  Javelin::initBehavior('win-a-hog', $config);
 
 Regardless, this will alert the user that they've won a hog (named Ethel, which
 is a good name for a hog) when they load the page.
diff --git a/webroot/rsrc/js/application/diffusion/collapsible-container.js b/webroot/rsrc/js/application/diffusion/collapsible-container.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/application/diffusion/collapsible-container.js
@@ -0,0 +1,22 @@
+/**
+ * @provides javelin-behavior-diffusion-collapsible-container
+ * @requires javelin-behavior
+ *           javelin-dom
+ */
+
+JX.behavior('diffusion-collapsible-container', function(config, statics) {
+  var open = false;
+  JX.Stratcom.listen(
+    'click',
+    'id:' + config.toggle_button_id,
+    function(e) {
+      var btnNode = JX.$(config.toggle_button_id);
+      var btnLabel = JX.DOM.find(btnNode, 'span', 'collapsible-toggler-label');
+      var containerNode = JX.$(config.container_id);
+      open = !open;
+      JX.DOM.alterClass(containerNode, 'collapsible-content-open', open);
+      // If element is open, set the button text for closing it, and vice-versa.
+      btnLabel.innerText = config.i18n[open ? 'btn_close' : 'btn_open'];
+    }
+  );
+});