Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/markdown-language-features/src/client/client.ts
3292 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as vscode from 'vscode';
7
import { BaseLanguageClient, LanguageClientOptions, NotebookDocumentSyncRegistrationType, Range, TextEdit } from 'vscode-languageclient';
8
import { IMdParser } from '../markdownEngine';
9
import { IDisposable } from '../util/dispose';
10
import { looksLikeMarkdownPath, markdownFileExtensions, markdownLanguageIds } from '../util/file';
11
import { FileWatcherManager } from './fileWatchingManager';
12
import { InMemoryDocument } from './inMemoryDocument';
13
import * as proto from './protocol';
14
import { VsCodeMdWorkspace } from './workspace';
15
16
export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient;
17
18
export class MdLanguageClient implements IDisposable {
19
20
constructor(
21
private readonly _client: BaseLanguageClient,
22
private readonly _workspace: VsCodeMdWorkspace,
23
) { }
24
25
dispose(): void {
26
this._client.stop();
27
this._workspace.dispose();
28
}
29
30
resolveLinkTarget(linkText: string, uri: vscode.Uri): Promise<proto.ResolvedDocumentLinkTarget> {
31
return this._client.sendRequest(proto.resolveLinkTarget, { linkText, uri: uri.toString() });
32
}
33
34
getEditForFileRenames(files: ReadonlyArray<{ oldUri: string; newUri: string }>, token: vscode.CancellationToken) {
35
return this._client.sendRequest(proto.getEditForFileRenames, files, token);
36
}
37
38
getReferencesToFileInWorkspace(resource: vscode.Uri, token: vscode.CancellationToken) {
39
return this._client.sendRequest(proto.getReferencesToFileInWorkspace, { uri: resource.toString() }, token);
40
}
41
42
prepareUpdatePastedLinks(doc: vscode.Uri, ranges: readonly vscode.Range[], token: vscode.CancellationToken) {
43
return this._client.sendRequest(proto.prepareUpdatePastedLinks, {
44
uri: doc.toString(),
45
ranges: ranges.map(range => Range.create(range.start.line, range.start.character, range.end.line, range.end.character)),
46
}, token);
47
}
48
49
getUpdatePastedLinksEdit(pastingIntoDoc: vscode.Uri, edits: readonly vscode.TextEdit[], metadata: string, token: vscode.CancellationToken) {
50
return this._client.sendRequest(proto.getUpdatePastedLinksEdit, {
51
metadata,
52
pasteIntoDoc: pastingIntoDoc.toString(),
53
edits: edits.map(edit => TextEdit.replace(edit.range, edit.newText)),
54
}, token);
55
}
56
}
57
58
export async function startClient(factory: LanguageClientConstructor, parser: IMdParser): Promise<MdLanguageClient> {
59
60
const mdFileGlob = `**/*.{${markdownFileExtensions.join(',')}}`;
61
62
const clientOptions: LanguageClientOptions = {
63
documentSelector: markdownLanguageIds,
64
synchronize: {
65
configurationSection: ['markdown'],
66
fileEvents: vscode.workspace.createFileSystemWatcher(mdFileGlob),
67
},
68
initializationOptions: {
69
markdownFileExtensions,
70
i10lLocation: vscode.l10n.uri?.toJSON(),
71
},
72
diagnosticPullOptions: {
73
onChange: true,
74
onTabs: true,
75
match(_documentSelector, resource) {
76
return looksLikeMarkdownPath(resource);
77
},
78
},
79
markdown: {
80
supportHtml: true,
81
}
82
};
83
84
const client = factory('markdown', vscode.l10n.t("Markdown Language Server"), clientOptions);
85
86
client.registerProposedFeatures();
87
88
const notebookFeature = client.getFeature(NotebookDocumentSyncRegistrationType.method);
89
if (notebookFeature !== undefined) {
90
notebookFeature.register({
91
id: String(Date.now()),
92
registerOptions: {
93
notebookSelector: [{
94
notebook: '*',
95
cells: [{ language: 'markdown' }]
96
}]
97
}
98
});
99
}
100
101
const workspace = new VsCodeMdWorkspace();
102
103
client.onRequest(proto.parse, async (e) => {
104
const uri = vscode.Uri.parse(e.uri);
105
if (typeof e.text === 'string') {
106
return parser.tokenize(new InMemoryDocument(uri, e.text, -1));
107
} else {
108
const doc = await workspace.getOrLoadMarkdownDocument(uri);
109
if (doc) {
110
return parser.tokenize(doc);
111
} else {
112
return [];
113
}
114
}
115
});
116
117
client.onRequest(proto.fs_readFile, async (e): Promise<number[]> => {
118
const uri = vscode.Uri.parse(e.uri);
119
return Array.from(await vscode.workspace.fs.readFile(uri));
120
});
121
122
client.onRequest(proto.fs_stat, async (e): Promise<{ isDirectory: boolean } | undefined> => {
123
const uri = vscode.Uri.parse(e.uri);
124
try {
125
const stat = await vscode.workspace.fs.stat(uri);
126
return { isDirectory: stat.type === vscode.FileType.Directory };
127
} catch {
128
return undefined;
129
}
130
});
131
132
client.onRequest(proto.fs_readDirectory, async (e): Promise<[string, { isDirectory: boolean }][]> => {
133
const uri = vscode.Uri.parse(e.uri);
134
const result = await vscode.workspace.fs.readDirectory(uri);
135
return result.map(([name, type]) => [name, { isDirectory: type === vscode.FileType.Directory }]);
136
});
137
138
client.onRequest(proto.findMarkdownFilesInWorkspace, async (): Promise<string[]> => {
139
return (await vscode.workspace.findFiles(mdFileGlob, '**/node_modules/**')).map(x => x.toString());
140
});
141
142
const watchers = new FileWatcherManager();
143
144
client.onRequest(proto.fs_watcher_create, async (params): Promise<void> => {
145
const id = params.id;
146
const uri = vscode.Uri.parse(params.uri);
147
148
const sendWatcherChange = (kind: 'create' | 'change' | 'delete') => {
149
client.sendRequest(proto.fs_watcher_onChange, { id, uri: params.uri, kind });
150
};
151
152
watchers.create(id, uri, params.watchParentDirs, {
153
create: params.options.ignoreCreate ? undefined : () => sendWatcherChange('create'),
154
change: params.options.ignoreChange ? undefined : () => sendWatcherChange('change'),
155
delete: params.options.ignoreDelete ? undefined : () => sendWatcherChange('delete'),
156
});
157
});
158
159
client.onRequest(proto.fs_watcher_delete, async (params): Promise<void> => {
160
watchers.delete(params.id);
161
});
162
163
vscode.commands.registerCommand('vscodeMarkdownLanguageservice.open', (uri, args) => {
164
return vscode.commands.executeCommand('vscode.open', uri, args);
165
});
166
167
vscode.commands.registerCommand('vscodeMarkdownLanguageservice.rename', (uri, pos) => {
168
return vscode.commands.executeCommand('editor.action.rename', [vscode.Uri.from(uri), new vscode.Position(pos.line, pos.character)]);
169
});
170
171
await client.start();
172
173
return new MdLanguageClient(client, workspace);
174
}
175
176