Skip to content

Commit 9e1a957

Browse files
committed
syntax highlighting - closes #4
1 parent e82b767 commit 9e1a957

File tree

10 files changed

+209
-106
lines changed

10 files changed

+209
-106
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"dependencies": {
2727
"marked": "^4.0.15",
2828
"monaco-editor": "^0.33.0",
29+
"prism-svelte": "^0.5.0",
30+
"prismjs": "^1.28.0",
2931
"ws": "^8.6.0"
3032
},
3133
"pnpm": {

pnpm-lock.yaml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/client/viewer/Viewer.svelte

Lines changed: 0 additions & 54 deletions
This file was deleted.

src/lib/server/content.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3-
import { marked } from 'marked';
3+
import { transform } from './markdown.js';
44

55
const text_files = new Set([
66
'.svelte',
@@ -106,7 +106,7 @@ export function get_section(slug) {
106106
slug: section.slug,
107107
prev: section.prev,
108108
next: section.next,
109-
html: marked(section.markdown), // TODO syntax highlighting
109+
html: transform(section.markdown), // TODO syntax highlighting
110110
a,
111111
b
112112
};

src/lib/server/markdown.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import PrismJS from 'prismjs';
2+
import 'prismjs/components/prism-bash.js';
3+
import 'prismjs/components/prism-diff.js';
4+
import 'prismjs/components/prism-typescript.js';
5+
import 'prism-svelte';
6+
import { marked } from 'marked';
7+
8+
const languages = {
9+
bash: 'bash',
10+
env: 'bash',
11+
html: 'markup',
12+
svelte: 'svelte',
13+
js: 'javascript',
14+
css: 'css',
15+
diff: 'diff',
16+
ts: 'typescript',
17+
'': ''
18+
};
19+
20+
marked.use({
21+
renderer: {
22+
code: (source, language, current) => {
23+
/** @type {Record<string, string>} */
24+
const options = {};
25+
26+
let html = '';
27+
28+
source = source
29+
.replace(/\/\/\/ (.+?): (.+)\n/gm, (match, key, value) => {
30+
options[key] = value;
31+
return '';
32+
})
33+
.replace(/^([\-\+])?((?: )+)/gm, (match, prefix = '', spaces) => {
34+
if (prefix && language !== 'diff') return match;
35+
36+
// for no good reason at all, marked replaces tabs with spaces
37+
let tabs = '';
38+
for (let i = 0; i < spaces.length; i += 4) {
39+
tabs += ' ';
40+
}
41+
return prefix + tabs;
42+
})
43+
.replace(/\*\\\//g, '*/');
44+
45+
if (language === 'diff') {
46+
const lines = source.split('\n').map((content) => {
47+
let type = null;
48+
if (/^[\+\-]/.test(content)) {
49+
type = content[0] === '+' ? 'inserted' : 'deleted';
50+
content = content.slice(1);
51+
}
52+
53+
return {
54+
type,
55+
content
56+
};
57+
});
58+
59+
html = `<div class="code-block"><pre class="language-diff"><code>${lines
60+
.map((line) => {
61+
if (line.type) return `<span class="${line.type}">${line.content}\n</span>`;
62+
return line.content + '\n';
63+
})
64+
.join('')}</code></pre></div>`;
65+
} else {
66+
const plang = languages[language];
67+
const highlighted = plang
68+
? PrismJS.highlight(source, PrismJS.languages[plang], language)
69+
: source.replace(/[&<>]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]));
70+
71+
html = `<div class="code-block">${
72+
options.file ? `<h5>${options.file}</h5>` : ''
73+
}<pre class='language-${plang}'><code>${highlighted}</code></pre></div>`;
74+
}
75+
76+
return html.replace(
77+
/^(\s+)<span class="token comment">([\s\S]+?)<\/span>\n/gm,
78+
(match, intro_whitespace, content) => {
79+
// we use some CSS trickery to make comments break onto multiple lines while preserving indentation
80+
const lines = (intro_whitespace + content).split('\n');
81+
return lines
82+
.map((line) => {
83+
const match = /^(\s*)(.*)/.exec(line);
84+
const indent = (match[1] ?? '').replace(/\t/g, ' ').length;
85+
86+
return `<span class="token comment wrapped" style="--indent: ${indent}ch">${
87+
line ?? ''
88+
}</span>`;
89+
})
90+
.join('');
91+
}
92+
);
93+
}
94+
}
95+
});
96+
97+
/** @param {string} markdown */
98+
export function transform(markdown) {
99+
return marked(markdown);
100+
}

src/routes/__layout.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
<script>
1414
import '@sveltejs/site-kit/base.css';
15+
import '@sveltejs/site-kit/code.css';
1516
import { page, navigating } from '$app/stores';
1617
import { Icon, Icons, Nav, NavItem, SkipLink } from '@sveltejs/site-kit';
1718
import PreloadingIndicator from '$lib/components/PreloadingIndicator.svelte';

src/lib/client/viewer/Editor.svelte renamed to src/routes/tutorial/[slug]/_/Editor.svelte

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
let h = 0;
1616
1717
onMount(() => {
18-
editor = monaco.editor.create(container);
18+
editor = monaco.editor.create(container, {
19+
minimap: {
20+
enabled: false
21+
}
22+
});
1923
2024
return () => {
2125
editor.dispose();

src/lib/client/viewer/FileTree/File.svelte renamed to src/routes/tutorial/[slug]/_/File.svelte

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@
1313

1414
<style>
1515
button {
16-
/* padding: 0 0 0 1.5em; */
17-
/* background: 0 0.1em no-repeat; */
18-
/* background-size: 1em 1em; */
1916
padding: 0 0 0 0.2em;
2017
font-size: 1.6rem;
2118
font-family: inherit;
19+
color: var(--text);
2220
}
2321
2422
button.selected {

src/lib/client/viewer/FileTree/Folder.svelte renamed to src/routes/tutorial/[slug]/_/Folder.svelte

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
}
3030
</script>
3131

32-
<span class:expanded on:click={toggle}>{name}</span>
32+
<button class:expanded on:click={toggle}>{name}</button>
3333

3434
{#if expanded}
3535
<ul>
@@ -53,13 +53,14 @@
5353
{/if}
5454

5555
<style>
56-
span {
56+
button {
57+
font-size: 1.6rem;
58+
font-family: inherit;
59+
color: var(--text);
5760
padding: 0 0 0 1.2em;
5861
background: url(/tutorial/icons/folder.svg) 0 0.25rem no-repeat;
5962
background-size: 1.4rem 1.4rem;
60-
font-size: 1.6rem;
6163
user-select: none;
62-
/* font-weight: bold; */
6364
cursor: pointer;
6465
}
6566

0 commit comments

Comments
 (0)