108 lines
3.3 KiB
TypeScript
108 lines
3.3 KiB
TypeScript
// Copyright 2022 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
import {CompletionContext} from '@codemirror/autocomplete'
|
|
import {syntaxTree} from '@codemirror/language'
|
|
import {Device} from "pigweedjs";
|
|
|
|
const completePropertyAfter = ['PropertyName', '.', '?.']
|
|
const dontCompleteIn = [
|
|
'TemplateString',
|
|
'LineComment',
|
|
'BlockComment',
|
|
'VariableDefinition',
|
|
'PropertyDefinition'
|
|
]
|
|
var objectPath = require("object-path");
|
|
|
|
export function completeFromGlobalScope(context: CompletionContext) {
|
|
let nodeBefore = syntaxTree(context.state).resolveInner(context.pos, -1)
|
|
|
|
if (
|
|
completePropertyAfter.includes(nodeBefore.name) &&
|
|
nodeBefore.parent?.name == 'MemberExpression'
|
|
) {
|
|
let object = nodeBefore.parent.getChild('Expression')
|
|
if (object?.name == 'VariableName') {
|
|
let from = /\./.test(nodeBefore.name) ? nodeBefore.to : nodeBefore.from
|
|
let variableName = context.state.sliceDoc(object.from, object.to)
|
|
// @ts-ignore
|
|
if (typeof window[variableName] == 'object') {
|
|
// @ts-ignore
|
|
return completeProperties(from, window[variableName])
|
|
}
|
|
}
|
|
else if (object?.name == 'MemberExpression') {
|
|
let from = /\./.test(nodeBefore.name) ? nodeBefore.to : nodeBefore.from
|
|
let variableName = context.state.sliceDoc(object.from, object.to)
|
|
let variable = resolveWindowVariable(variableName);
|
|
// @ts-ignore
|
|
if (typeof variable == 'object') {
|
|
// @ts-ignore
|
|
return completeProperties(from, variable, variableName)
|
|
}
|
|
}
|
|
} else if (nodeBefore.name == 'VariableName') {
|
|
return completeProperties(nodeBefore.from, window)
|
|
} else if (context.explicit && !dontCompleteIn.includes(nodeBefore.name)) {
|
|
return completeProperties(context.pos, window)
|
|
}
|
|
return null
|
|
}
|
|
|
|
function completeProperties(from: number, object: Object, variableName?: string) {
|
|
let options = []
|
|
for (let name in object) {
|
|
// @ts-ignore
|
|
if (object[name] instanceof Function && variableName) {
|
|
debugger;
|
|
options.push({
|
|
label: name,
|
|
// @ts-ignore
|
|
detail: getFunctionDetailText(`${variableName}.${name}`),
|
|
type: 'function'
|
|
})
|
|
}
|
|
else {
|
|
options.push({
|
|
label: name,
|
|
type: 'variable'
|
|
})
|
|
}
|
|
|
|
}
|
|
return {
|
|
from,
|
|
options,
|
|
validFor: /^[\w$]*$/
|
|
}
|
|
}
|
|
|
|
function resolveWindowVariable(variableName: string) {
|
|
if (objectPath.has(window, variableName)) {
|
|
return objectPath.get(window, variableName);
|
|
}
|
|
}
|
|
|
|
function getFunctionDetailText(fullExpression: string): string {
|
|
if (fullExpression.startsWith("device.rpcs.")) {
|
|
fullExpression = fullExpression.replace("device.rpcs.", "");
|
|
}
|
|
const args = ((window as any).device as Device).getMethodArguments(fullExpression);
|
|
if (args) {
|
|
return `(${args.join(", ")})`;
|
|
}
|
|
return "";
|
|
}
|