diff --git a/package.json b/package.json
index 5fc8ad5..259522b 100644
--- a/package.json
+++ b/package.json
@@ -122,6 +122,7 @@
"@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-rust": "^6.0.2",
"@codemirror/lang-sql": "^6.10.0",
+ "@codemirror/lang-vue": "^0.1.3",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/lang-yaml": "^6.1.3",
"@codemirror/language": "^6.12.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5ed2a9e..a5848b7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -47,6 +47,9 @@ importers:
'@codemirror/lang-sql':
specifier: ^6.10.0
version: 6.10.0
+ '@codemirror/lang-vue':
+ specifier: ^0.1.3
+ version: 0.1.3
'@codemirror/lang-xml':
specifier: ^6.1.0
version: 6.1.0
@@ -265,6 +268,9 @@ packages:
'@codemirror/lang-sql@6.10.0':
resolution: {integrity: sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w==}
+ '@codemirror/lang-vue@0.1.3':
+ resolution: {integrity: sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug==}
+
'@codemirror/lang-xml@6.1.0':
resolution: {integrity: sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==}
@@ -3015,6 +3021,15 @@ snapshots:
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
+ '@codemirror/lang-vue@0.1.3':
+ dependencies:
+ '@codemirror/lang-html': 6.4.12
+ '@codemirror/lang-javascript': 6.2.5
+ '@codemirror/language': 6.12.4
+ '@lezer/common': 1.5.2
+ '@lezer/highlight': 1.2.3
+ '@lezer/lr': 1.4.10
+
'@codemirror/lang-xml@6.1.0':
dependencies:
'@codemirror/autocomplete': 6.20.3
diff --git a/src/client/lang.ts b/src/client/lang.ts
index 8e7dc40..af83e23 100644
--- a/src/client/lang.ts
+++ b/src/client/lang.ts
@@ -4,12 +4,12 @@
* the CodeMirror language packages (bundled into the client).
*/
import { Language, LanguageSupport, StreamLanguage } from '@codemirror/language'
-import { javascript } from '@codemirror/lang-javascript'
+import { javascript, jsxLanguage, typescriptLanguage, tsxLanguage } from '@codemirror/lang-javascript'
import { json } from '@codemirror/lang-json'
import { markdown } from '@codemirror/lang-markdown'
import { python } from '@codemirror/lang-python'
import { html } from '@codemirror/lang-html'
-import { css } from '@codemirror/lang-css'
+import { css, cssLanguage } from '@codemirror/lang-css'
import { xml } from '@codemirror/lang-xml'
import { yaml } from '@codemirror/lang-yaml'
import { sql } from '@codemirror/lang-sql'
@@ -18,13 +18,36 @@ import { cpp } from '@codemirror/lang-cpp'
import { rust } from '@codemirror/lang-rust'
import { go } from '@codemirror/lang-go'
import { php } from '@codemirror/lang-php'
+import { vue } from '@codemirror/lang-vue'
import { shell } from '@codemirror/legacy-modes/mode/shell'
import { toml } from '@codemirror/legacy-modes/mode/toml'
import { nginx } from '@codemirror/legacy-modes/mode/nginx'
import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile'
import { properties } from '@codemirror/legacy-modes/mode/properties'
-import { csharp, kotlin } from '@codemirror/legacy-modes/mode/clike'
+import { csharp, kotlin, dart, scala, objectiveCpp } from '@codemirror/legacy-modes/mode/clike'
import { swift } from '@codemirror/legacy-modes/mode/swift'
+import { sCSS, less } from '@codemirror/legacy-modes/mode/css'
+import { sass } from '@codemirror/legacy-modes/mode/sass'
+import { stylus } from '@codemirror/legacy-modes/mode/stylus'
+import { ruby } from '@codemirror/legacy-modes/mode/ruby'
+import { lua } from '@codemirror/legacy-modes/mode/lua'
+import { perl } from '@codemirror/legacy-modes/mode/perl'
+import { r } from '@codemirror/legacy-modes/mode/r'
+import { groovy } from '@codemirror/legacy-modes/mode/groovy'
+import { powerShell } from '@codemirror/legacy-modes/mode/powershell'
+import { diff } from '@codemirror/legacy-modes/mode/diff'
+import { protobuf } from '@codemirror/legacy-modes/mode/protobuf'
+import { cmake } from '@codemirror/legacy-modes/mode/cmake'
+import { pug } from '@codemirror/legacy-modes/mode/pug'
+import { tcl } from '@codemirror/legacy-modes/mode/tcl'
+import { haskell } from '@codemirror/legacy-modes/mode/haskell'
+import { clojure } from '@codemirror/legacy-modes/mode/clojure'
+import { erlang } from '@codemirror/legacy-modes/mode/erlang'
+import { julia } from '@codemirror/legacy-modes/mode/julia'
+import { pascal } from '@codemirror/legacy-modes/mode/pascal'
+import { vb } from '@codemirror/legacy-modes/mode/vb'
+import { vhdl } from '@codemirror/legacy-modes/mode/vhdl'
+import { stex } from '@codemirror/legacy-modes/mode/stex'
/** The lowercased file extension of a path ('' when none). */
export function extOf(path: string): string {
@@ -63,10 +86,47 @@ export function languageKeyForExt(ext: string): string | null {
case 'nginx': case 'conf': return 'nginx'
case 'dockerfile': case 'docker': return 'dockerfile'
case 'properties': case 'env': return 'properties'
+ case 'vue': return 'vue'
+ case 'scss': return 'scss'
+ case 'sass': return 'sass'
+ case 'less': return 'less'
+ case 'styl': return 'stylus'
+ case 'rb': return 'ruby'
+ case 'lua': return 'lua'
+ case 'pl': case 'pm': return 'perl'
+ case 'r': return 'r'
+ case 'dart': return 'dart'
+ case 'scala': case 'sc': return 'scala'
+ case 'groovy': return 'groovy'
+ case 'ps1': case 'psm1': return 'powershell'
+ case 'diff': case 'patch': return 'diff'
+ case 'proto': return 'protobuf'
+ case 'cmake': return 'cmake'
+ case 'pug': return 'pug'
+ case 'tcl': return 'tcl'
+ case 'hs': return 'haskell'
+ case 'clj': case 'cljs': return 'clojure'
+ case 'erl': return 'erlang'
+ case 'jl': return 'julia'
+ case 'pas': return 'pascal'
+ case 'vb': return 'vb'
+ case 'vhd': return 'vhdl'
+ case 'tex': return 'stex'
+ case 'mm': return 'objectivecpp'
+ // '.v' (Verilog/Coq/V) 与 '.m' (Objective-C/MATLAB) 存在跨语言歧义,
+ // 故意不映射——错配高亮比纯文本更误导。
default: return null
}
}
+/** Per-lang `',
+ )
+ const names = new Set()
+ let hasError = false
+ tree.iterate({ enter: (node) => { if (node.type.isError) hasError = true; names.add(node.name) } })
+ expect(hasError).toBe(false)
+ expect(names.has('Script')).toBe(true)
+ expect(names.has('StyleSheet')).toBe(true)
+ expect(names.has('Interpolation')).toBe(true)
+ expect(names.has('SingleExpression')).toBe(true)
+ })
+
+ // P1-2 修复守护:')
+ const names = new Set()
+ let hasError = false
+ tree.iterate({ enter: (node) => { if (node.type.isError) hasError = true; names.add(node.name) } })
+ expect(hasError).toBe(false)
+ // 两条正向鉴别:无 StyleSheet = CSS parser 未接管;无 StyleText =
+ // 内容确有 parser 接管(删掉 scss 条目时内容会退化回纯文本 StyleText)。
+ expect(names.has('StyleSheet')).toBe(false)
+ expect(names.has('StyleText')).toBe(false)
+ })
})
describe('pdf preview kind', () => {