Skip to content

Commit ce46599

Browse files
authored
Rollup merge of rust-lang#7279 - xFrednet:7172-adapt-website-to-new-format, r=flip1995
Adapting the lint list to Clippy's new metadata format This is close to the end of a long living project to rewrite the lint metadata collection for Clippy. Progress on this has been tracked in rust-lang#7172. This PR adds one of the last missing puzzle pieces, the actual display of all the changes that have been done in the background. A preview can be seen here: [Clippy's lint list](https://xfrednet.github.io/rust-clippy/master/index.html) The styling has been discussed on [zulip](https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Styling.20feedback.20for.20Clippy's.20lint.20list/near/239601067) but is still open to suggestion. Side note: It has been fun working on the website where we don't have unit tests and everything is just tested by playing around. However, it's good that this chaos is contained into this one part of Clippy. 🐛 --- Closes: rust-lang#1303 Closes: rust-lang#4310 This actually closes fewer things than I thought it would... changelog: Reworked Clippy's [website](https://rust-lang.github.io/rust-clippy/master/index.html): changelog: * Added applicability information about lints changelog: * Added a link to jump to the specific lint implementation changelog: * Adapted some styling and improved loading time r? `@flip1995`
2 parents ac0fd99 + 322a768 commit ce46599

File tree

2 files changed

+172
-63
lines changed

2 files changed

+172
-63
lines changed

clippy_lints/src/utils/internal_lints/metadata_collector.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "Cl
114114

115115
/// The index of the applicability name of `paths::APPLICABILITY_VALUES`
116116
const APPLICABILITY_NAME_INDEX: usize = 2;
117+
/// This applicability will be set for unresolved applicability values.
118+
const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved";
117119

118120
declare_clippy_lint! {
119121
/// **What it does:** Collects metadata about clippy lints for the website.
@@ -192,7 +194,7 @@ impl Drop for MetadataCollector {
192194
let mut lints = std::mem::take(&mut self.lints).into_sorted_vec();
193195
lints
194196
.iter_mut()
195-
.for_each(|x| x.applicability = applicability_info.remove(&x.id));
197+
.for_each(|x| x.applicability = Some(applicability_info.remove(&x.id).unwrap_or_default()));
196198

197199
// Outputting
198200
if Path::new(OUTPUT_FILE).exists() {
@@ -208,7 +210,7 @@ struct LintMetadata {
208210
id: String,
209211
id_span: SerializableSpan,
210212
group: String,
211-
level: &'static str,
213+
level: String,
212214
docs: String,
213215
/// This field is only used in the output and will only be
214216
/// mapped shortly before the actual output.
@@ -221,7 +223,7 @@ impl LintMetadata {
221223
id,
222224
id_span,
223225
group,
224-
level,
226+
level: level.to_string(),
225227
docs,
226228
applicability: None,
227229
}
@@ -269,14 +271,16 @@ impl Serialize for ApplicabilityInfo {
269271
where
270272
S: Serializer,
271273
{
272-
let index = self.applicability.unwrap_or_default();
273-
274274
let mut s = serializer.serialize_struct("ApplicabilityInfo", 2)?;
275275
s.serialize_field("is_multi_part_suggestion", &self.is_multi_part_suggestion)?;
276-
s.serialize_field(
277-
"applicability",
278-
&paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX],
279-
)?;
276+
if let Some(index) = self.applicability {
277+
s.serialize_field(
278+
"applicability",
279+
&paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX],
280+
)?;
281+
} else {
282+
s.serialize_field("applicability", APPLICABILITY_UNRESOLVED_STR)?;
283+
}
280284
s.end()
281285
}
282286
}
@@ -486,6 +490,13 @@ fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<St
486490
/// ```
487491
///
488492
/// Would result in `Hello world!\n=^.^=\n`
493+
///
494+
/// ---
495+
///
496+
/// This function may modify the doc comment to ensure that the string can be displayed using a
497+
/// markdown viewer in Clippy's lint list. The following modifications could be applied:
498+
/// * Removal of leading space after a new line. (Important to display tables)
499+
/// * Ensures that code blocks only contain language information
489500
fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
490501
let attrs = cx.tcx.hir().attrs(item.hir_id());
491502
let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
@@ -510,7 +521,12 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
510521
continue;
511522
}
512523
}
513-
docs.push_str(line);
524+
// This removes the leading space that the macro translation introduces
525+
if let Some(stripped_doc) = line.strip_prefix(' ') {
526+
docs.push_str(stripped_doc);
527+
} else if !line.is_empty() {
528+
docs.push_str(line);
529+
}
514530
}
515531
Some(docs)
516532
}

