Skip to content

Commit 73f5b4b

Browse files
johnsoncodehkkermanxautofix-ci[bot]antfu
authored
feat(vscode): add Slidev language server (#1743)
Co-authored-by: _Kerman <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Anthony Fu <[email protected]> Co-authored-by: Anthony Fu <[email protected]>
1 parent 6293e10 commit 73f5b4b

34 files changed

+2116
-128
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ packages/create-app/template/pages
2020
packages/create-app/template/slides.md
2121
packages/create-app/template/snippets
2222
packages/slidev/README.md
23+
packages/vscode/syntaxes/codeblock-patch.json
2324
slides-export.md
2425
*slides-export.pptx

.npmrc

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
shamefully-hoist=true
22
ignore-workspace-root-check=true
33
strict-peer-dependencies=false
4+
link-workspace-packages=true

.vscode/launch.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"type": "extensionHost",
77
"request": "launch",
88
"args": [
9-
"--extensionDevelopmentPath=${workspaceFolder}/packages/vscode"
9+
"--extensionDevelopmentPath=${workspaceFolder}/packages/vscode",
10+
"--folder-uri=${workspaceRoot}/packages/vscode/syntaxes"
1011
],
1112
"outFiles": [
1213
"${workspaceFolder}/out/**/*.js"

.vscode/settings.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,9 @@
4646
"jsonc",
4747
"yaml"
4848
],
49-
"vitest.disableWorkspaceWarning": true
49+
"vitest.disableWorkspaceWarning": true,
50+
"slidev.include": [
51+
"**/slides.md",
52+
"packages/vscode/syntax/slidev.example.md"
53+
]
5054
}

eslint.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default antfu(
1717
'**/template.md',
1818
'**/example.md',
1919
'test/fixtures/markdown/**/*.md',
20+
'packages/vscode/syntaxes/slidev.example.md',
2021
],
2122
},
2223
},

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"shiki": "^1.10.2",
6767
"simple-git-hooks": "^2.11.1",
6868
"taze": "^0.14.2",
69+
"ts-json-schema-generator": "^2.3.0",
6970
"tsup": "^8.1.0",
7071
"typescript": "^5.5.3",
7172
"vite": "^5.3.3",

packages/parser/src/config.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ export function getDefaultConfig(): SlidevConfig {
3636
css: 'unocss',
3737
presenter: true,
3838
htmlAttrs: {},
39-
transition: undefined,
39+
transition: null,
4040
editor: true,
41-
contextMenu: undefined,
41+
contextMenu: null,
4242
wakeLock: true,
43+
remote: false,
44+
mdc: false,
4345
}
4446
}
4547

packages/parser/src/core.ts

+81-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import YAML from 'yaml'
22
import { ensurePrefix } from '@antfu/utils'
33
import type { FrontmatterStyle, SlidevDetectedFeatures, SlidevMarkdown, SlidevPreparserExtension, SourceSlideInfo } from '@slidev/types'
44

5+
export interface SlidevParserOptions {
6+
noParseYAML?: boolean
7+
preserveCR?: boolean
8+
}
9+
510
export function stringify(data: SlidevMarkdown) {
611
return `${data.slides.map(stringifySlide).join('\n').trim()}\n`
712
}
@@ -30,7 +35,7 @@ export function prettify(data: SlidevMarkdown) {
3035
return data
3136
}
3237

33-
function matter(code: string) {
38+
function matter(code: string, options: SlidevParserOptions) {
3439
let type: FrontmatterStyle | undefined
3540
let raw: string | undefined
3641

@@ -50,13 +55,13 @@ function matter(code: string) {
5055
})
5156
}
5257

53-
const doc = YAML.parseDocument(raw || '')
58+
const doc = raw && !options.noParseYAML ? YAML.parseDocument(raw) : undefined
5459

5560
return {
5661
type,
5762
raw,
5863
doc,
59-
data: doc.toJSON(),
64+
data: doc?.toJSON(),
6065
content,
6166
}
6267
}
@@ -70,8 +75,8 @@ export function detectFeatures(code: string): SlidevDetectedFeatures {
7075
}
7176
}
7277

73-
export function parseSlide(raw: string): Omit<SourceSlideInfo, 'filepath' | 'index' | 'start' | 'contentStart' | 'end'> {
74-
const matterResult = matter(raw)
78+
export function parseSlide(raw: string, options: SlidevParserOptions = {}): Omit<SourceSlideInfo, 'filepath' | 'index' | 'start' | 'contentStart' | 'end'> {
79+
const matterResult = matter(raw, options)
7580
let note: string | undefined
7681
const frontmatter = matterResult.data || {}
7782
let content = matterResult.content.trim()
@@ -115,8 +120,9 @@ export async function parse(
115120
markdown: string,
116121
filepath: string,
117122
extensions?: SlidevPreparserExtension[],
123+
options: SlidevParserOptions = {},
118124
): Promise<SlidevMarkdown> {
119-
const lines = markdown.split(/\r?\n/g)
125+
const lines = markdown.split(options.preserveCR ? '\n' : /\r?\n/g)
120126
const slides: SourceSlideInfo[] = []
121127

122128
let start = 0
@@ -127,7 +133,7 @@ export async function parse(
127133
return
128134
const raw = lines.slice(start, end).join('\n')
129135
const slide: SourceSlideInfo = {
130-
...parseSlide(raw),
136+
...parseSlide(raw, options),
131137
filepath,
132138
index: slides.length,
133139
start,
@@ -195,6 +201,74 @@ export async function parse(
195201
}
196202
}
197203

204+
export function parseSync(
205+
markdown: string,
206+
filepath: string,
207+
options: SlidevParserOptions = {},
208+
): SlidevMarkdown {
209+
const lines = markdown.split(options.preserveCR ? '\n' : /\r?\n/g)
210+
const slides: SourceSlideInfo[] = []
211+
212+
let start = 0
213+
let contentStart = 0
214+
215+
function slice(end: number) {
216+
if (start === end)
217+
return
218+
const raw = lines.slice(start, end).join('\n')
219+
const slide: SourceSlideInfo = {
220+
...parseSlide(raw, options),
221+
filepath,
222+
index: slides.length,
223+
start,
224+
contentStart,
225+
end,
226+
}
227+
slides.push(slide)
228+
start = end + 1
229+
contentStart = end + 1
230+
}
231+
232+
for (let i = 0; i < lines.length; i++) {
233+
const line = lines[i].trimEnd()
234+
if (line.startsWith('---')) {
235+
slice(i)
236+
237+
const next = lines[i + 1]
238+
// found frontmatter, skip next dash
239+
if (line[3] !== '-' && next?.trim()) {
240+
start = i
241+
for (i += 1; i < lines.length; i++) {
242+
if (lines[i].trimEnd() === '---')
243+
break
244+
}
245+
contentStart = i + 1
246+
}
247+
}
248+
// skip code block
249+
else if (line.trimStart().startsWith('```')) {
250+
const codeBlockLevel = line.match(/^\s*`+/)![0]
251+
let j = i + 1
252+
for (; j < lines.length; j++) {
253+
if (lines[j].startsWith(codeBlockLevel))
254+
break
255+
}
256+
// Update i only when code block ends
257+
if (j !== lines.length)
258+
i = j
259+
}
260+
}
261+
262+
if (start <= lines.length - 1)
263+
slice(lines.length)
264+
265+
return {
266+
filepath,
267+
raw: markdown,
268+
slides,
269+
}
270+
}
271+
198272
function scanMonacoReferencedMods(md: string) {
199273
const types = new Set<string>()
200274
const deps = new Set<string>()

0 commit comments

Comments
 (0)