blob: 24d7efb3a41c192f4487d7c8d038e054bc9feb26 [file] [log] [blame]
// 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 "";
}