返回 slidev
volar-service-yaml.ts
根目录 / packages / vscode / language-server / volar-service-yaml.ts
1 // Vendored from https://github.com/volarjs/services/tree/master/packages/yaml
2 // Await https://github.com/volarjs/services/pull/103
3
4 import type { Disposable, DocumentSelector, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, ProviderResult } from '@volar/language-service'
5 import type { TextDocument } from 'vscode-languageserver-textdocument'
6 import { URI, Utils } from 'vscode-uri'
7 import * as yaml from 'yaml-language-server'
8
9 export interface Provide {
10 'yaml/languageService': () => yaml.LanguageService
11 }
12
13 function noop(): undefined { }
14
15 /**
16 * Create a Volar language service for YAML documents.
17 */
18 export function create({
19 documentSelector = ['yaml'],
20 getWorkspaceContextService = (context) => {
21 return {
22 resolveRelativePath(relativePath, resource) {
23 const base = resource.substring(0, resource.lastIndexOf('/') + 1)
24 let baseUri = URI.parse(base)
25 const decoded = context.decodeEmbeddedDocumentUri(baseUri)
26 if (decoded) {
27 baseUri = decoded[0]
28 }
29 return Utils.resolvePath(baseUri, relativePath).toString()
30 },
31 }
32 },
33 getLanguageSettings = () => {
34 return {
35 completion: true,
36 customTags: [],
37 format: true,
38 hover: true,
39 isKubernetes: false,
40 validate: true,
41 yamlVersion: '1.2',
42 }
43 },
44 onDidChangeLanguageSettings = () => {
45 return { dispose() { } }
46 },
47 }: {
48 documentSelector?: DocumentSelector
49 getWorkspaceContextService?: (context: LanguageServiceContext) => yaml.WorkspaceContextService
50 getLanguageSettings?: (context: LanguageServiceContext) => ProviderResult<yaml.LanguageSettings>
51 onDidChangeLanguageSettings?: (listener: () => void, context: LanguageServiceContext) => Disposable
52 } = {}): LanguageServicePlugin {
53 return {
54 name: 'yaml',
55 capabilities: {
56 codeActionProvider: {},
57 codeLensProvider: {
58 resolveProvider: false,
59 },
60 completionProvider: {
61 triggerCharacters: [' ', ':'],
62 },
63 definitionProvider: true,
64 diagnosticProvider: {
65 interFileDependencies: true,
66 workspaceDiagnostics: false,
67 },
68 documentOnTypeFormattingProvider: {
69 triggerCharacters: ['\n'],
70 },
71 documentSymbolProvider: true,
72 hoverProvider: true,
73 documentLinkProvider: {},
74 foldingRangeProvider: true,
75 selectionRangeProvider: true,
76 },
77 create(context): LanguageServicePluginInstance<Provide> {
78 const ls = yaml.getLanguageService({
79 schemaRequestService: async uri => await context.env.fs?.readFile(URI.parse(uri)) ?? '',
80 telemetry: {
81 send: noop,
82 sendError: noop,
83 sendTrack: noop,
84 },
85 clientCapabilities: context.env?.clientCapabilities,
86 workspaceContext: getWorkspaceContextService(context),
87 })
88 let initializing: Promise<void> | undefined
89
90 const disposable = onDidChangeLanguageSettings(() => initializing = undefined, context)
91
92 return {
93 dispose() {
94 disposable.dispose()
95 },
96
97 provide: {
98 'yaml/languageService': () => ls,
99 },
100
101 provideCodeActions(document, range, context) {
102 return worker(document, () => {
103 return ls.getCodeAction(document, {
104 context,
105 range,
106 textDocument: document,
107 })
108 })
109 },
110
111 // provideCodeLenses(document) {
112 // return worker(document, () => {
113 // return ls.getCodeLens(document)
114 // })
115 // },
116
117 provideCompletionItems(document, position) {
118 return worker(document, () => {
119 return ls.doComplete(document, position, false)
120 })
121 },
122
123 provideDefinition(document, position) {
124 return worker(document, () => {
125 return ls.doDefinition(document, { position, textDocument: document })
126 })
127 },
128
129 provideDiagnostics(document) {
130 return worker(document, () => {
131 return ls.doValidation(document, false)
132 })
133 },
134
135 provideDocumentSymbols(document) {
136 return worker(document, () => {
137 return ls.findDocumentSymbols2(document, {})
138 })
139 },
140
141 provideHover(document, position) {
142 return worker(document, () => {
143 return ls.doHover(document, position)
144 })
145 },
146
147 provideDocumentLinks(document) {
148 return worker(document, () => {
149 return ls.findLinks(document)
150 })
151 },
152
153 provideFoldingRanges(document) {
154 return worker(document, () => {
155 return ls.getFoldingRanges(document, context.env.clientCapabilities?.textDocument?.foldingRange ?? {})
156 })
157 },
158
159 provideOnTypeFormattingEdits(document, position, key, options) {
160 return worker(document, () => {
161 return ls.doDocumentOnTypeFormatting(document, { ch: key, options, position, textDocument: document })
162 })
163 },
164
165 provideSelectionRanges(document, positions) {
166 return worker(document, () => {
167 return ls.getSelectionRanges(document, positions)
168 })
169 },
170
171 // resolveCodeLens(codeLens) {
172 // return ls.resolveCodeLens(codeLens)
173 // },
174 }
175
176 async function worker<T>(document: TextDocument, callback: () => T): Promise<Awaited<T> | undefined> {
177 if (!matchDocument(documentSelector, document)) {
178 return
179 }
180
181 await (initializing ??= initialize())
182
183 return await callback()
184 }
185
186 async function initialize() {
187 const settings = await getLanguageSettings(context)
188 ls.configure(settings)
189 }
190 },
191 }
192 }
193
194 function matchDocument(selector: DocumentSelector, document: TextDocument) {
195 for (const sel of selector) {
196 if (sel === document.languageId || (typeof sel === 'object' && sel.language === document.languageId)) {
197 return true
198 }
199 }
200 return false
201 }
202
202 lines TYPESCRIPT