-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathnode-completion.ts
92 lines (76 loc) · 4.02 KB
/
node-completion.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import { CompletionItem } from 'vscode-languageserver'
import { Body, Class, Describe, Entity, Environment, Import, Method, Mixin, New, Node, Package, Program, Reference, Singleton, Test, Variable, implicitImport, match, parentImport, when } from 'wollok-ts'
import { logger } from '../../utils/logger'
import { classCompletionItem, entityCompletionItem, fieldCompletionItem, initializerCompletionItem, parameterCompletionItem, singletonCompletionItem, variableCompletionItem, withImport } from './autocomplete'
import { optionAsserts, optionConstReferences, optionDescribes, optionImports, optionInitialize, optionMethods, optionModules, optionPrograms, optionPropertiesAndReferences, optionReferences, optionTests } from './options-autocomplete'
export const completionsForNode = (node: Node): CompletionItem[] => {
try {
return match(node)(
when(Environment)(_ => []),
when(Package)(completePackage),
when(Singleton)(completeModule),
when(Class)(completeModule),
when(Mixin)(completeModule),
when(Program)(completeProgram),
when(Test)(completeTest),
when(Body)(completeBody),
when(Method)(completeMethod),
when(Describe)(completeDescribe),
when(Reference<Class>)(completeReference),
when(New)(completeNew)
)
} catch (error) {
logger.error(`✘ Completions for node failed: ${error}`, error)
return completeForParent(node)
}
}
const isTestFile = (node: Node) => node.sourceFileName?.endsWith('wtest')
const isProgramFile = (node: Node) => node.sourceFileName?.endsWith('wpgm')
const completePackage = (node: Package): CompletionItem[] => [
...optionImports,
...optionConstReferences,
...isTestFile(node) ? optionDescribes : isProgramFile(node) ? optionPrograms : optionModules,
]
const completeProgram = (): CompletionItem[] => [
...optionReferences,
]
const completeTest = (node: Test): CompletionItem[] => [
...optionReferences,
...optionAsserts,
...node.parent.is(Describe) ? node.parent.allFields.map(fieldCompletionItem) : [],
...completeAllSigletons(node),
]
const completeModule = (): CompletionItem[] => [
...optionPropertiesAndReferences,
...optionMethods,
]
const completeBody = (node: Body): CompletionItem[] => [
...completeForParent(node),
...node.scope.localContributions()
.filter((value) => value[1].is(Variable))
.map((value) => variableCompletionItem(value[1] as Variable)),
]
const completeMethod = (node: Method): CompletionItem[] => {
const parent = node.parent
return [
...node.parameters.map(parameterCompletionItem),
...parent.fields.map(fieldCompletionItem),
...completeAllSigletons(node),
]
}
const completeDescribe = (node: Describe): CompletionItem[] => isTestFile(node) ? [...optionConstReferences, ...optionTests, ...optionInitialize] : []
export const completeForParent = (node: Node): CompletionItem[] => {
if (!node.parent) throw new Error('Node has no parent')
return completionsForNode(node.parent)
}
const completeReference = (node: Reference<Class>): CompletionItem[] => {
const nodeImport = parentImport(node)
if (nodeImport) return completeImports(nodeImport)
const classes = node.environment.descendants.filter(child => child.is(Class) && !child.isAbstract) as Class[]
return classes.map(withImport(classCompletionItem)(node)).concat(completeForParent(node))
}
const completeNew = (node: New): CompletionItem[] =>
node.instantiated.target && node.instantiated.target.is(Class) ? [withImport(initializerCompletionItem)(node)(node.instantiated.target)] : []
const availableForImport = (node: Node) => (node.is(Class) || node.is(Singleton) || node.is(Reference) || node.is(Mixin)) && node.name && (node as Entity).fullyQualifiedName && !implicitImport(node)
const completeImports = (node: Import) => (node.environment.descendants.filter(availableForImport) as Entity[]).map(entityCompletionItem)
const completeAllSigletons = (originNode: Node) => (originNode.environment.descendants.filter(node => node.is(Singleton) && !node.isClosure()) as Singleton[]).map(withImport(singletonCompletionItem)(originNode))