util/gh-pages/index.html

+146-53
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
<!DOCTYPE html>
2+
<!--
3+
Welcome to a Clippy's lint list, at least the source code of it. If you are
4+
interested in contributing to this website checkout `util/gh-pages/index.html`
5+
inside the rust-clippy repository.
6+
7+
Otherwise, have a great day =^.^=
8+
-->
29
<html lang="en">
310
<head>
411
<meta charset="UTF-8"/>
512
<meta name="viewport" content="width=device-width, initial-scale=1"/>
613

7-
<title>ALL the Clippy Lints</title>
14+
<title>Clippy Lints</title>
815

916
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css"/>
1017
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/styles/github.min.css"/>
@@ -22,15 +29,95 @@
2229

2330
.panel-heading { cursor: pointer; }
2431

25-
.panel-title { display: flex; }
32+
.panel-title { display: flex; flex-wrap: wrap;}
2633
.panel-title .label { display: inline-block; }
2734

28-
.panel-title-name { flex: 1; }
35+
.panel-title-name { flex: 1; min-width: 400px;}
2936
.panel-title-name span { vertical-align: bottom; }
3037

3138
.panel .panel-title-name .anchor { display: none; }
3239
.panel:hover .panel-title-name .anchor { display: inline;}
3340

41+
.label {
42+
padding-top: 0.3em;
43+
padding-bottom: 0.3em;
44+
}
45+
46+
.label-lint-group {
47+
min-width: 8em;
48+
}
49+
.label-lint-level {
50+
min-width: 4em;
51+
}
52+
53+
.label-lint-level-allow {
54+
background-color: #5cb85c;
55+
}
56+
.label-lint-level-warn {
57+
background-color: #f0ad4e;
58+
}
59+
.label-lint-level-deny {
60+
background-color: #d9534f;
61+
}
62+
.label-lint-level-none {
63+
background-color: #777777;
64+
opacity: 0.5;
65+
}
66+
67+
.label-group-deprecated {
68+
opacity: 0.5;
69+
}
70+
71+
.label-doc-folding {
72+
color: #000;
73+
background-color: #fff;
74+
border: 1px solid var(--theme-popup-border);
75+
}
76+
.label-doc-folding:hover {
77+
background-color: #e6e6e6;
78+
}
79+
80+
.lint-doc-md > h3 {
81+
border-top: 1px solid var(--theme-popup-border);
82+
padding: 10px 15px;
83+
margin: 0 -15px;
84+
font-size: 18px;
85+
}
86+
.lint-doc-md > h3:first-child {
87+
border-top: none;
88+
padding-top: 0px;
89+
}
90+
91+
@media (max-width:749px) {
92+
.lint-additional-info-container {
93+
display: flex;
94+
flex-flow: column;
95+
}
96+
.lint-additional-info-item + .lint-additional-info-item {
97+
border-top: 1px solid var(--theme-popup-border);
98+
}
99+
}
100+
@media (min-width:750px) {
101+
.lint-additional-info-container {
102+
display: flex;
103+
flex-flow: row;
104+
}
105+
.lint-additional-info-item + .lint-additional-info-item {
106+
border-left: 1px solid var(--theme-popup-border);
107+
}
108+
}
109+
110+
.lint-additional-info-item {
111+
display: inline-flex;
112+
min-width: 200px;
113+
flex-grow: 1;
114+
padding: 9px 5px 5px 15px;
115+
}
116+
117+
.label-applicability {
118+
background-color: #777777;
119+
margin: auto 5px;
120+
}
34121
</style>
35122
<style>
36123
/* Expanding the mdBoom theme*/
@@ -159,7 +246,7 @@
159246

