about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2024-08-12 20:39:25 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2024-09-22 22:30:44 +0200
commitb522e7a944341d463bf9091bd72faffcc807d875 (patch)
treee6573de0fb3d8c6b4d93bfd5d4d88990256e6efd
parent43e338458168db91b8459735ba6ac0f230d78d92 (diff)
downloadrust-b522e7a944341d463bf9091bd72faffcc807d875.tar.gz
rust-b522e7a944341d463bf9091bd72faffcc807d875.zip
Generate lint list in HTML directly instead of JS
-rw-r--r--.github/deploy.sh1
-rw-r--r--.gitignore1
-rw-r--r--Cargo.toml2
-rw-r--r--clippy_dev/src/serve.rs2
-rw-r--r--rinja.toml8
-rw-r--r--tests/compile-test.rs33
-rw-r--r--util/gh-pages/index_template.html (renamed from util/gh-pages/index.html)103
-rw-r--r--util/gh-pages/script.js108
8 files changed, 152 insertions, 106 deletions
diff --git a/.github/deploy.sh b/.github/deploy.sh
index 5b4b4be4e36..6cebbb7801b 100644
--- a/.github/deploy.sh
+++ b/.github/deploy.sh
@@ -9,7 +9,6 @@ echo "Making the docs for master"
 mkdir out/master/
 cp util/gh-pages/index.html out/master
 cp util/gh-pages/script.js out/master
-cp util/gh-pages/lints.json out/master
 cp util/gh-pages/style.css out/master
 
 if [[ -n $TAG_NAME ]]; then
diff --git a/.gitignore b/.gitignore
index 181b71a658b..a7c25b29021 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,7 @@ out
 
 # gh pages docs
 util/gh-pages/lints.json
+util/gh-pages/index.html
 
 # rustfmt backups
 *.rs.bk
diff --git a/Cargo.toml b/Cargo.toml
index cf810798d8c..c7383520741 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,6 +39,8 @@ toml = "0.7.3"
 walkdir = "2.3"
 filetime = "0.2.9"
 itertools = "0.12"
+pulldown-cmark = "0.11"
+rinja = { version = "0.3", default-features = false, features = ["config"] }
 
 # UI test dependencies
 clippy_utils = { path = "clippy_utils" }
diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs
index cc14cd8dae6..0216d884e2d 100644
--- a/clippy_dev/src/serve.rs
+++ b/clippy_dev/src/serve.rs
@@ -19,7 +19,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
     });
 
     loop {
-        if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
+        if mtime("util/gh-pages/index.html") < mtime("clippy_lints/src") {
             Command::new(env::var("CARGO").unwrap_or("cargo".into()))
                 .arg("collect-metadata")
                 .spawn()
diff --git a/rinja.toml b/rinja.toml
new file mode 100644
index 00000000000..5fa682788bd
--- /dev/null
+++ b/rinja.toml
@@ -0,0 +1,8 @@
+[general]
+dirs = ["util/gh-pages/"]
+default_syntax = "mixed"
+
+[[syntax]]
+name = "mixed"
+expr_start = "{("
+expr_end = ")}"
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index af2aa519257..0bd6ac67770 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -8,6 +8,8 @@ use clippy_config::ClippyConfiguration;
 use clippy_lints::LintInfo;
 use clippy_lints::declared_lints::LINTS;
 use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED};
+use pulldown_cmark::{Options, Parser, html};
+use rinja::{Template, filters::Safe};
 use serde::{Deserialize, Serialize};
 use test_utils::IS_RUSTC_TEST_SUITE;
 use ui_test::custom_flags::Flag;
@@ -385,6 +387,22 @@ fn ui_cargo_toml_metadata() {
     }
 }
 
