@kerebron/extension-codemirror 0.4.28 → 0.4.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/esm/ExtensionCodeMirror.js +1 -0
  2. package/esm/ExtensionCodeMirror.js.map +1 -0
  3. package/esm/NodeCodeMirror.js +1 -0
  4. package/esm/NodeCodeMirror.js.map +1 -0
  5. package/esm/codeMirrorBlockNodeView.js +1 -0
  6. package/esm/codeMirrorBlockNodeView.js.map +1 -0
  7. package/esm/defaults.js +1 -0
  8. package/esm/defaults.js.map +1 -0
  9. package/esm/languageLoaders.js +1 -0
  10. package/esm/languageLoaders.js.map +1 -0
  11. package/esm/languages.js +1 -0
  12. package/esm/languages.js.map +1 -0
  13. package/esm/lsp/LSPExtension.js +1 -0
  14. package/esm/lsp/LSPExtension.js.map +1 -0
  15. package/esm/lsp/completion.js +1 -0
  16. package/esm/lsp/completion.js.map +1 -0
  17. package/esm/lsp/hover.js +1 -0
  18. package/esm/lsp/hover.js.map +1 -0
  19. package/esm/lsp/index.js +1 -0
  20. package/esm/lsp/index.js.map +1 -0
  21. package/esm/lsp/plugin.js +1 -0
  22. package/esm/lsp/plugin.js.map +1 -0
  23. package/esm/lsp/pos.js +1 -0
  24. package/esm/lsp/pos.js.map +1 -0
  25. package/esm/lsp/text.js +1 -0
  26. package/esm/lsp/text.js.map +1 -0
  27. package/esm/lsp/theme.js +1 -0
  28. package/esm/lsp/theme.js.map +1 -0
  29. package/esm/remote-selections.js +1 -0
  30. package/esm/remote-selections.js.map +1 -0
  31. package/esm/remote-sync.js +1 -0
  32. package/esm/remote-sync.js.map +1 -0
  33. package/esm/types.js +1 -0
  34. package/esm/types.js.map +1 -0
  35. package/esm/utils.js +1 -0
  36. package/esm/utils.js.map +1 -0
  37. package/package.json +9 -5
  38. package/src/ExtensionCodeMirror.ts +84 -0
  39. package/src/NodeCodeMirror.ts +135 -0
  40. package/src/codeMirrorBlockNodeView.ts +400 -0
  41. package/src/defaults.ts +80 -0
  42. package/src/languageLoaders.ts +401 -0
  43. package/src/languages.ts +109 -0
  44. package/src/lsp/LSPExtension.ts +42 -0
  45. package/src/lsp/completion.ts +231 -0
  46. package/src/lsp/hover.ts +100 -0
  47. package/src/lsp/index.ts +55 -0
  48. package/src/lsp/plugin.ts +128 -0
  49. package/src/lsp/pos.ts +12 -0
  50. package/src/lsp/text.ts +63 -0
  51. package/src/lsp/theme.ts +81 -0
  52. package/src/remote-selections.ts +263 -0
  53. package/src/remote-sync.ts +23 -0
  54. package/src/types.ts +55 -0
  55. package/src/utils.ts +336 -0
  56. package/assets/codemirror.css +0 -80
