* Adds query param for version no This adds support for using a query parameter for selecting the version no * Adds error handling to configuration request Catch request exception in case fetching the configuration from the url fails, this can happen either if non existent version number is passed in or because of server issues. * Makes version selection better Covers a few common cases in which the version number can be specified.
234 lines
9.5 KiB
HTML
234 lines
9.5 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<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) {
|
|
.markdown-body {
|
|
padding: 15px;
|
|
}
|
|
|
|
#search {
|
|
max-width: 85%;
|
|
}
|
|
}
|
|
body {
|
|
overflow: scroll;
|
|
}
|
|
.markdown-body {
|
|
box-sizing: border-box;
|
|
min-width: 200px;
|
|
max-width: 980px;
|
|
margin: 0 auto;
|
|
padding: 45px;
|
|
}
|
|
#search {
|
|
border: 1px solid #d1d5da;
|
|
padding-left: 30px;
|
|
overflow: hidden;
|
|
}
|
|
.searchCondition {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
.searchCondition > div {
|
|
margin-right: 30px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<article class="markdown-body">
|
|
<div class="searchCondition">
|
|
<div>
|
|
<form style="display:flex;">
|
|
<label for="search" style="margin-right: 3px;" >search:</label>
|
|
<div style="position: relative;">
|
|
<input id="search" placeholder="Search all options" v-model="searchCondition">
|
|
<svg style="position: absolute; left: 8px; top: 7px;" class="octicon octicon-search subnav-search-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true">
|
|
<path fill-rule="evenodd" d="M15.7 13.3l-3.81-3.83A5.93 5.93 0 0 0 13 6c0-3.31-2.69-6-6-6S1 2.69 1 6s2.69 6 6 6c1.3 0 2.48-.41 3.47-1.11l3.83 3.81c.19.2.45.3.7.3.25 0 .52-.09.7-.3a.996.996 0 0 0 0-1.41v.01zM7 10.7c-2.59 0-4.7-2.11-4.7-4.7 0-2.59 2.11-4.7 4.7-4.7 2.59 0 4.7 2.11 4.7 4.7 0 2.59-2.11 4.7-4.7 4.7z"></path>
|
|
</svg>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div>
|
|
<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 RusfmtTagsUrl = 'https://api.github.com/repos/rust-lang/rustfmt/tags';
|
|
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: {
|
|
aboutHtml: '',
|
|
configurationAboutHtml: '',
|
|
configurationDescriptions: [],
|
|
searchCondition: searchTerm,
|
|
shouldStable: false,
|
|
version: versionNumber,
|
|
oldVersion: undefined,
|
|
versionOptions: ['master']
|
|
},
|
|
asyncComputed: {
|
|
async outputHtml() {
|
|
if (this.version !== this.oldVersion) {
|
|
const ConfigurationMdUrl =
|
|
`https://raw.githubusercontent.com/rust-lang/rustfmt/${this.version}/Configurations.md`;
|
|
try {
|
|
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;
|
|
this.oldVersion = this.version;
|
|
} catch(error) {
|
|
this.aboutHtml = "<p>Failed to get configuration options for this version, please select the version from the dropdown above.</p>";
|
|
}
|
|
}
|
|
|
|
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);
|
|
}, []);
|
|
ast.links = {};
|
|
|
|
return marked.parser(ast, {
|
|
highlight(code, lang) {
|
|
return hljs.highlight(lang ? lang : 'rust', code).value;
|
|
},
|
|
headerIds: true,
|
|
headerPrefix: ''
|
|
});
|
|
}
|
|
},
|
|
created: async function() {
|
|
const {data: tags} = await axios.get(RusfmtTagsUrl);
|
|
const reMajorVersion = /v(\d+)/;
|
|
const tagOptions = tags
|
|
.map(tag => tag.name)
|
|
.filter(tag => tag.startsWith('v'));
|
|
this.versionOptions = this.versionOptions.concat(tagOptions);
|
|
},
|
|
mounted() {
|
|
if (UrlHash === '') return;
|
|
const interval = setInterval(() => {
|
|
const target = document.querySelector(`#${UrlHash}`);
|
|
if (target != null) {
|
|
target.scrollIntoView(true);
|
|
clearInterval(interval);
|
|
}
|
|
}, 100);
|
|
}
|
|
});
|
|
const extractDepthOnes = (ast) => {
|
|
return ast.reduce((stack, next) => {
|
|
if (next.depth === 1) {
|
|
stack.push([]);
|
|
}
|
|
const lastIndex = stack.length - 1;
|
|
stack[lastIndex].push(next);
|
|
return stack;
|
|
}, []);
|
|
}
|
|
const extractDepthTwos = (ast) => {
|
|
return ast.map((elem) => {
|
|
return elem.reduce((stack, next) => {
|
|
if (next.depth === 2) {
|
|
stack.push([]);
|
|
}
|
|
const lastIndex = stack.length - 1;
|
|
stack[lastIndex].push(next);
|
|
return stack;
|
|
},
|
|
[[]]);
|
|
});
|
|
}
|
|
const createHeadAndValue = (ast) => {
|
|
return ast.map((elem) => {
|
|
return elem.map((val) => {
|
|
return {
|
|
head: val[0].text,
|
|
value: val,
|
|
stable: val.some((elem) => {
|
|
return elem.type === "list" &&
|
|
!!elem.raw &&
|
|
elem.raw.includes("**Stable**: Yes");
|
|
}),
|
|
text: val.reduce((result, next) => {
|
|
return next.text != null
|
|
? `${result} ${next.text}`
|
|
: result;
|
|
}, '')
|
|
}
|
|
});
|
|
})
|
|
}
|
|
const parseMarkdownAst = (rawMarkdown) => {
|
|
const ast = marked.lexer(rawMarkdown);
|
|
const depthOnes = extractDepthOnes(ast);
|
|
const depthTwos = extractDepthTwos(depthOnes);
|
|
const [
|
|
abouts, configurations
|
|
] = createHeadAndValue(depthTwos);
|
|
const about = abouts[0].value;
|
|
about.links = {};
|
|
const [
|
|
configurationAbout, ...configurationDescriptions
|
|
] = configurations;
|
|
configurationAbout.value.links = {};
|
|
|
|
return {
|
|
about,
|
|
configurationAbout: configurationAbout.value,
|
|
configurationDescriptions
|
|
};
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|