Skip to content

Commit 7036382

Browse files
committed
more EC features
1 parent 1a1b355 commit 7036382

File tree

9 files changed

+380
-162
lines changed

9 files changed

+380
-162
lines changed

bun.lockb

458 Bytes
Binary file not shown.

exampleVault/index.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
test: hello
33
---
44

5-
```ts asdasd
5+
TypeScript code
6+
7+
```ts title="A part of ParsiNOM" {13-15}
68
export class Parser<const SType extends STypeBase> {
79
public p: ParseFunction<SType>;
810

@@ -35,6 +37,8 @@ export class Parser<const SType extends STypeBase> {
3537
}
3638
```
3739

40+
CSS code
41+
3842
```css
3943
input:is([data-task=""], [data-task=""] > *):checked::after {
4044
content: "";
@@ -55,3 +59,16 @@ input:is([data-task="字"], [data-task="字"] > *):checked::after {
5559
-webkit-mask-clip: text;
5660
}
5761
```
62+
63+
Bash
64+
65+
```bash title="My Bash Script"
66+
echo "Hello"
67+
```
68+
69+
70+
```diff
71+
+ this line will be marked as inserted
72+
- this line will be marked as deleted
73+
this is a regular line
74+
```

package.json

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,57 @@
11
{
2-
"name": "shiki-highlighter",
3-
"version": "0.1.2",
4-
"description": "Highlight code blocks with Shiki.",
5-
"main": "main.js",
6-
"scripts": {
7-
"dev": "bun run automation/build/esbuild.dev.config.ts",
8-
"build": "bun run tsc && bun run automation/build/esbuild.config.ts",
9-
"tsc": "tsc -noEmit -skipLibCheck",
10-
"test": "bun test",
11-
"test:log": "LOG_TESTS=true bun test",
12-
"format": "prettier --write --plugin prettier-plugin-svelte .",
13-
"format:check": "prettier --check --plugin prettier-plugin-svelte .",
14-
"lint": "eslint --max-warnings=0 src/**",
15-
"lint:fix": "eslint --max-warnings=0 --fix src/**",
16-
"svelte-check": "svelte-check --compiler-warnings \"unused-export-let:ignore\"",
17-
"check": "bun run format:check && bun run tsc && bun run svelte-check && bun run lint && bun run test",
18-
"check:fix": "bun run format && bun run tsc && bun run svelte-check && bun run lint:fix && bun run test",
19-
"release": "bun run automation/release.ts",
20-
"stats": "bun run automation/stats.ts"
21-
},
22-
"keywords": [],
23-
"author": "Moritz Jung",
24-
"license": "GPL-3.0",
25-
"devDependencies": {
26-
"@expressive-code/core": "^0.33.5",
27-
"@expressive-code/plugin-collapsible-sections": "^0.33.5",
28-
"@expressive-code/plugin-line-numbers": "^0.33.5",
29-
"@expressive-code/plugin-shiki": "^0.33.5",
30-
"@expressive-code/plugin-text-markers": "^0.33.5",
31-
"@happy-dom/global-registrator": "^14.3.6",
32-
"@lemons_dev/parsinom": "^0.0.12",
33-
"@tsconfig/svelte": "^5.0.3",
34-
"@types/bun": "^1.0.10",
35-
"@typescript-eslint/eslint-plugin": "^7.3.1",
36-
"@typescript-eslint/parser": "^7.3.1",
37-
"builtin-modules": "^3.3.0",
38-
"esbuild": "^0.20.2",
39-
"esbuild-plugin-copy-watch": "^2.1.0",
40-
"esbuild-svelte": "^0.8.0",
41-
"eslint": "^8.57.0",
42-
"eslint-plugin-import": "^2.29.1",
43-
"eslint-plugin-isaacscript": "^3.12.2",
44-
"eslint-plugin-only-warn": "^1.1.0",
45-
"obsidian": "latest",
46-
"prettier": "^3.2.5",
47-
"prettier-plugin-svelte": "^3.2.2",
48-
"shiki": "^1.2.0",
49-
"string-argv": "^0.3.2",
50-
"svelte": "^4.2.12",
51-
"svelte-check": "^3.6.8",
52-
"svelte-preprocess": "^5.1.3",
53-
"tslib": "^2.6.2",
54-
"typescript": "^5.4.3"
55-
}
2+
"name": "shiki-highlighter",
3+
"version": "0.1.2",
4+
"description": "Highlight code blocks with Shiki.",
5+
"main": "main.js",
6+
"scripts": {
7+
"dev": "bun run automation/build/esbuild.dev.config.ts",
8+
"build": "bun run tsc && bun run automation/build/esbuild.config.ts",
9+
"tsc": "tsc -noEmit -skipLibCheck",
10+
"test": "bun test",
11+
"test:log": "LOG_TESTS=true bun test",
12+
"format": "prettier --write --plugin prettier-plugin-svelte .",
13+
"format:check": "prettier --check --plugin prettier-plugin-svelte .",
14+
"lint": "eslint --max-warnings=0 src/**",
15+
"lint:fix": "eslint --max-warnings=0 --fix src/**",
16+
"svelte-check": "svelte-check --compiler-warnings \"unused-export-let:ignore\"",
17+
"check": "bun run format:check && bun run tsc && bun run svelte-check && bun run lint && bun run test",
18+
"check:fix": "bun run format && bun run tsc && bun run svelte-check && bun run lint:fix && bun run test",
19+
"release": "bun run automation/release.ts",
20+
"stats": "bun run automation/stats.ts"
21+
},
22+
"keywords": [],
23+
"author": "Moritz Jung",
24+
"license": "GPL-3.0",
25+
"devDependencies": {
26+
"@expressive-code/core": "^0.33.5",
27+
"@expressive-code/plugin-collapsible-sections": "^0.33.5",
28+
"@expressive-code/plugin-frames": "^0.33.5",
29+
"@expressive-code/plugin-line-numbers": "^0.33.5",
30+
"@expressive-code/plugin-shiki": "^0.33.5",
31+
"@expressive-code/plugin-text-markers": "^0.33.5",
32+
"@happy-dom/global-registrator": "^14.3.6",
33+
"@lemons_dev/parsinom": "^0.0.12",
34+
"@tsconfig/svelte": "^5.0.3",
35+
"@types/bun": "^1.0.10",
36+
"@typescript-eslint/eslint-plugin": "^7.3.1",
37+
"@typescript-eslint/parser": "^7.3.1",
38+
"builtin-modules": "^3.3.0",
39+
"esbuild": "^0.20.2",
40+
"esbuild-plugin-copy-watch": "^2.1.0",
41+
"esbuild-svelte": "^0.8.0",
42+
"eslint": "^8.57.0",
43+
"eslint-plugin-import": "^2.29.1",
44+
"eslint-plugin-isaacscript": "^3.12.2",
45+
"eslint-plugin-only-warn": "^1.1.0",
46+
"obsidian": "latest",
47+
"prettier": "^3.2.5",
48+
"prettier-plugin-svelte": "^3.2.2",
49+
"shiki": "^1.2.0",
50+
"string-argv": "^0.3.2",
51+
"svelte": "^4.2.12",
52+
"svelte-check": "^3.6.8",
53+
"svelte-preprocess": "^5.1.3",
54+
"tslib": "^2.6.2",
55+
"typescript": "^5.4.3"
56+
}
5657
}

src/CodeBlock.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { MarkdownRenderChild, type MarkdownSectionInformation } from 'obsidian';
2+
import type ShikiPlugin from 'src/main';
3+
import { toHtml } from 'hast-util-to-html';
4+
5+
export class CodeBlock extends MarkdownRenderChild {
6+
plugin: ShikiPlugin;
7+
source: string;
8+
language: string;
9+
languageShorthand: string;
10+
sectionInfo: MarkdownSectionInformation | null;
11+
12+
constructor(
13+
plugin: ShikiPlugin,
14+
containerEl: HTMLElement,
15+
source: string,
16+
language: string,
17+
languageShorthand: string,
18+
sectionInfo: MarkdownSectionInformation | null,
19+
) {
20+
super(containerEl);
21+
22+
this.plugin = plugin;
23+
this.source = source;
24+
this.language = language;
25+
this.languageShorthand = languageShorthand;
26+
this.sectionInfo = sectionInfo;
27+
}
28+
29+
getMetaString(): string {
30+
if (this.sectionInfo === null) {
31+
return '';
32+
}
33+
34+
const lines = this.sectionInfo.text.split('\n');
35+
const startLine = lines[this.sectionInfo.lineStart];
36+
37+
// regexp to match the text after the code block language
38+
const regex = new RegExp('^[^`~]*?(```+|~~~+)' + this.languageShorthand + ' (.*)', 'g');
39+
const match = regex.exec(startLine);
40+
if (match !== null) {
41+
return match[2];
42+
} else {
43+
return '';
44+
}
45+
}
46+
47+
public async onload(): Promise<void> {
48+
super.onload();
49+
50+
const metaString = this.getMetaString();
51+
52+
const renderResult = await this.plugin.ec.render({
53+
code: this.source,
54+
language: this.language,
55+
meta: metaString,
56+
});
57+
58+
const ast = this.plugin.themeMapper.fixAST(renderResult.renderedGroupAst);
59+
60+
// yes, this is innerHTML, but we trust hast
61+
this.containerEl.innerHTML = toHtml(ast);
62+
}
63+
64+
public onunload(): void {
65+
this.containerEl.empty();
66+
this.containerEl.innerText = 'unloaded shiki code block';
67+
}
68+
}

src/ECTheme.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { type ExpressiveCodeEngineConfig } from '@expressive-code/core';
2+
3+
export const EC_THEME: ExpressiveCodeEngineConfig['styleOverrides'] = {
4+
borderColor: 'var(--shiki-code-block-border-color)',
5+
borderRadius: 'var(--shiki-code-block-border-radius)',
6+
borderWidth: 'var(--shiki-code-block-border-width)',
7+
codeBackground: 'var(--code-background)',
8+
codeFontFamily: 'var(--font-monospace)',
9+
codeFontSize: 'var(--code-size)',
10+
codeFontWeight: 'var(--font-normal)',
11+
codeForeground: 'var(--code-normal)',
12+
codeLineHeight: 'var(--line-height-normal)',
13+
codePaddingBlock: 'var(--size-4-3)',
14+
codePaddingInline: 'var(--size-4-4)',
15+
codeSelectionBackground: 'var(--text-selection)',
16+
focusBorder: 'var(--background-modifier-border)',
17+
scrollbarThumbColor: 'var(--scrollbar-thumb-bg)',
18+
scrollbarThumbHoverColor: 'var(--scrollbar-active-thumb-bg)',
19+
uiFontFamily: 'var(--font-interface)',
20+
uiFontSize: 'var(--font-text-size)',
21+
uiFontWeight: 'var(--font-normal)',
22+
uiLineHeight: 'var(--line-height-normal)',
23+
uiPaddingBlock: 'var(--size-4-2)',
24+
uiPaddingInline: 'var(--size-4-4)',
25+
uiSelectionBackground: 'var(--text-selection)',
26+
uiSelectionForeground: 'var(--text-normal)',
27+
textMarkers: {
28+
delBackground: 'rgba(var(--shiki-highlight-red-rgb), var(--shiki-highlight-opacity))',
29+
delBorderColor: 'rgba(var(--shiki-highlight-red-rgb), 1)',
30+
delDiffIndicatorColor: 'rgba(var(--shiki-highlight-red-rgb), 1)',
31+
inlineMarkerBorderWidth: 'var(--border-width)',
32+
insBackground: 'rgba(var(--shiki-highlight-green-rgb), var(--shiki-highlight-opacity))',
33+
insBorderColor: 'rgba(var(--shiki-highlight-green-rgb), 1)',
34+
insDiffIndicatorColor: 'rgba(var(--shiki-highlight-green-rgb), 1)',
35+
lineDiffIndicatorMarginLeft: '0.3rem',
36+
lineMarkerAccentMargin: '0rem',
37+
lineMarkerAccentWidth: '0.15rem',
38+
lineMarkerLabelColor: 'white',
39+
lineMarkerLabelPaddingInline: '0.2rem',
40+
markBackground: 'rgba(var(--shiki-highlight-neutral-rgb), var(--shiki-highlight-opacity))',
41+
markBorderColor: 'rgba(var(--shiki-highlight-neutral-rgb), 1)',
42+
},
43+
frames: {
44+
editorActiveTabBackground: 'var(--code-background)',
45+
editorActiveTabBorderColor: 'transparent',
46+
editorActiveTabForeground: 'var(--text-normal)',
47+
editorActiveTabIndicatorBottomColor: 'transparent',
48+
editorActiveTabIndicatorHeight: '2px',
49+
editorActiveTabIndicatorTopColor: 'rgb(var(--shiki-highlight-neutral-rgb), 1)',
50+
editorBackground: 'var(--code-background)',
51+
editorTabBarBackground: 'var(--color-primary)',
52+
editorTabBarBorderBottomColor: 'transparent',
53+
editorTabBarBorderColor: 'transparent',
54+
editorTabBorderRadius: 'var(--shiki-code-border-radius)',
55+
editorTabsMarginBlockStart: '0',
56+
editorTabsMarginInlineStart: '0',
57+
frameBoxShadowCssValue: 'none',
58+
inlineButtonBackground: 'var(--interactive-normal)',
59+
inlineButtonBackgroundActiveOpacity: '1',
60+
inlineButtonBackgroundHoverOrFocusOpacity: '1',
61+
inlineButtonBackgroundIdleOpacity: '1',
62+
inlineButtonBorder: 'var(--shiki-code-border-color)',
63+
inlineButtonBorderOpacity: '1',
64+
inlineButtonForeground: 'var(--text-normal)',
65+
shadowColor: 'transparent',
66+
terminalBackground: 'var(--code-background)',
67+
terminalTitlebarBackground: 'var(--code-background)',
68+
terminalTitlebarBorderBottomColor: 'transparent',
69+
terminalTitlebarDotsForeground: 'var(--shiki-terminal-dots-color)',
70+
terminalTitlebarDotsOpacity: '1',
71+
terminalTitlebarForeground: 'var(--text-normal)',
72+
tooltipSuccessBackground: 'var(--shiki-tooltip-background)',
73+
tooltipSuccessForeground: 'var(--shiki-tooltip-text-color)',
74+
},
75+
};

src/ObsidianTheme.ts

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,4 @@
1-
import { ThemeRegistration } from 'shiki';
2-
import * as hast_util_to_html_lib_types from 'hast-util-to-html/lib/types';
3-
import * as hast_types from 'hast';
4-
5-
export class ThemeMapper {
6-
mapCounter: number;
7-
mapping: Map<string, string>;
8-
9-
constructor() {
10-
this.mapCounter = 0;
11-
this.mapping = new Map();
12-
}
13-
14-
getTheme(): ThemeRegistration {
15-
return {
16-
displayName: OBSIDIAN_THEME.displayName,
17-
name: OBSIDIAN_THEME.name,
18-
semanticHighlighting: OBSIDIAN_THEME.semanticHighlighting,
19-
colors: Object.fromEntries(Object.entries(OBSIDIAN_THEME.colors).map(([key, value]) => [key, this.mapColor(value)])),
20-
tokenColors: OBSIDIAN_THEME.tokenColors.map(token => {
21-
const newToken = { ...token };
22-
23-
if (newToken.settings) {
24-
newToken.settings = { ...newToken.settings };
25-
}
26-
27-
if (newToken.settings.foreground) {
28-
newToken.settings.foreground = this.mapColor(newToken.settings.foreground);
29-
}
30-
31-
return newToken;
32-
}),
33-
};
34-
}
35-
36-
mapColor(color: string): string {
37-
if (this.mapping.has(color)) {
38-
return this.mapping.get(color)!;
39-
} else {
40-
const newColor = `#${this.mapCounter.toString(16).padStart(6, '0').toUpperCase()}`;
41-
this.mapCounter += 1;
42-
this.mapping.set(color, newColor);
43-
return newColor;
44-
}
45-
}
46-
47-
fixAST(ast: hast_util_to_html_lib_types.Parent): hast_util_to_html_lib_types.Parent {
48-
ast.children = ast.children.map(child => {
49-
if (child.type === 'element') {
50-
return this.fixNode(child);
51-
} else {
52-
return child;
53-
}
54-
});
55-
56-
return ast;
57-
}
58-
59-
private fixNode(node: hast_types.Element): hast_types.Element {
60-
if (node.properties?.style) {
61-
let style = node.properties.style as string;
62-
console.log(style);
63-
for (const [key, value] of this.mapping) {
64-
style = style.replaceAll(value, key);
65-
}
66-
console.log(style);
67-
node.properties.style = style;
68-
}
69-
70-
for (const child of node.children) {
71-
if (child.type === 'element') {
72-
this.fixNode(child);
73-
}
74-
}
75-
76-
return node;
77-
}
78-
}
1+
import { type ThemeRegistration } from 'shiki';
792

803
export const OBSIDIAN_THEME = {
814
displayName: 'Obsidian Theme',

0 commit comments

Comments
 (0)