Procházet zdrojové kódy

Editor: add definition provider

bdbai před 3 roky
rodič
revize
55f48a17e1

+ 120 - 0
Maple.App/MonacoEditor/src/definition.ts

@@ -0,0 +1,120 @@
+import * as monaco from 'monaco-editor'
+import { findIndexOfSections, ILeafConfKvItem, ILeafConfStruct, parseKvLine, parseStruct, splitByComma, trimComment } from './parse'
+import * as facts from './facts'
+
+function findProxyOrGroupKeyLocation(
+    model: monaco.editor.ITextModel,
+    struct: ILeafConfStruct,
+    targetName: string,
+): monaco.languages.Location | undefined {
+    const defKv = struct.sections.filter(s =>
+        s.sectionName === facts.SECTION_PROXY || s.sectionName === facts.SECTION_PROXY_GROUP
+    )
+        .flatMap(s => Array.from({ length: s.endLine - s.startLine + 1 }, (_, i) => s.startLine + i))
+        .map(lineId => parseKvLine(model.getLineContent(lineId), lineId, 1))
+        .filter((kv): kv is ILeafConfKvItem => kv !== undefined)
+        .find(kv => kv.key === targetName)
+    if (defKv === undefined) {
+        return undefined
+    }
+    return {
+        uri: model.uri,
+        range: new monaco.Range(
+            defKv.lineId,
+            defKv.keyStartCol,
+            defKv.lineId,
+            defKv.keyStartCol + defKv.key.length,
+        ),
+    }
+}
+
+function provideDefinitionForProxy(
+    model: monaco.editor.ITextModel,
+    position: monaco.Position,
+): monaco.languages.Location | undefined {
+    const lineId = position.lineNumber
+    const kv = parseKvLine(model.getLineContent(lineId), lineId, 1)
+    if (kv === undefined) {
+        return undefined
+    }
+    if (position.column > kv.keyStartCol + kv.key.length) {
+        return undefined
+    }
+    return {
+        uri: model.uri,
+        range: new monaco.Range(lineId, kv.keyStartCol, lineId, kv.keyStartCol + kv.key.length),
+    }
+}
+
+function provideDefinitionForProxyGroup(
+    model: monaco.editor.ITextModel,
+    struct: ILeafConfStruct,
+    position: monaco.Position,
+): monaco.languages.Location | undefined {
+    const lineId = position.lineNumber
+    const kv = parseKvLine(model.getLineContent(lineId), lineId, 1)
+    if (kv === undefined) {
+        return undefined
+    }
+    if (position.column <= kv.keyStartCol + kv.key.length) {
+        return {
+            uri: model.uri,
+            range: new monaco.Range(lineId, kv.keyStartCol, lineId, kv.keyStartCol + kv.key.length),
+        }
+    }
+
+    const args = splitByComma(kv.value, kv.valueStartCol)
+    const currentArgId = kv.value.substring(0, position.column - kv.valueStartCol).split(',').length - 1
+    const targetName = args[currentArgId].text
+    if (targetName.includes('=')) {
+        return undefined
+    }
+    return findProxyOrGroupKeyLocation(model, struct, targetName)
+}
+
+function provideDefinitionForRule(
+    model: monaco.editor.ITextModel,
+    struct: ILeafConfStruct,
+    position: monaco.Position,
+): monaco.languages.Location | undefined {
+    const lineId = position.lineNumber
+    const line = trimComment(model.getLineContent(lineId))
+
+    const args = splitByComma(line, 1)
+    const currentArgId = line.substring(0, position.column - 1).split(',').length - 1
+    if (currentArgId === 0) {
+        return undefined
+    }
+    const ruleType = args[0].text
+    let targetName = args[currentArgId].text
+    if (ruleType === facts.RULE_TYPE_FINAL && currentArgId === 1 || currentArgId === 2) {
+        targetName = args[currentArgId].text
+    } else {
+        return undefined
+    }
+    if (targetName.includes('=')) {
+        return undefined
+    }
+    return findProxyOrGroupKeyLocation(model, struct, targetName)
+}
+
+export const definitionProvider: monaco.languages.DefinitionProvider = {
+    provideDefinition(model, position, token) {
+        const lineId = position.lineNumber
+        const struct = parseStruct(model)
+        const sectionId = findIndexOfSections(struct.sections, lineId)
+        if (sectionId === -1) {
+            return undefined
+        }
+        const section = struct.sections[sectionId]
+        switch (section.sectionName) {
+            case facts.SECTION_PROXY:
+                return provideDefinitionForProxy(model, position)
+            case facts.SECTION_PROXY_GROUP:
+                return provideDefinitionForProxyGroup(model, struct, position)
+            case facts.SECTION_RULE:
+                return provideDefinitionForRule(model, struct, position)
+        }
+        return undefined
+    },
+}

+ 2 - 0
Maple.App/MonacoEditor/src/init.ts

@@ -3,6 +3,7 @@ import { monarchTokenProvider } from './monarch'
 import { foldingRangeProvider } from './folding'
 import { foldingRangeProvider } from './folding'
 import { completionProvider } from './completion'
 import { completionProvider } from './completion'
 import { validateModel } from './validate'
 import { validateModel } from './validate'
+import { definitionProvider } from './definition'
 
 
 declare global {
 declare global {
     interface Window {
     interface Window {
@@ -47,6 +48,7 @@ function initLang() {
     monaco.languages.setMonarchTokensProvider('leafConf', monarchTokenProvider)
     monaco.languages.setMonarchTokensProvider('leafConf', monarchTokenProvider)
     monaco.languages.registerCompletionItemProvider('leafConf', completionProvider)
     monaco.languages.registerCompletionItemProvider('leafConf', completionProvider)
     monaco.languages.registerFoldingRangeProvider('leafConf', foldingRangeProvider)
     monaco.languages.registerFoldingRangeProvider('leafConf', foldingRangeProvider)
+    monaco.languages.registerDefinitionProvider('leafConf', definitionProvider)
 
 
     const editor = monaco.editor.create(document.getElementById('container')!, {
     const editor = monaco.editor.create(document.getElementById('container')!, {
         wordBasedSuggestions: false,
         wordBasedSuggestions: false,