4 <meta name="viewport" content="width=device-width">
6 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.css" />
7 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css">
8 <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
9 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
10 <script src="https://unpkg.com/vue-async-computed@3.8.1"></script>
11 <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"></script>
12 <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
14 @media (max-width: 767px) {
27 box-sizing: border-box;
34 border: 1px solid #d1d5da;
42 .searchCondition > div {
48 .header-link:hover::before {
52 content: '\2002\00a7\2002';
58 <article class="markdown-body">
59 <div class="searchCondition">
61 <form style="display:flex;">
62 <label for="search" style="margin-right: 3px;" >search:</label>
63 <div style="position: relative;">
64 <input id="search" placeholder="Search all options" v-model="searchCondition">
65 <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">
66 <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>
72 <label for="stable">stable: </label>
73 <input type="checkbox" id="stable" v-model="shouldStable">
76 <label for="viewVersion">version: </label>
77 <select name="viewVersion" id="viewVersion" v-model="viewVersion">
78 <option v-for="option in versionOptions" v-bind:value="option">
84 <div v-html="aboutHtml"></div>
85 <div v-html="configurationAboutHtml"></div>
86 <div v-html="outputHtml"></div>
90 const RusfmtTagsUrl = 'https://api.github.com/repos/rust-lang/rustfmt/tags';
91 const RustfmtLatestUrl = 'https://api.github.com/repos/rust-lang/rustfmt/releases/latest';
92 const UrlHash = window.location.hash.replace(/^#/, '');
93 const queryParams = new URLSearchParams(window.location.search);
94 const searchParam = queryParams.get('search');
95 const searchTerm = null !== searchParam ? searchParam : '';
96 const versionParam = queryParams.get('version');
97 const parseVersionParam = (version) => {
98 if (version === 'master') return 'master';
99 if (version.startsWith('v')) return version;
100 return `v${version}`;
102 const versionNumber = null !== versionParam ? parseVersionParam(versionParam) : 'master';
107 configurationAboutHtml: '',
108 configurationDescriptions: [],
109 searchCondition: searchTerm,
111 viewVersion: versionNumber,
112 oldViewVersion: undefined,
113 versionOptions: ['master'],
117 async updateVersion() {
120 latest = (await axios.get(RustfmtLatestUrl)).data;
125 if (versionParam == null) {
126 this.viewVersion = latest.name;
130 if (this.viewVersion !== this.oldViewVersion) {
131 const ConfigurationMdUrl =
132 `https://raw.githubusercontent.com/rust-lang/rustfmt/${this.viewVersion}/Configurations.md`;
135 res = await axios.get(ConfigurationMdUrl).catch(e => { throw e });
137 this.handleReqFailure(e);
143 configurationDescriptions
144 } = parseMarkdownAst(res.data);
145 this.aboutHtml = marked.parser(about);
146 this.configurationAboutHtml = marked.parser(configurationAbout);
147 this.configurationDescriptions = configurationDescriptions;
148 this.oldViewVersion = this.viewVersion;
151 const ast = this.configurationDescriptions
152 .filter(({ head, text, stable }) => {
153 if (text.includes(this.searchCondition) === false &&
154 head.includes(this.searchCondition) === false) {
157 return (this.shouldStable)
161 .reduce((stack, { value }) => {
162 return stack.concat(value);
166 queryParams.set('version', this.viewVersion);
167 queryParams.set('search', this.searchCondition);
168 const curUrl = window.location.pathname +
169 '?' + queryParams.toString() + window.location.hash;
170 history.pushState(null, '', curUrl);
172 const renderer = new marked.Renderer();
173 renderer.heading = function(text, level) {
174 const id = htmlToId(text);
176 <a id="${id}" href="#${id}" name="${id}" class="header-link">${text}</a>
180 return marked.parser(ast, {
181 highlight(code, lang) {
182 return hljs.highlight(lang ? lang : 'rust', code).value;
190 created: async function() {
193 tags = (await axios.get(RusfmtTagsUrl)).data;
195 this.handleReqFailure(e);
199 const excludedTagVersions = new Set(['v0.7', 'v0.8.1']);
201 const tagOptions = tags
202 .map(tag => tag.name)
203 .filter(tag => tag.startsWith('v') && !excludedTagVersions.has(tag));
204 this.versionOptions = this.versionOptions.concat(tagOptions);
207 if (UrlHash === '') return;
208 this.$nextTick(() => {
209 const target = document.querySelector(`#${UrlHash}`);
210 if (target != null && !this.scrolledOnce) {
211 target.scrollIntoView(true);
212 this.scrolledOnce = true;
217 handleReqFailure(e) {
218 if (e.response.status === 404) {
220 "<p>Failed to get configuration options for this version, please select the version from the dropdown above.</p>";
222 e.response.status === 403 &&
223 e.response.headers["X-RateLimit-Remaining"] === 0
225 const resetDate = new Date(
226 e.response.headers['X-RateLimit-Reset'] * 1000
229 `<p>You have hit the GitHub API rate limit; documentation cannot be updated.` +
230 `<p>The rate limit will be reset at ${resetDate}.</p>`;
233 `<p>Ecountered an error when fetching documentation data:</p>` +
234 `<pre><code>${e.response.data}</code></pre>` +
235 `<p>We would appreciate <a href="https://github.com/rust-lang/rustfmt/issues/new?template=bug_report.md">a bug report</a>.` +
236 `<p>Try refreshing the page.</p>`;
241 const extractDepthOnes = (ast) => {
242 return ast.reduce((stack, next) => {
243 if (next.depth === 1) {
246 const lastIndex = stack.length - 1;
247 stack[lastIndex].push(next);
251 const extractDepthTwos = (ast) => {
252 return ast.map((elem) => {
253 return elem.reduce((stack, next) => {
254 if (next.depth === 2) {
257 const lastIndex = stack.length - 1;
258 stack[lastIndex].push(next);
264 const createHeadAndValue = (ast) => {
265 return ast.map((elem) => {
266 return elem.map((val) => {
270 stable: val.some((elem) => {
271 return elem.type === "list" &&
273 elem.raw.includes("**Stable**: Yes");
275 text: val.reduce((result, next) => {
276 return next.text != null
277 ? `${result} ${next.text}`
284 const parseMarkdownAst = (rawMarkdown) => {
285 const ast = marked.lexer(rawMarkdown);
286 const depthOnes = extractDepthOnes(ast);
287 const depthTwos = extractDepthTwos(depthOnes);
289 abouts, configurations
290 ] = createHeadAndValue(depthTwos);
291 const about = abouts[0].value;
294 configurationAbout, ...configurationDescriptions
296 configurationAbout.value.links = {};
300 configurationAbout: configurationAbout.value,
301 configurationDescriptions
304 function htmlToId(text) {
305 const tmpl = document.createElement('template');
306 tmpl.innerHTML = text.trim();
307 return encodeURIComponent(CSS.escape(tmpl.content.textContent));