@@ -0,0 +1,231 @@
1
+ import type * as lsp from 'vscode-languageserver-protocol';
2
+ import { EditorState, Extension, Facet } from '@codemirror/state';
3
+ import {
4
+ autocompletion,
5
+ Completion,
6
+ CompletionContext,
7
+ CompletionSource,
8
+ snippet,
9
+ } from '@codemirror/autocomplete';
10
+
11
+ import { LSPPlugin } from './plugin.js';
12
+ import { CompletionTriggerKind } from 'vscode-languageserver-protocol';
13
+
14
+ export function serverCompletion(config: {
15
+ override?: boolean;
16
+ validFor?: RegExp;
17
+ } = {}): Extension {
18
+ let result: Extension[];
19
+ if (config.override) {
20
+ result = [autocompletion({ override: [serverCompletionSource] })];
21
+ } else {
22
+ const data = [{ autocomplete: serverCompletionSource }];
23
+ result = [autocompletion(), EditorState.languageData.of(() => data)];
24
+ }
25
+ if (config.validFor) {
26
+ result.push(completionConfig.of({ validFor: config.validFor }));
27
+ }
28
+ return result;
29
+ }
30
+
31
+ const completionConfig = Facet.define<
32
+ { validFor: RegExp },
33
+ { validFor: RegExp | null }
34
+ >({
35
+ combine: (results) => results.length ? results[0] : { validFor: null },
36
+ });
37
+
38
+ async function getCompletions(
39
+ plugin: LSPPlugin,
40
+ pos: number,
41
+ context: lsp.CompletionContext,
42
+ abort?: CompletionContext,
43
+ ) {
44
+ const client = plugin.extensionLsp.getClient(plugin.lang);
45
+ if (!client) {
46
+ return [];
47
+ }
48
+
49
+ if (client.hasCapability('completionProvider') === false) {
50
+ null;
51
+ }
52
+ client.sync();
53
+ const params: lsp.CompletionParams = {
54
+ position: plugin.toPosition(pos),
55
+ textDocument: { uri: plugin.uri },
56
+ context,
57
+ };
58
+ if (abort) {
59
+ abort.addEventListener('abort', () => client.cancelRequest(params));
60
+ }
61
+ const result = await client.request<
62
+ lsp.CompletionParams,
63
+ lsp.CompletionItem[] | lsp.CompletionList | null
64
+ >(
65
+ 'textDocument/completion',
66
+ params,
67
+ );
68
+ return result;
69
+ }
70
+
71
+ // Look for non-alphanumeric prefixes in the completions, and return a
72
+ // regexp that matches them, to use in validFor
73
+ function prefixRegexp(items: readonly lsp.CompletionItem[]) {
74
+ let step = Math.ceil(items.length / 50), prefixes: string[] = [];
75
+ for (let i = 0; i < items.length; i += step) {
76
+ let item = items[i],
77
+ text = item.textEdit?.newText || item.textEditText || item.insertText ||
78
+ item.label;
79
+ if (!/^\w/.test(text)) {
80
+ let prefix = /^[^\w]*/.exec(text)![0];
81
+ if (prefixes.indexOf(prefix) < 0) prefixes.push(prefix);
82
+ }
83
+ }
84
+ if (!prefixes.length) return /^\w*$/;
85
+ return new RegExp(
86
+ '^(?:' + prefixes.map(
87
+ (RegExp as any).escape || ((s) => s.replace(/[^\w\s]/g, '\\$&')),
88
+ ).join('|') + ')?\\w*$',
89
+ );
90
+ }
91
+
92
+ /// A completion source that requests completions from a language
93
+ /// server.
94
+ export const serverCompletionSource: CompletionSource = async (context) => {
95
+ const plugin = context.view && LSPPlugin.get(context.view);
96
+ if (!plugin) return null;
97
+
98
+ let triggerChar = '';
99
+ if (!context.explicit) {
100
+ triggerChar = context.view.state.sliceDoc(context.pos - 1, context.pos);
101
+
102
+ const client = plugin.extensionLsp.getClient(plugin.lang);
103
+ if (!client) {
104
+ return null;
105
+ }
106
+
107
+ const triggers = client.serverCapabilities?.completionProvider
108
+ ?.triggerCharacters;
109
+ if (
110
+ !/[a-zA-Z_]/.test(triggerChar) &&
111
+ !(triggers && triggers.indexOf(triggerChar) > -1)
112
+ ) return null;
113
+ }
114
+
115
+ try {
116
+ let result = await getCompletions(plugin, context.pos, {
117
+ triggerCharacter: triggerChar,
118
+ triggerKind: context.explicit
119
+ ? CompletionTriggerKind.Invoked
120
+ : CompletionTriggerKind.TriggerCharacter,
121
+ }, context);
122
+
123
+ if (!result) return null;
124
+ if (Array.isArray(result)) {
125
+ result = { items: result } as lsp.CompletionList;
126
+ }
127
+
128
+ const { from, to } = completionResultRange(context, result);
129
+ const defaultCommitChars = result.itemDefaults?.commitCharacters;
130
+ const config = context.state.facet(completionConfig);
131
+
132
+ const options = result.items.map<Completion>((item) => {
133
+ let text = item.textEdit?.newText || item.textEditText ||
134
+ item.insertText || item.label;
135
+ let option: Completion = {
136
+ label: text,
137
+ type: item.kind && kindToType[item.kind],
138
+ };
139
+ if (
140
+ item.commitCharacters && item.commitCharacters != defaultCommitChars
141
+ ) {
142
+ option.commitCharacters = item.commitCharacters;
143
+ }
144
+ if (item.detail) option.detail = item.detail;
145
+ if (item.insertTextFormat == 2 /* Snippet */) {
146
+ option.apply = (view, c, from, to) => snippet(text)(view, c, from, to);
147
+ option.label = item.label;
148
+ }
149
+ if (item.documentation) {
150
+ option.info = () => renderDocInfo(plugin, item.documentation!);
151
+ }
152
+ return option;
153
+ });
154
+
155
+ return {
156
+ from,
157
+ to,
158
+ options,
159
+ commitCharacters: defaultCommitChars,
160
+ validFor: config.validFor ?? prefixRegexp(result.items),
161
+ map: (result, changes) => ({
162
+ ...result,
163
+ from: changes.mapPos(result.from),
164
+ }),
165
+ };
166
+ } catch (err: any) {
167
+ if (
168
+ 'code' in err &&
169
+ (err as lsp.ResponseError).code == -32800 /* RequestCancelled */
170
+ ) {
171
+ return null;
172
+ }
173
+ throw err;
174
+ }
175
+ };
176
+
177
+ function completionResultRange(
178
+ cx: CompletionContext,
179
+ result: lsp.CompletionList,
180
+ ): { from: number; to: number } {
181
+ if (!result.items.length) {
182
+ return { from: cx.pos, to: cx.pos };
183
+ }
184
+
185
+ const defaultRange = result.itemDefaults?.editRange;
186
+ const item0 = result.items[0];
187
+
188
+ const range = defaultRange
189
+ ? ('insert' in defaultRange ? defaultRange.insert : defaultRange)
190
+ : item0.textEdit
191
+ ? ('range' in item0.textEdit ? item0.textEdit.range : item0.textEdit.insert)
192
+ : null;
193
+
194
+ if (!range) return cx.state.wordAt(cx.pos) || { from: cx.pos, to: cx.pos };
195
+
196
+ const line = cx.state.doc.lineAt(cx.pos);
197
+
198
+ return {
199
+ from: line.from + range.start.character,
200
+ to: line.from + range.end.character,
201
+ };
202
+ }
203
+
204
+ function renderDocInfo(plugin: LSPPlugin, doc: string | lsp.MarkupContent) {
205
+ let elt = document.createElement('div');
206
+ elt.className = 'cm-lsp-documentation cm-lsp-completion-documentation';
207
+ elt.innerHTML = plugin.docToHTML(doc);
208
+ return elt;
209
+ }
210
+
211
+ const kindToType: { [kind: number]: string } = {
212
+ 1: 'text', // Text
213
+ 2: 'method', // Method
214
+ 3: 'function', // Function
215
+ 4: 'class', // Constructor
216
+ 5: 'property', // Field
217
+ 6: 'variable', // Variable
218
+ 7: 'class', // Class
219
+ 8: 'interface', // Interface
220
+ 9: 'namespace', // Module
221
+ 10: 'property', // Property
222
+ 11: 'keyword', // Unit
223
+ 12: 'constant', // Value
224
+ 13: 'constant', // Enum
225
+ 14: 'keyword', // Keyword
226
+ 16: 'constant', // Color
227
+ 20: 'constant', // EnumMember
228
+ 21: 'constant', // Constant
229
+ 22: 'class', // Struct
230
+ 25: 'type', // TypeParameter
231
+ };
@@ -0,0 +1,100 @@
1
+ import type * as lsp from 'vscode-languageserver-protocol';
2
+ import { EditorView, hoverTooltip, Tooltip } from '@codemirror/view';
3
+ import { Extension } from '@codemirror/state';
4
+ import {
5
+ highlightingFor,
6
+ language as languageFacet,
7
+ } from '@codemirror/language';
8
+ import { fromPosition } from './pos.js';
9
+ import { LSPPlugin } from './plugin.js';
10
+ // import {highlightCode} from "@lezer/highlight"
11
+ // import {escHTML} from "./text.ts"
12
+
13
+ /// Create an extension that queries the language server for hover
14
+ /// tooltips when the user hovers over the code with their pointer,
15
+ /// and displays a tooltip when the server provides one.
16
+ export function hoverTooltips(config: { hoverTime?: number } = {}): Extension {
17
+ return hoverTooltip(lspTooltipSource, {
18
+ hideOn: (tr) => tr.docChanged,
19
+ hoverTime: config.hoverTime,
20
+ });
21
+ }
22
+
23
+ function hoverRequest(plugin: LSPPlugin, pos: number) {
24
+ const client = plugin.getClient();
25
+ if (client?.hasCapability('hoverProvider') === false) {
26
+ return Promise.resolve(null);
27
+ }
28
+ client?.sync();
29
+ return client?.request<lsp.HoverParams, lsp.Hover | null>(
30
+ 'textDocument/hover',
31
+ {
32
+ position: plugin.toPosition(pos),
33
+ textDocument: { uri: plugin.uri },
34
+ },
35
+ );
36
+ }
37
+
38
+ function lspTooltipSource(
39
+ view: EditorView,
40
+ pos: number,
41
+ ): Promise<Tooltip | null> {
42
+ const plugin = LSPPlugin.get(view);
43
+ if (!plugin) return Promise.resolve(null);
44
+ return hoverRequest(plugin, pos).then((result) => {
45
+ if (!result) return null;
46
+ return {
47
+ pos: result.range
48
+ ? fromPosition(view.state.doc, result.range.start)
49
+ : pos,
50
+ end: result.range ? fromPosition(view.state.doc, result.range.end) : pos,
51
+ create() {
52
+ let elt = document.createElement('div');
53
+ elt.className = 'cm-lsp-hover-tooltip cm-lsp-documentation';
54
+ elt.innerHTML = renderTooltipContent(plugin, result.contents);
55
+ return { dom: elt };
56
+ },
57
+ above: true,
58
+ };
59
+ });
60
+ }
61
+
62
+ function renderTooltipContent(
63
+ plugin: LSPPlugin,
64
+ value: string | lsp.MarkupContent | lsp.MarkedString | lsp.MarkedString[],
65
+ ) {
66
+ if (Array.isArray(value)) {
67
+ return value.map((m) => renderCode(plugin, m)).join('<br>');
68
+ }
69
+ if (
70
+ typeof value == 'string' || typeof value == 'object' && 'language' in value
71
+ ) return renderCode(plugin, value);
72
+ return plugin.docToHTML(value);
73
+ }
74
+
75
+ function renderCode(plugin: LSPPlugin, code: lsp.MarkedString) {
76
+ if (typeof code == 'string') return plugin.docToHTML(code, 'markdown');
77
+ let { language, value } = code;
78
+ // return plugin.docToHTML(value, language); // TODO highlight language
79
+ return plugin.docToHTML(value, 'plaintext');
80
+ }
81
+
82
+ /*
83
+ function renderCode(plugin: LSPPlugin, code: lsp.MarkedString) {
84
+ if (typeof code == "string") return plugin.docToHTML(code, "markdown")
85
+ let {language, value} = code
86
+ let lang = plugin.client.config.highlightLanguage && plugin.client.config.highlightLanguage(language || "")
87
+ if (!lang) {
88
+ let viewLang = plugin.view.state.facet(languageFacet)
89
+ if (viewLang && (!language || viewLang.name == language)) lang = viewLang
90
+ }
91
+ if (!lang) return escHTML(value)
92
+ let result = ""
93
+ highlightCode(value, lang.parser.parse(value), {style: tags => highlightingFor(plugin.view.state, tags)}, (text, cls) => {
94
+ result += cls ? `<span class="${cls}">${escHTML(text)}</span>` : escHTML(text)
95
+ }, () => {
96
+ result += "<br>"
97
+ })
98
+ return result
99
+ }
100
+ */
@@ -0,0 +1,55 @@
1
+ import { Extension } from '@codemirror/state';
2
+ import { keymap } from '@codemirror/view';
3
+
4
+ export { LSPExtension, type LSPExtensionConfig } from './LSPExtension.js';
5
+ export { LSPPlugin } from './plugin.js';
6
+ export { serverCompletion, serverCompletionSource } from './completion.js';
7
+ export { hoverTooltips } from './hover.js';
8
+ // export { formatDocument, formatKeymap } from './formatting.ts';
9
+ // export { renameKeymap, renameSymbol } from './rename.ts';
10
+ // export {
11
+ // nextSignature,
12
+ // prevSignature,
13
+ // showSignatureHelp,
14
+ // signatureHelp,
15
+ // signatureKeymap,
16
+ // } from './signature.ts';
17
+ // export {
18
+ // jumpToDeclaration,
19
+ // jumpToDefinition,
20
+ // jumpToDefinitionKeymap,
21
+ // jumpToImplementation,
22
+ // jumpToTypeDefinition,
23
+ // } from './definition.ts';
24
+ // export {
25
+ // closeReferencePanel,
26
+ // findReferences,
27
+ // findReferencesKeymap,
28
+ // } from './references.ts';
29
+ // export { serverDiagnostics } from './diagnostics.ts';
30
+
31
+ import { serverCompletion } from './completion.js';
32
+ import { hoverTooltips } from './hover.js';
33
+ // import { formatKeymap } from './formatting.ts';
34
+ // import { renameKeymap } from './rename.ts';
35
+ // import { signatureHelp } from './signature.ts';
36
+ // import { jumpToDefinitionKeymap } from './definition.ts';
37
+ // import { findReferencesKeymap } from './references.ts';
38
+ // import { serverDiagnostics } from './diagnostics.ts';
39
+
40
+ export function languageServerExtensions(): readonly (
41
+ Extension
42
+ )[] {
43
+ return [
44
+ serverCompletion(),
45
+ hoverTooltips(),
46
+ keymap.of([
47
+ // ...formatKeymap,
48
+ // ...renameKeymap,
49
+ // ...jumpToDefinitionKeymap,
50
+ // ...findReferencesKeymap,
51
+ ]),
52
+ // signatureHelp(),
53
+ // serverDiagnostics(),
54
+ ];
55
+ }
@@ -0,0 +1,128 @@
1
+ import type * as lsp from 'vscode-languageserver-protocol';
2
+ import { EditorView, ViewPlugin } from '@codemirror/view';
3
+ import { Text } from '@codemirror/state';
4
+
5
+ import { type CoreEditor, RawTextResult } from '@kerebron/editor';
6
+ import type {
7
+ ExtensionLsp,
8
+ LSPClient,
9
+ LspSource,
10
+ } from '@kerebron/extension-lsp';
11
+
12
+ import { fromPosition, toPosition } from './pos.js';
13
+ import { escHTML } from './text.js';
14
+ import { LSPExtension } from './index.js';
15
+ import { PositionMapper } from '@kerebron/extension-markdown/PositionMapper';
16
+ import { toRawTextResult } from '@kerebron/editor/utilities';
17
+
18
+ export class LSPPlugin {
19
+ readonly extensionLsp: ExtensionLsp;
20
+ readonly uri: string;
21
+ readonly editor: CoreEditor;
22
+ readonly extension: LSPExtension;
23
+ lang = 'plaintext';
24
+ client?: LSPClient;
25
+ source: LspSource;
26
+
27
+ /// @internal
28
+ constructor(
29
+ /// The editor view that this plugin belongs to.
30
+ readonly view: EditorView,
31
+ { extension, extensionLsp, uri, editor }: {
32
+ extension: LSPExtension;
33
+ extensionLsp: ExtensionLsp;
34
+ uri: string;
35
+ editor: CoreEditor;
36
+ },
37
+ ) {
38
+ this.extension = extension;
39
+ this.extensionLsp = extensionLsp;
40
+ this.uri = uri;
41
+ this.editor = editor;
42
+
43
+ this.source = {
44
+ ui: this.editor.ui,
45
+ getMappedContent: async () => {
46
+ const editor = this.editor;
47
+ const result: RawTextResult = toRawTextResult(
48
+ this.view.state.doc.toString().toString(),
49
+ 0,
50
+ );
51
+ const mapper = new PositionMapper(editor, result.rawTextMap);
52
+ return {
53
+ ...result,
54
+ mapper,
55
+ };
56
+ },
57
+ };
58
+ }
59
+
60
+ getClient() {
61
+ return this.client;
62
+ }
63
+
64
+ setLang(lang: string) {
65
+ this.lang = lang;
66
+
67
+ const client = this.extensionLsp.getClient(lang);
68
+ this.client = client;
69
+ if (client) {
70
+ client.disconnect(this.uri);
71
+ client.connect(this.uri, this.source);
72
+ client.workspace.openFile(
73
+ this.uri,
74
+ lang,
75
+ this.source,
76
+ );
77
+ }
78
+ }
79
+
80
+ update() {
81
+ if (this.client) {
82
+ this.client.workspace.changedFile(
83
+ this.uri,
84
+ );
85
+ }
86
+ }
87
+
88
+ // /// Render a doc string from the server to HTML.
89
+ // docToHTML(value: string | lsp.MarkupContent, defaultKind: lsp.MarkupKind = "plaintext") {
90
+ // let html = withContext(this.view, this.client.config.highlightLanguage, () => docToHTML(value, defaultKind))
91
+ // return this.client.config.sanitizeHTML ? this.client.config.sanitizeHTML(html) : html
92
+ // }
93
+
94
+ docToHTML(
95
+ value: string | lsp.MarkupContent,
96
+ defaultKind: lsp.MarkupKind = 'plaintext',
97
+ ) {
98
+ if ('string' === typeof value) {
99
+ return escHTML(value);
100
+ }
101
+ return `docToHTML ${value.kind} ${JSON.stringify(value.value, null, 2)}`;
102
+ }
103
+
104
+ /// Convert a CodeMirror document offset into an LSP `{line,
105
+ /// character}` object. Defaults to using the view's current
106
+ /// document, but can be given another one.
107
+ toPosition(pos: number, doc: Text = this.view.state.doc): lsp.Position {
108
+ return toPosition(doc, pos);
109
+ }
110
+
111
+ /// Convert an LSP `{line, character}` object to a CodeMirror
112
+ /// document offset.
113
+ fromPosition(pos: lsp.Position, doc: Text = this.view.state.doc): number {
114
+ return fromPosition(doc, pos);
115
+ }
116
+
117
+ /// Display an error in this plugin's editor.
118
+ reportError(message: string, err: any) {
119
+ this.editor.ui.showError(err);
120
+ }
121
+
122
+ /// Get the LSP plugin associated with an editor, if any.
123
+ static get(view: EditorView) {
124
+ return view.plugin(lspPlugin);
125
+ }
126
+ }
127
+
128
+ export const lspPlugin = ViewPlugin.fromClass(LSPPlugin);
package/src/lsp/pos.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type * as lsp from 'vscode-languageserver-protocol';
2
+ import { Text } from '@codemirror/state';
3
+
4
+ export function toPosition(doc: Text, pos: number): lsp.Position {
5
+ let line = doc.lineAt(pos);
6
+ return { line: line.number - 1, character: pos - line.from };
7
+ }
8
+
9
+ export function fromPosition(doc: Text, pos: lsp.Position): number {
10
+ let line = doc.line(pos.line + 1);
11
+ return line.from + pos.character;
12
+ }
@@ -0,0 +1,63 @@
1
+ import type * as lsp from 'vscode-languageserver-protocol';
2
+ import { EditorView } from '@codemirror/view';
3
+ import {
4
+ highlightingFor,
5
+ Language,
6
+ language as languageFacet,
7
+ } from '@codemirror/language';
8
+ // import {Marked} from "marked"
9
+ // import {highlightCode, Highlighter} from "@lezer/highlight"
10
+
11
+ // let context: {view: EditorView, language: ((name: string) => Language | null) | undefined} | null = null
12
+
13
+ // export function withContext<T>(view: EditorView, language: ((name: string) => Language | null) | undefined, f: () => T): T {
14
+ // let prev = context
15
+ // try {
16
+ // context = {view, language}
17
+ // return f()
18
+ // } finally {
19
+ // context = prev
20
+ // }
21
+ // }
22
+
23
+ export function escHTML(text: string) {
24
+ return text.replace(
25
+ /[\n<&]/g,
26
+ (ch) => ch == '\n' ? '<br>' : ch == '<' ? '&lt;' : '&amp;',
27
+ );
28
+ }
29
+
30
+ // const marked = new Marked({
31
+ // walkTokens(token) {
32
+ // if (!context || token.type != "code") return
33
+
34
+ // let lang = context.language && context.language(token.lang)
35
+ // if (!lang) {
36
+ // let viewLang = context.view.state.facet(languageFacet)
37
+ // if (viewLang && viewLang.name == token.lang) lang = viewLang
38
+ // }
39
+ // if (!lang) return
40
+ // let highlighter: Highlighter = {style: tags => highlightingFor(context!.view.state, tags)}
41
+ // let result = ""
42
+ // highlightCode(token.text, lang.parser.parse(token.text), highlighter, (text, cls) => {
43
+ // result += cls ? `<span class="${cls}">${escHTML(text)}</span>` : escHTML(text)
44
+ // }, () => {
45
+ // result += "<br>"
46
+ // })
47
+ // token.escaped = true
48
+ // token.text = result
49
+ // }
50
+ // })
51
+
52
+ // export function docToHTML(value: string | lsp.MarkupContent, defaultKind: lsp.MarkupKind) {
53
+ // let kind = defaultKind, text = value
54
+ // if (typeof text != "string") {
55
+ // kind = text.kind
56
+ // text = text.value
57
+ // }
58
+ // if (kind == "plaintext") {
59
+ // return escHTML(text)
60
+ // } else {
61
+ // return marked.parse(text, {async: false, })
62
+ // }
63
+ // }
@@ -0,0 +1,81 @@
1
+ import { EditorView } from '@codemirror/view';
2
+
3
+ export const lspTheme = EditorView.baseTheme({
4
+ '.cm-lsp-documentation': {
5
+ padding: '0 7px',
6
+ '& p, & pre': {
7
+ margin: '2px 0',
8
+ },
9
+ },
10
+
11
+ '.cm-lsp-signature-tooltip': {
12
+ padding: '2px 6px',
13
+ borderRadius: '2.5px',
14
+ position: 'relative',
15
+ maxWidth: '30em',
16
+ maxHeight: '10em',
17
+ overflowY: 'scroll',
18
+ '& .cm-lsp-documentation': {
19
+ padding: '0',
20
+ fontSize: '80%',
21
+ },
22
+ '& .cm-lsp-signature-num': {
23
+ fontFamily: 'monospace',
24
+ position: 'absolute',
25
+ left: '2px',
26
+ top: '4px',
27
+ fontSize: '70%',
28
+ lineHeight: '1.3',
29
+ },
30
+ '& .cm-lsp-signature': {
31
+ fontFamily: 'monospace',
32
+ textIndent: '1em hanging',
33
+ },
34
+ '& .cm-lsp-active-parameter': {
35
+ fontWeight: 'bold',
36
+ },
37
+ },
38
+ '.cm-lsp-signature-multiple': {
39
+ paddingLeft: '1.5em',
40
+ },
41
+
42
+ '.cm-panel.cm-lsp-rename-panel': {
43
+ padding: '2px 6px 4px',
44
+ position: 'relative',
45
+ '& label': { fontSize: '80%' },
46
+ '& [name=close]': {
47
+ position: 'absolute',
48
+ top: '0',
49
+ bottom: '0',
50
+ right: '4px',
51
+ backgroundColor: 'inherit',
52
+ border: 'none',
53
+ font: 'inherit',
54
+ padding: '0',
55
+ },
56
+ },
57
+
58
+ '.cm-lsp-message button[type=submit]': {
59
+ display: 'block',
60
+ },
61
+
62
+ '.cm-lsp-reference-panel': {
63
+ fontFamily: 'monospace',
64
+ whiteSpace: 'pre',
65
+ padding: '3px 6px',
66
+ maxHeight: '120px',
67
+ overflow: 'auto',
68
+ '& .cm-lsp-reference-file': {
69
+ fontWeight: 'bold',
70
+ },
71
+ '& .cm-lsp-reference': {
72
+ cursor: 'pointer',
73
+ '&[aria-selected]': {
74
+ backgroundColor: '#0077ee44',
75
+ },
76
+ },
77
+ '& .cm-lsp-reference-line': {
78
+ opacity: '0.7',
79
+ },
80
+ },
81
+ });