+#[derive(Template)]
+#[template(path = "index_template.html")]
+struct Renderer<'a> {
+    lints: &'a Vec<LintMetadata>,
+}
+
+impl<'a> Renderer<'a> {
+    fn markdown(&self, input: &str) -> Safe<String> {
+        let parser = Parser::new_ext(input, Options::all());
+        let mut html_output = String::new();
+        html::push_html(&mut html_output, parser);
+        // Oh deer, what a hack :O
+        Safe(html_output.replace("<table", "<table class=\"table\""))
+    }
+}
+
 #[derive(Deserialize)]
 #[serde(untagged)]
 enum DiagnosticOrMessage {
@@ -447,8 +465,7 @@ impl DiagnosticCollector {
                 .collect();
             metadata.sort_unstable_by(|a, b| a.id.cmp(&b.id));
 
-            let json = serde_json::to_string_pretty(&metadata).unwrap();
-            fs::write("util/gh-pages/lints.json", json).unwrap();
+            fs::write("util/gh-pages/index.html", Renderer { lints: &metadata }.render().unwrap()).unwrap();
         });
 
         (Self { sender }, handle)
@@ -487,7 +504,7 @@ impl Flag for DiagnosticCollector {
     }
 }
 
-#[derive(Debug, Serialize)]
+#[derive(Debug)]
 struct LintMetadata {
     id: String,
     id_location: Option<&'static str>,
@@ -559,4 +576,14 @@ impl LintMetadata {
             applicability: Applicability::Unspecified,
         }
     }
+
+    fn applicability_str(&self) -> &str {
+        match self.applicability {
+            Applicability::MachineApplicable => "MachineApplicable",
+            Applicability::HasPlaceholders => "HasPlaceholders",
+            Applicability::MaybeIncorrect => "MaybeIncorrect",
+            Applicability::Unspecified => "Unspecified",
+            _ => panic!("needs to update this code"),
+        }
+    }
 }
diff --git a/util/gh-pages/index.html b/util/gh-pages/index_template.html
index f3d7e504fdf..ee134eaaa98 100644
--- a/util/gh-pages/index.html
+++ b/util/gh-pages/index_template.html
@@ -55,16 +55,8 @@ Otherwise, have a great day =^.^=
             </div>
         </noscript>
 
-        <div ng-cloak>
-
-            <div class="alert alert-info" role="alert" ng-if="loading">
-                Loading&#x2026;
-            </div>
-            <div class="alert alert-danger" role="alert" ng-if="error">
-                Error loading lints!
-            </div>
-
-            <div class="panel panel-default" ng-show="data">
+        <div>
+            <div class="panel panel-default">
                 <div class="panel-body row">
                     <div id="upper-filters" class="col-12 col-md-5">
                         <div class="btn-group" filter-dropdown>
@@ -188,9 +180,7 @@ Otherwise, have a great day =^.^=
                     <div class="col-12 col-md-5 search-control">
                         <div class="input-group">
                             <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label>
-                            <input type="text" class="form-control filter-input" placeholder="Keywords or search string (`S` or `/` to focus)" id="search-input"
-                                ng-model="search" ng-blur="updatePath()" ng-keyup="$event.keyCode == 13 && updatePath()"
-                                ng-model-options="{debounce: 50}" />
+                            <input type="text" class="form-control filter-input" placeholder="Keywords or search string (`S` or `/` to focus)" id="search-input" onblur="updatePath()" onchange="handleInputChanged()" />
                             <span class="input-group-btn">
                                 <button class="filter-clear btn" type="button" ng-click="search = ''; updatePath();">
                                     Clear
@@ -208,56 +198,57 @@ Otherwise, have a great day =^.^=
                     </div>
                 </div>
             </div>
-            <!-- The order of the filters should be from most likely to remove a lint to least likely to improve performance. -->
-            <article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels | filter:byVersion | filter:byApplicabilities">
-                <header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]">
-                    <h2 class="panel-title">
-                        <div class="panel-title-name">
-                            <span>{{lint.id}}</span>
-                            <a href="#{{lint.id}}" class="anchor label label-default"
-                                ng-click="openLint(lint); $event.preventDefault(); $event.stopPropagation()">&para;</a>
-                            <a href="" id="clipboard-{{lint.id}}" class="anchor label label-default" ng-click="copyToClipboard(lint); $event.stopPropagation()">
-                                &#128203;
-                            </a>
-                        </div>
+            {% for lint in lints %}
+                <article class="panel panel-default" id="{{lint.id}}">
+                    <header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]">
+                        <h2 class="panel-title">
+                            <div class="panel-title-name">
+                                <span>{(lint.id)}</span>
+                                <a href="#{{lint.id}}" class="anchor label label-default"
+                                    ng-click="openLint(lint); $event.preventDefault(); $event.stopPropagation()">&para;</a>
+                                <a href="" id="clipboard-{{lint.id}}" class="anchor label label-default" ng-click="copyToClipboard(lint); $event.stopPropagation()">
+                                    &#128203;
+                                </a>
+                            </div>
 
