Skip to content

Commit

Permalink
update author info, add code highlighting
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyx1998 committed Dec 20, 2023
1 parent c431708 commit 67e285c
Show file tree
Hide file tree
Showing 21 changed files with 172 additions and 53 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion config/config.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion config/get-title.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion config/nav.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion config/sidebar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
11 changes: 11 additions & 0 deletions config/theme/highlight.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Code block highlighting with dual color scheme
*/

html:not(.dark) div.dual-scheme>pre.scheme-dark {
display: none;
}

html.dark div.dual-scheme>pre.scheme-light {
display: none;
}
1 change: 1 addition & 0 deletions config/theme/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { h } from 'vue'
import DefaultTheme from 'vitepress/theme'
import './style.css'
import './highlight.css'

/** @type {import('vitepress').Theme} */
export default {
Expand Down
2 changes: 1 addition & 1 deletion lib/env.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion lib/output.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion lib/pool.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion lib/resource.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion lib/transform.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
19 changes: 18 additions & 1 deletion lib/traverse.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down Expand Up @@ -39,3 +39,20 @@ export default function* traverse(...nodes) {
}
}
}

/**
* Traverse the DOM tree, and yield each node in the order they appear.
* Parent nodes are yielded before their children.
* @param {Element[]} nodes
* @returns {Generator<[Element, (skip?:Boolean) => any], void, void>}
*/
export function* skippableTraverse(...nodes) {
for (const node of nodes) {
let skip = false;
yield [node, (f = true) => skip = f];
if (skip) continue;
for (const child of node?.childNodes ?? []) {
yield* skippableTraverse(child);
}
}
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"devDependencies": {
"front-matter": "^4.0.2",
"jsdom": "^23.0.1",
"lang-detector": "^1.0.6",
"shiki": "^0.14.7",
"vitepress": "^1.0.0-rc.32",
"yaml": "^2.3.4"
},
Expand All @@ -21,4 +23,4 @@
"postbuild": "tar -czf var/dist.tar.gz -C var dist",
"preview": "vitepress preview docs"
}
}
}
2 changes: 1 addition & 1 deletion setup/fetch-raw.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion setup/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
50 changes: 27 additions & 23 deletions setup/task/breakdown-article.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down Expand Up @@ -33,14 +33,7 @@ function children(node) {
else return [node];
}
}
/**
* @param {String} str
*/
function get_name(str) {
str = str.slice(str.indexOf('-') + 1);
str = str.replace(/\-+/g, s => s.length > 1 ? '-' : ' ');
return str.trim();
}

/**
* @param {HTMLElement} sec
*/
Expand Down Expand Up @@ -111,6 +104,7 @@ export default function breakdown(src_id, body, write) {
}
}
// Find names from segments
const segTitles = {};
const segNames = segments.map((seg, i) => {
const idx = `${i + 1}`.padStart(2, '0')
const title_node = seg.querySelector(
Expand All @@ -122,16 +116,21 @@ export default function breakdown(src_id, body, write) {
for (const attr of title_node.getAttributeNames())
h1.setAttribute(attr, title_node.getAttribute(attr));
title_node.parentNode.replaceChild(h1, title_node);
const title = h1.textContent
.trim()
.replace(':', '-')
const title = h1.textContent.trim();
const title_id = title
.toLowerCase()
.split('')
.filter(c => /^(\s|[a-z]|[0-9]|_|\-)$/ig.test(c))
.join('')
.slice(0, 64)
.replace(/\s+/g, '-');
if (title) return [idx, title].join('-');
if (title && title_id) {
const seg_id = [idx, title_id].join('-');
segTitles[seg_id] = title;
return seg_id;
}
}
segTitles[idx] = 'untitled';
return idx;
});
// Rewrite hash links according to hash map
Expand All @@ -140,20 +139,25 @@ export default function breakdown(src_id, body, write) {
if (!(seg_id in segNames)) continue;
node.setAttribute('href', [segNames[seg_id], id].join('#'));
}
for (const [node, id] of href_nodes(...segments)) {
const seg_id = hash_map[id];
if (seg_id === 'index')
node.setAttribute('href', ['./', id].join('#'));
else if (seg_id in segNames)
node.setAttribute('href', [segNames[seg_id], id].join('#'));
}
// Save all segments
for (const [i, seg] of segments.entries()) {
const seg_id = segNames[i];
for (const [node, id] of href_nodes(seg)) {
const target_id = hash_map[id];
// Skip if the link is in the same segment
if (target_id === seg_id) continue;
else if (target_id === 'index')
node.setAttribute('href', ['./', id].join('#'));
else if (target_id in segNames)
node.setAttribute('href', [segNames[target_id], id].join('#'));
}
// Save this segment
console.log("#", "|", '/'.padStart(src_id.length) + seg_id);
write(src_id + seg_id, seg.innerHTML, get_name(seg_id));
write(src_id + seg_id, seg.innerHTML, segTitles[seg_id]);
}
// Return index_page elements
return [index_page, segNames.map(sid => ({ link: '/' + src_id + sid, text: get_name(sid) }))];
return [index_page, segNames.map(sid => ({
link: '/' + src_id + sid,
text: segTitles[sid]
}))];
}
}
82 changes: 82 additions & 0 deletions setup/task/code-block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */

