Skip to content

Commit 5712aae

Browse files
committed
sv
1 parent a6b1cef commit 5712aae

File tree

7 files changed

+71
-19
lines changed

7 files changed

+71
-19
lines changed

spx-gui/src/components/editor/code-editor/code-editor.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { Runtime } from '@/models/runtime'
88
import type { Project } from '@/models/project'
99
import { Copilot } from './copilot'
1010
import { DocumentBase } from './document-base'
11-
import { SpxLSPClient } from './lsp'
11+
import { SpxLSPClient, semanticTokenLegend } from './lsp'
1212
import {
1313
type ICodeEditorUI,
1414
type DiagnosticsContext,
@@ -55,7 +55,8 @@ import {
5555
type CommandArgs,
5656
getTextDocumentId,
5757
containsPosition,
58-
makeBasicMarkdownString
58+
makeBasicMarkdownString,
59+
fromMonacoUri
5960
} from './common'
6061
import { TextDocument, createTextDocument } from './text-document'
6162
import { type Monaco } from './monaco'
@@ -542,6 +543,22 @@ export class CodeEditor extends Disposable {
542543

543544
init() {
544545
this.lspClient.init()
546+
547+
this.addDisposable(
548+
this.monaco.languages.registerDocumentSemanticTokensProvider('spx', {
549+
getLegend: () => semanticTokenLegend,
550+
provideDocumentSemanticTokens: async (model) => {
551+
const tokens = await this.lspClient.textDocumentSemanticTokens({
552+
textDocument: fromMonacoUri(model.uri)
553+
})
554+
if (tokens == null) return { data: new Uint32Array(0) }
555+
return { data: new Uint32Array(tokens.data) } // TODO: pass data with array buffer instead of number array
556+
},
557+
releaseDocumentSemanticTokens() {
558+
// do nothing
559+
}
560+
})
561+
)
545562
}
546563

547564
dispose(): void {

spx-gui/src/components/editor/code-editor/common.ts

+9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Costume } from '@/models/costume'
1111
import { Animation } from '@/models/animation'
1212
import { isWidget } from '@/models/widget'
1313
import { stageCodeFilePaths } from '@/models/stage'
14+
import type { Monaco, monaco } from './monaco'
1415

1516
export type Position = {
1617
line: number
@@ -562,3 +563,11 @@ export function textDocumentId2CodeFileName(id: TextDocumentIdentifier) {
562563
return { en: spriteName, zh: spriteName }
563564
}
564565
}
566+
567+
export function fromMonacoUri(uri: monaco.Uri): TextDocumentIdentifier {
568+
return { uri: uri.toString() }
569+
}
570+
571+
export function toMonacoUri(id: TextDocumentIdentifier, monaco: Monaco): monaco.Uri {
572+
return monaco.Uri.parse(id.uri)
573+
}

spx-gui/src/components/editor/code-editor/lsp/index.ts

+32
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ export class SpxLSPClient extends Disposable {
163163
return spxlc.request<lsp.TextEdit[] | null>(lsp.DocumentFormattingRequest.method, params)
164164
}
165165

166+
async textDocumentSemanticTokens(params: lsp.SemanticTokensParams): Promise<lsp.SemanticTokens | null> {
167+
const spxlc = await this.prepareRequest()
168+
return spxlc.request<lsp.SemanticTokens | null>(lsp.SemanticTokensRequest.method, params)
169+
}
170+
166171
// Higher-level APIs
167172

168173
async getResourceReferences(textDocument: TextDocumentIdentifier): Promise<ResourceReference[]> {
@@ -200,3 +205,30 @@ export class SpxLSPClient extends Disposable {
200205
return completionResult as CompletionItem[]
201206
}
202207
}
208+
209+
// Keep in sync with `tools/spxls/internal/server/semantic_token.go`
210+
export const semanticTokenLegend = {
211+
tokenTypes: [
212+
lsp.SemanticTokenTypes.namespace,
213+
lsp.SemanticTokenTypes.type,
214+
lsp.SemanticTokenTypes.interface,
215+
lsp.SemanticTokenTypes.struct,
216+
lsp.SemanticTokenTypes.parameter,
217+
lsp.SemanticTokenTypes.variable,
218+
lsp.SemanticTokenTypes.property,
219+
lsp.SemanticTokenTypes.function,
220+
lsp.SemanticTokenTypes.method,
221+
lsp.SemanticTokenTypes.keyword,
222+
lsp.SemanticTokenTypes.comment,
223+
lsp.SemanticTokenTypes.string,
224+
lsp.SemanticTokenTypes.number,
225+
lsp.SemanticTokenTypes.operator,
226+
'label' // since LSP 3.18.0, Not supported by `vscode-languageserver-protocol` yet
227+
],
228+
tokenModifiers: [
229+
lsp.SemanticTokenModifiers.declaration,
230+
lsp.SemanticTokenModifiers.readonly,
231+
lsp.SemanticTokenModifiers.static,
232+
lsp.SemanticTokenModifiers.defaultLibrary
233+
]
234+
}

spx-gui/src/components/editor/code-editor/text-document.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
type TextDocumentIdentifier,
1212
type WordAtPosition,
1313
type TextEdit,
14-
getTextDocumentId
14+
getTextDocumentId,
15+
toMonacoUri
1516
} from './common'
1617
import { toMonacoPosition, toMonacoRange, fromMonacoPosition } from './ui/common'
1718
import type { Monaco, monaco } from './monaco'
@@ -114,7 +115,11 @@ export class TextDocument
114115
) {
115116
super()
116117

117-
this.monacoTextModel = monaco.editor.createModel(codeOwner.getCode() ?? '', 'spx')
118+
this.monacoTextModel = monaco.editor.createModel(
119+
codeOwner.getCode() ?? '',
120+
'spx',
121+
toMonacoUri(this.codeOwner.getTextDocumentId(), monaco)
122+
)
118123

119124
this.addDisposer(
120125
watch(

spx-gui/src/components/editor/code-editor/ui/CodeEditorUI.vue

+3-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ const monacoEditorOptions = computed<monaco.editor.IStandaloneEditorConstruction
128128
tabSize,
129129
insertSpaces,
130130
fontSize: fontSize.value,
131-
contextmenu: false
131+
contextmenu: false,
132+
// TODO: preserve `semanticHighlighting` of theme (in `@shikijs/monaco`), then remove this line
133+
'semanticHighlighting.enabled': true
132134
}))
133135
134136
const monacEditorInitDataRef = shallowRef<MonacoEditorInitData | null>(null)