-                        <div class="panel-title-addons">
-                            <span class="label label-lint-group label-default label-group-{{lint.group}}">{{lint.group}}</span>
+                            <div class="panel-title-addons">
+                                <span class="label label-lint-group label-default label-group-{{lint.group}}">{(lint.group)}</span>
 
-                            <span class="label label-lint-level label-lint-level-{{lint.level}}">{{lint.level}}</span>
+                                <span class="label label-lint-level label-lint-level-{{lint.level}}">{(lint.level)}</span>
 
 
-                            <span class="label label-doc-folding" ng-show="open[lint.id]">&minus;</span>
-                            <span class="label label-doc-folding" ng-hide="open[lint.id]">&plus;</span>
-                        </div>
-                    </h2>
-                </header>
+                                <span class="label label-doc-folding" ng-show="open[lint.id]">&minus;</span>
+                                <span class="label label-doc-folding" ng-hide="open[lint.id]">&plus;</span>
+                            </div>
+                        </h2>
+                    </header>
 
-                <div class="list-group lint-docs" ng-if="open[lint.id]" ng-class="{collapse: true, in: open[lint.id]}">
-                    <div class="list-group-item lint-doc-md" ng-bind-html="lint.docs | markdown"></div>
-                    <div class="lint-additional-info-container">
-                        <!-- Applicability -->
-                        <div class="lint-additional-info-item">
-                            <span> Applicability: </span>
-                            <span class="label label-default label-applicability">{{lint.applicability}}</span>
-                            <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a>
-                        </div>
-                        <!-- Clippy version -->
-                        <div class="lint-additional-info-item">
-                            <span>{{lint.group == "deprecated" ? "Deprecated" : "Added"}} in: </span>
-                            <span class="label label-default label-version">{{lint.version}}</span>
-                        </div>
-                        <!-- Open related issues -->
-                        <div class="lint-additional-info-item">
-                            <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
-                        </div>
-                        <!-- Jump to source -->
-                        <div class="lint-additional-info-item" ng-if="lint.id_location">
-                            <a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/{{lint.id_location}}">View Source</a>
+                    <div class="list-group lint-docs" ng-class="{collapse: true, in: open[lint.id]}">
+                        <div class="list-group-item lint-doc-md">{(markdown(lint.docs))}</div>
+                        <div class="lint-additional-info-container">
+                            {# Applicability #}
+                            <div class="lint-additional-info-item">
+                                <span> Applicability: </span>
+                                <span class="label label-default label-applicability">{( lint.applicability_str() )}</span>
+                                <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a>
+                            </div>
+                            <!-- Clippy version -->
+                            <div class="lint-additional-info-item">
+                                <span>{% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif %} in: </span>
+                                <span class="label label-default label-version">{(lint.version)}</span>
+                            </div>
+                            <!-- Open related issues -->
+                            <div class="lint-additional-info-item">
+                                <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
+                            </div>
+                            <!-- Jump to source -->
+                            <div class="lint-additional-info-item" ng-if="lint.id_location">
+                                <a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/clippy_lints/{{lint.id_location.path}}">View Source</a>
+                            </div>
                         </div>
                     </div>
-                </div>
-            </article>
+                </article>
+            {% endfor %}
         </div>
     </div>
 
diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js
index 1a5330bc0e5..8942628d5da 100644
--- a/util/gh-pages/script.js
+++ b/util/gh-pages/script.js
@@ -1,21 +1,4 @@
 (function () {
-    const md = window.markdownit({
-        html: true,
-        linkify: true,
-        typographer: true,
-        highlight: function (str, lang) {
-            if (lang && hljs.getLanguage(lang)) {
-                try {
-                    return '<pre class="hljs"><code>' +
-                        hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
-                        '</code></pre>';
-                } catch (__) {}
-            }
-
-            return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
-        }
-    });
-
     function scrollToLint(lintId) {
         const target = document.getElementById(lintId);
         if (!target) {
@@ -41,15 +24,6 @@
     }
 
     angular.module("clippy", [])
-        .filter('markdown', function ($sce) {
-            return function (text) {
-                return $sce.trustAsHtml(
-                    md.render(text || '')
-                        // Oh deer, what a hack :O
-                        .replace('<table', '<table class="table"')
-                );
-            };
-        })
         .directive('filterDropdown', function ($document) {
             return {
                 restrict: 'A',
@@ -470,27 +444,17 @@
             // Set up the filters from the URL parameters before we start loading the data
             loadFromURLParameters();
 
-            $http.get('./lints.json')
-                .success(function (data) {
-                    $scope.data = data;
-                    $scope.loading = false;
-
-                    const selectedGroup = getQueryVariable("sel");
-                    if (selectedGroup) {
-                        selectGroup($scope, selectedGroup.toLowerCase());
-                    }
+            const selectedGroup = getQueryVariable("sel");
+            if (selectedGroup) {
+                selectGroup($scope, selectedGroup.toLowerCase());
+            }
 
-                    scrollToLintByURL($scope, $location);
+            scrollToLintByURL($scope, $location);
 
-                    setTimeout(function () {
-                        const el = document.getElementById('filter-input');
-                        if (el) { el.focus() }
-                    }, 0);
-                })
-                .error(function (data) {
-                    $scope.error = data;
-                    $scope.loading = false;
-                });
+            setTimeout(function () {
+                const el = document.getElementById('filter-input');
+                if (el) { el.focus() }
+            }, 0);
         });
 })();
 
@@ -505,6 +469,58 @@ function getQueryVariable(variable) {
     }
 }
 
+window.searchState = {
+    timeout: null,
+    inputElem: document.getElementById("search-input"),
+    clearInputTimeout: () => {
+        if (searchState.timeout !== null) {
+            clearTimeout(searchState.timeout);
+            searchState.timeout = null
+        }
+    },
+    resetInputTimeout: () => {
+        searchState.clearInputTimeout();
+        setTimeout(searchState.filterLints, 50);
+    },
+    filterLints: () => {
+        let searchStr = searchState.value.trim().toLowerCase();
+        if (searchStr.startsWith("clippy::")) {
+            searchStr = searchStr.slice(8);
+        }
+        const terms = searchStr.split(" ");
+
+        onEachLazy(document.querySelectorAll("article"), lint => {
+            // Search by id
+            if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) {
+                el.style.display = "";
+                return;
+            }
+            // Search the description
+            // The use of `for`-loops instead of `foreach` enables us to return early
+            const docsLowerCase = lint.docs.toLowerCase();
+            for (index = 0; index < terms.length; index++) {
+                // This is more likely and will therefore be checked first
+                if (docsLowerCase.indexOf(terms[index]) !== -1) {
+                    continue;
+                }
+
+                if (lint.id.indexOf(terms[index]) !== -1) {
+                    continue;
+                }
+
+                return false;
+            }
+        });
+    },
+};
+
+function handleInputChanged(event) {
+    if (event.target !== document.activeElement) {
+        return;
+    }
+    searchState.resetInputTimeout();
+}
+
 function storeValue(settingName, value) {
     try {
         localStorage.setItem(`clippy-lint-list-${settingName}`, value);
@@ -627,3 +643,5 @@ if (prefersDark.matches && !theme) {
 }
 let disableShortcuts = loadValue('disable-shortcuts') === "true";
 document.getElementById("disable-shortcuts").checked = disableShortcuts;
+
+hljs.highlightAll();