import { JSDOM } from 'jsdom';
import shiki from 'shiki';
import detectLang from 'lang-detector';

// Lazy loaded highlighter
/** @type {shiki.Highlighter} */
let __hl__;
const themes = ['light-plus', 'dark-plus'];
async function hl() {
if (!__hl__) __hl__ = await shiki.getHighlighter({
themes, langs: ['c++']
});
return __hl__;
}

/**
* @param {HTMLElement} node
* @returns
*/
export function isCodeElement(node) {
const classList = ['code', 'funcsynopsis']
for (const cls of node.classList) {
if (classList.includes(cls)) return true;
}
return false;
}
/**
* @param {HTMLPreElement} node
*/
export default async function transformCode(node) {
const text = node.textContent
.replace(/^(\s*\n)+/s, '')
.replace(/(\n\s*)+$/s, '');
const isMultiLineCode =
text.includes('\n') ||
!/^(span|a|p|label|td)$/ig.test(node.parentElement.tagName);
if (!isMultiLineCode) {
// Inline code block
node.innerHTML = `<code>${node.innerHTML}</code>`;
return;
} else {
// Multi-line code block
const lang = detectLang(text);
// Add a div wrapper
const div = node.ownerDocument.createElement('div');
if (/^C(\+\+|\#)?$/i.test(lang)) {
div.classList.add('language-c');
div.classList.add('dual-scheme');
// Preserve all anchors
for (const a of node.querySelectorAll('a[id], a[name]')) {
a.innerHTML = '';
div.appendChild(a);
}
// Use C++ syntax highlighting
const highlighter = await hl();
function highlight(text, theme) {
const src = highlighter.codeToHtml(
text, { lang: 'c++', defaultColor: false, theme }
);
const node = JSDOM.fragment(src).querySelector('pre');
node.removeAttribute('style');
return node;
}
const [node_light, node_dark] = themes.map(t => highlight(text, t));
node_light.classList.add('scheme-light');
node_dark.classList.add('scheme-dark');
div.appendChild(node_light);
div.appendChild(node_dark);
} else {
div.classList.add('language-plain-text');
div.appendChild(node.cloneNode(true));
}
// Replace <pre> with <div>
node.parentNode.replaceChild(div, node);
}
}
2 changes: 1 addition & 1 deletion setup/task/extract-links.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand Down
30 changes: 16 additions & 14 deletions setup/task/transform-raw.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ---------------------------------------------------------
* Copyright (c) 2023 Yuxuan Zhang @ FOCUS Lab
* Copyright (c) 2023 Yuxuan Zhang, web-dev@z-yx.cc
* This source code is licensed under the MIT license.
* You may find the full license in project root directory.
* ------------------------------------------------------ */
Expand All @@ -10,12 +10,13 @@ import { dirname } from 'path'

import YAML from 'yaml';

import traverse from '../../lib/traverse.js'
import { skippableTraverse as traverse } from '../../lib/traverse.js'
import { ELEMENT_NODE } from '../../lib/transform.js'
import { baseURL } from '../../lib/env.js'

import { source_id } from '../fetch-raw.js';
import breakdown from './breakdown-article.js';
import transformCode, { isCodeElement } from './code-block.js';

const src_id = process.env.SRC_ID

Expand Down Expand Up @@ -56,11 +57,11 @@ function write_html_md(id, src, title) {
'',
`<script setup>`,
`import { onMounted, ref } from "vue";`,
`const html = ref("");`,
`onMounted(async () => {`,
` const raw = await import("/${id}.src.html?raw");`,
` html.value = raw.default;`,
`});`,
`import html from "/${id}.src.html?raw";`,
// `onMounted(async () => {`,
// ` const raw = await import("/${id}.src.html?raw");`,
// ` html.value = raw.default;`,
// `});`,
`</script>`,
'',
`<div v-html="html"></div>`,
Expand All @@ -74,19 +75,20 @@ for (const node of document.querySelectorAll(blacklist.join(','))) {
}

// Transform all links
for (const node of traverse(document.body)) {
for (const [node, skip_children] of traverse(document.body)) {
if (node.nodeType !== ELEMENT_NODE) continue;
const tagName = node.tagName.toLowerCase();
// Remove all irrelevant tags
if (disallowed_tags.includes(tagName)) {
node.parentElement.removeChild(node);
continue;
} else if (tagName === 'pre') {
// const code = document.createElement('code');
// code.innerHTML = node.outerHTML;
// node.parentNode.insertBefore(code, node);
// node.parentNode.removeChild(node);
} else if (tagName === 'table') {
}
if (tagName === 'pre' || isCodeElement(node)) {
await transformCode(node);
skip_children();
continue;
}
if (tagName === 'table') {
for (const attr of node.getAttributeNames()) {
node.removeAttribute(attr);
}
Expand Down
Loading

0 comments on commit 67e285c

Please sign in to comment.