spx-gui/src/components/editor/code-editor/ui/common.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import type { ResourceModel } from '@/models/common/resource-model'
44
import { Sprite } from '@/models/sprite'
55
import { Sound } from '@/models/sound'
66
import { isWidget } from '@/models/widget'
7-
import { type Range, type Position, type TextDocumentIdentifier, type Selection } from '../common'
8-
import type { Monaco } from '../monaco'
7+
import { type Range, type Position, type Selection } from '../common'
98

109
export function token2Signal(token: monaco.CancellationToken): AbortSignal {
1110
const ctrl = new AbortController()
@@ -60,15 +59,6 @@ export function toMonacoSelection(selection: Selection): monaco.ISelection {
6059
}
6160
}
6261

63-
export function fromMonacoUri(uri: monaco.Uri): TextDocumentIdentifier {
64-
// TODO: check if this is correct
65-
return { uri: uri.toString() }
66-
}
67-
68-
export function toMonacoUri(id: TextDocumentIdentifier, monaco: Monaco): monaco.Uri {
69-
return monaco.Uri.parse(id.uri)
70-
}
71-
7262
export function supportGoTo(resourceModel: ResourceModel): boolean {
7363
// Currently, we do not support "go to detail" for other types of resources due to two reasons:
7464
// 1. The "selected" state of certain resource types, such as animations, is still managed within the Component, making it difficult to control from here.

spx-gui/src/utils/spx/gop-tm-language.json

-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
"name": "GoPlus",
66
"scopeName": "source.gop",
77
"patterns": [
8-
{
9-
"include": "#statements"
10-
}
118
],
129
"repository": {
1310
"statements": {

0 commit comments

Comments
 (0)