Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix configuration documentation site #4842

Merged
merged 13 commits into from
May 18, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 166 additions & 47 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
<head>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css">
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vue-async-computed@3.8.1"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<style>
@media (max-width: 767px) {
Expand Down Expand Up @@ -38,6 +41,15 @@
.searchCondition > div {
margin-right: 30px;
}
.header-link {
position: relative;
}
.header-link:hover::before {
position: absolute;
left: -2em;
padding-right: 0.5em;
content: '\2002\00a7\2002';
}
</style>
</head>
<body>
Expand All @@ -59,70 +71,170 @@
<label for="stable">stable: </label>
<input type="checkbox" id="stable" v-model="shouldStable">
</div>
<div>
<label for="version">version: </label>
<select name="version" id="version" v-model="version">
<option v-for="option in versionOptions" v-bind:value="option">
{{ option }}
</option>
</select>
</div>
</div>
<div v-html="aboutHtml"></div>
<div v-html="configurationAboutHtml"></div>
<div v-html="outputHtml"></div>
</article>
</div>
<script>
const ConfigurationMdUrl = 'https://raw.githubusercontent.com/rust-lang/rustfmt/master/Configurations.md';
const RusfmtTagsUrl = 'https://api.github.com/repos/rust-lang/rustfmt/tags';
const RustfmtLatestUrl = 'https://api.github.com/repos/rust-lang/rustfmt/releases/latest';
const UrlHash = window.location.hash.replace(/^#/, '');
const queryParams = new URLSearchParams(window.location.search);
const searchParam = queryParams.get('search');
const searchTerm = null !== searchParam ? searchParam : '';
const versionParam = queryParams.get('version');
const parseVersionParam = (version) => {
if (version === 'master') return 'master';
if (version.startsWith('v')) return version;
return `v${version}`;
};
const versionNumber = null !== versionParam ? parseVersionParam(versionParam) : 'master';
new Vue({
el: '#app',
data() {
const configurationDescriptions = [];
configurationDescriptions.links = {};
return {
aboutHtml: '',
configurationAboutHtml: '',
searchCondition: UrlHash,
configurationDescriptions,
shouldStable: false
}
data: {
aboutHtml: '',
configurationAboutHtml: '',
configurationDescriptions: [],
searchCondition: searchTerm,
shouldStable: false,
version: versionNumber,
oldVersion: undefined,
versionOptions: ['master'],
scrolledOnce: false,
},
computed: {
outputHtml() {
asyncComputed: {
async updateVersion() {
let latest;
try {
latest = (await axios.get(RustfmtLatestUrl)).data;
} catch(err) {
console.log(err);
return;
}
if (versionParam == null) {
this.version = latest.name;
}
},
async outputHtml() {
if (this.version !== this.oldVersion) {
const ConfigurationMdUrl =
`https://raw.githubusercontent.com/rust-lang/rustfmt/${this.version}/Configurations.md`;
let res;
try {
res = await axios.get(ConfigurationMdUrl).catch(e => { throw e });
} catch(e) {
this.handleReqFailure(e);
return;
}
const {
about,
configurationAbout,
configurationDescriptions
} = parseMarkdownAst(res.data);
this.aboutHtml = marked.parser(about);
this.configurationAboutHtml = marked.parser(configurationAbout);
this.configurationDescriptions = configurationDescriptions;
this.oldVersion = this.version;
}

const ast = this.configurationDescriptions
.filter(({ head, text, stable }) => {

if (
text.includes(this.searchCondition) === false &&
head.includes(this.searchCondition) === false
) {
return false;
}
return (this.shouldStable)
? stable === true
: true;
})
.reduce((stack, { value }) => {
return stack.concat(value);
}, []);
.filter(({ head, text, stable }) => {
if (text.includes(this.searchCondition) === false &&
head.includes(this.searchCondition) === false) {
return false;
}
return (this.shouldStable)
? stable === true
: true;
})
.reduce((stack, { value }) => {
return stack.concat(value);
}, []);
ast.links = {};
return marked.parser(ast);

queryParams.set('version', this.version);
queryParams.set('search', this.searchCondition);
const curUrl = window.location.pathname +
'?' + queryParams.toString() + window.location.hash;
history.pushState(null, '', curUrl);

const renderer = new marked.Renderer();
renderer.heading = function(text, level) {
const id = htmlToId(text);
return `<h${level}>
<a id="${id}" href="#${id}" name="${id}" class="header-link">${text}</a>
</h${level}>`;
};

return marked.parser(ast, {
highlight(code, lang) {
return hljs.highlight(lang ? lang : 'rust', code).value;
},
headerIds: true,
headerPrefix: '',
renderer,
});
}
},
created: async function() {
const res = await axios.get(ConfigurationMdUrl);
const {
about,
configurationAbout,
configurationDescriptions
} = parseMarkdownAst(res.data);
this.aboutHtml = marked.parser(about);
this.configurationAboutHtml = marked.parser(configurationAbout);
this.configurationDescriptions = configurationDescriptions;
let tags;
try {
tags = (await axios.get(RusfmtTagsUrl)).data;
} catch(e) {
this.handleReqFailure(e);
return;
}

const excludedTagVersions = new Set(['v0.7', 'v0.8.1']);

const tagOptions = tags
.map(tag => tag.name)
.filter(tag => tag.startsWith('v') && !excludedTagVersions.has(tag));
this.versionOptions = this.versionOptions.concat(tagOptions);
},
mounted() {
updated() {
if (UrlHash === '') return;
const interval = setInterval(() => {
this.$nextTick(() => {
const target = document.querySelector(`#${UrlHash}`);
if (target != null) {
if (target != null && !this.scrolledOnce) {
target.scrollIntoView(true);
clearInterval(interval);
this.scrolledOnce = true;
}
});
},
methods: {
handleReqFailure(e) {
if (e.response.status === 404) {
this.aboutHtml =
"<p>Failed to get configuration options for this version, please select the version from the dropdown above.</p>";
} else if (
e.response.status === 403 &&
e.response.headers["X-RateLimit-Remaining"] === 0
) {
const resetDate = new Date(
e.response.headers['X-RateLimit-Reset'] * 1000
).toLocaleString();
this.aboutHtml =
`<p>You have hit the GitHub API rate limit; documentation cannot be updated.` +
`<p>The rate limit will be reset at ${resetDate}.</p>`;
} else {
this.aboutHtml =
`<p>Ecountered an error when fetching documentation data:</p>` +
`<pre><code>${e.response.data}</code></pre>` +
`<p>We would appreciate <a href="https://github.com/rust-lang/rustfmt/issues/new?template=bug_report.md">a bug report</a>.` +
`<p>Try refreshing the page.</p>`;
}
}, 100);
}
}
});
const extractDepthOnes = (ast) => {
Expand All @@ -144,7 +256,7 @@
const lastIndex = stack.length - 1;
stack[lastIndex].push(next);
return stack;
},
},
[[]]);
});
}
Expand All @@ -155,7 +267,9 @@
head: val[0].text,
value: val,
stable: val.some((elem) => {
return !!elem.text && elem.text.includes("**Stable**: Yes")
return elem.type === "list" &&
!!elem.raw &&
elem.raw.includes("**Stable**: Yes");
}),
text: val.reduce((result, next) => {
return next.text != null
Expand All @@ -179,13 +293,18 @@
configurationAbout, ...configurationDescriptions
] = configurations;
configurationAbout.value.links = {};

return {
about,
configurationAbout: configurationAbout.value,
configurationDescriptions
};
}
function htmlToId(text) {
const tmpl = document.createElement('template');
tmpl.innerHTML = text.trim();
return encodeURIComponent(CSS.escape(tmpl.content.textContent));
}
</script>
</body>
</html>
</html>