160247
<div class="container" ng-app="clippy" ng-controller="lintList">
161248
<div class="page-header">
162-
<h1>ALL the Clippy Lints</h1>
249+
<h1>Clippy Lints</h1>
163250
</div>
164251

165252
<noscript>
@@ -181,9 +268,12 @@ <h1>ALL the Clippy Lints</h1>
181268
<div class="panel-body row filter-panel">
182269
<div class="col-md-6 form-inline">
183270
<div class="form-group form-group-lg">
184-
<p class="h4">Lint levels</p>
271+
<p class="h4">
272+
Lint levels
273+
<a href="https://doc.rust-lang.org/rustc/lints/levels.html">(?)</a>
274+
</p>
185275
<div class="checkbox" ng-repeat="(level, enabled) in levels">
186-
<label>
276+
<label class="text-capitalize">
187277
<input type="checkbox" ng-model="levels[level]" />
188278
{{level}}
189279
</label>
@@ -192,7 +282,10 @@ <h1>ALL the Clippy Lints</h1>
192282
</div>
193283
<div class="col-md-6 form-inline">
194284
<div class="form-group form-group-lg">
195-
<p class="h4">Lint groups</p>
285+
<p class="h4">
286+
Lint groups
287+
<a href="https://github.com/rust-lang/rust-clippy/#clippy">(?)</a>
288+
</p>
196289
<div class="checkbox" ng-repeat="(group, enabled) in groups">
197290
<label class="text-capitalize">
198291
<input type="checkbox" ng-model="groups[group]" />
@@ -216,9 +309,8 @@ <h1>ALL the Clippy Lints</h1>
216309
</div>
217310
</div>
218311
</div>
219-
220-
<article class="panel panel-default" id="{{lint.id}}"
221-
ng-repeat="lint in data | filter:byLevels | filter:byGroups | filter:bySearch | orderBy:'id' track by lint.id">
312+
<!-- The order of the filters should be from most likely to remove a lint to least likely to improve performance. -->
313+
<article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels">
222314
<header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]">
223315
<h2 class="panel-title">
224316
<div class="panel-title-name">
@@ -227,29 +319,36 @@ <h2 class="panel-title">
227319
</div>
228320

229321
<div class="panel-title-addons">
230-
<span class="label label-default text-capitalize">{{lint.group}}</span>
322+
<span class="label label-lint-group label-default label-group-{{lint.group}}">{{lint.group}}</span>
323+
324+
<span class="label label-lint-level label-lint-level-{{lint.level}}">{{lint.level}}</span>
231325

232-
<span ng-if="lint.level == 'Allow'" class="label label-success">Allow</span>
233-
<span ng-if="lint.level == 'Warn'" class="label label-warning">Warn</span>
234-
<span ng-if="lint.level == 'Deny'" class="label label-danger">Deny</span>
235-
<span ng-if="lint.level == 'Deprecated'" class="label label-default">Deprecated</span>
236326

237-
<button class="btn btn-default btn-xs">
238-
<span ng-show="open[lint.id]">&minus;</span>
239-
<span ng-hide="open[lint.id]">&plus;</span>
240-
</button>
327+
<span class="label label-doc-folding" ng-show="open[lint.id]">&minus;</span>
328+
<span class="label label-doc-folding" ng-hide="open[lint.id]">&plus;</span>
241329
</div>
242330
</h2>
243331
</header>
244332

245-
<ul class="list-group lint-docs" ng-if="lint.docs" ng-class="{collapse: true, in: open[lint.id]}">
246-
<li class="list-group-item" ng-repeat="(title, text) in lint.docs">
247-
<h4 class="list-group-item-heading">
248-
{{title}}
249-
</h4>
250-
<div class="list-group-item-text" ng-bind-html="text | markdown"></div>
251-
<a ng-if="title == 'Known problems'" href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+is%3Aopen+{{lint.id}}">Search on GitHub</a>
252-
</li>
333+
<ul class="list-group lint-docs" ng-class="{collapse: true, in: open[lint.id]}">
334+
<div class="list-group-item lint-doc-md" ng-bind-html="lint.docs | markdown"></div>
335+
<div class="lint-additional-info-container">
336+
<!-- Applicability -->
337+
<div class="lint-additional-info-item">
338+
<span> Applicability: </span>
339+
<span class="label label-default label-applicability">{{lint.applicability.applicability}}</span>
340+
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a>
341+
</div>
342+
<!-- TODO xFrednet 2021-05-19: Somehow collect and show the version See rust-clippy#6492 -->
343+
<!-- Open related issues -->
344+
<div class="lint-additional-info-item">
345+
<a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
346+
</div>
347+
<!-- Jump to source -->
348+
<div class="lint-additional-info-item">
349+
<a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/clippy_lints/{{lint.id_span.path}}#L{{lint.id_span.line}}">View Source</a>
350+
</div>
351+
</div>
253352
</ul>
254353
</article>
255354
</div>
@@ -310,22 +409,6 @@ <h4 class="list-group-item-heading">
310409
}
311410
}
312411

313-
function searchLint(lint, term) {
314-
for (const field in lint.docs) {
315-
// Continue if it's not a property
316-
if (!lint.docs.hasOwnProperty(field)) {
317-
continue;
318-
}
319-
320-
// Return if not found
321-
if (lint.docs[field].toLowerCase().indexOf(term) !== -1) {
322-
return true;
323-
}
324-
}
325-
326-
return false;
327-
}
328-
329412
angular.module("clippy", [])
330413
.filter('markdown', function ($sce) {
331414
return function (text) {
@@ -350,13 +433,25 @@ <h4 class="list-group-item-heading">
350433
})
351434
.controller("lintList", function ($scope, $http, $timeout) {
352435
// Level filter
353-
var LEVEL_FILTERS_DEFAULT = {Allow: true, Warn: true, Deny: true, Deprecated: true};
436+
var LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
354437
$scope.levels = LEVEL_FILTERS_DEFAULT;
355438
$scope.byLevels = function (lint) {
356439
return $scope.levels[lint.level];
357440
};
358441

359-
$scope.groups = {};
442+
var GROUPS_FILTER_DEFAULT = {
443+
cargo: true,
444+
complexity: true,
445+
correctness: true,
446+
deprecated: false,
447+
nursery: true,
448+
pedantic: true,
449+
perf: true,
450+
restriction: true,
451+
style: true,
452+
suspicious: true,
453+
};
454+
$scope.groups = GROUPS_FILTER_DEFAULT;
360455
$scope.byGroups = function (lint) {
361456
return $scope.groups[lint.group];
362457
};
@@ -377,12 +472,14 @@ <h4 class="list-group-item-heading">
377472
// Search the description
378473
// The use of `for`-loops instead of `foreach` enables us to return early
379474
let terms = searchStr.split(" ");
475+
let docsLowerCase = lint.docs.toLowerCase();
380476
for (index = 0; index < terms.length; index++) {
381-
if (lint.id.indexOf(terms[index]) !== -1) {
477+
// This is more likely and will therefor be checked first
478+
if (docsLowerCase.indexOf(terms[index]) !== -1) {
382479
continue;
383480
}
384481

385-
if (searchLint(lint, terms[index])) {
482+
if (lint.id.indexOf(terms[index]) !== -1) {
386483
continue;
387484
}
388485

@@ -395,6 +492,8 @@ <h4 class="list-group-item-heading">
395492
// Get data
396493
$scope.open = {};
397494
$scope.loading = true;
495+
// This will be used to jump into the source code of the version that this documentation is for.
496+
$scope.docVersion = window.location.pathname.split('/')[2] || "master";
398497

399498
if (window.location.hash.length > 1) {
400499
$scope.search = window.location.hash.slice(1);
@@ -407,12 +506,6 @@ <h4 class="list-group-item-heading">
407506
$scope.data = data;
408507
$scope.loading = false;
409508

410-
// Initialize lint groups (the same structure is also used to enable filtering)
411-
$scope.groups = data.reduce(function (result, val) {
412-
result[val.group] = true;
413-
return result;
414-
}, {});
415-
416509
var selectedGroup = getQueryVariable("sel");
417510
if (selectedGroup) {
418511
selectGroup($scope, selectedGroup.toLowerCase());

0 commit comments

Comments
 (0)