Skip to content

Commit 34aa0bc

Browse files
authored
Merge pull request #47 from lets-cli/add-ref-reference-and-completion
add ref reference and completion
2 parents a09a51f + 142322b commit 34aa0bc

File tree

15 files changed

+840
-395
lines changed

15 files changed

+840
-395
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ File type recognition for `lets.yaml` and `lets.*.yaml` configs
1414
- **Completion**
1515
- [x] Complete command `options` with code snippet
1616
- [x] Complete commands in `depends` with code snippet
17-
- [ ] Complete commands in `depends` from mixins
17+
- [x] Complete commands in `depends` from mixins
1818
- [ ] Complete env mode in `env` with code snippet
1919
- [x] Complete `LETS*` environment variables in cmd scripts
2020
- [ ] Complete environment variables for checksum
@@ -26,7 +26,7 @@ File type recognition for `lets.yaml` and `lets.*.yaml` configs
2626
- [x] Navigate to definitions of `mixins` remote files (as http links)
2727
- [x] Navigate to definitions of commands in `depends`
2828
- [x] Navigate to definitions of commands in `depends` from mixins
29-
- [ ] Navigate to definitions of commands in `ref`
29+
- [x] Navigate to definitions of commands in `ref`
3030
- [ ] Navigate to files in `checksum`
3131
- **Highlighting**
3232
- [x] Highlighting for shell script in `cmd`
Lines changed: 68 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.github.kindermax.intellijlets
22

3-
import com.intellij.psi.PsiFile
4-
import org.jetbrains.yaml.psi.YAMLDocument
53
import org.jetbrains.yaml.psi.YAMLKeyValue
64
import org.jetbrains.yaml.psi.YAMLMapping
75
import org.jetbrains.yaml.psi.YAMLScalar
@@ -29,75 +27,83 @@ data class Command(
2927
val cmdAsMap: Map<String, String>,
3028
val env: Env,
3129
val depends: List<String>,
30+
val yaml: YAMLKeyValue,
3231
)
3332

34-
open class ConfigException(message: String) : Exception(message)
35-
36-
class ConfigParseException(message: String) : ConfigException(message)
37-
class CommandParseException(message: String) : ConfigException(message)
33+
class ConfigParser {
34+
companion object {
35+
// @Suppress("NestedBlockDepth")
36+
fun parseCommand(obj: YAMLKeyValue): Command {
37+
val name = obj.keyText
38+
var depends = emptyList<String>()
3839

39-
/**
40-
* Representation of current lets.yaml.
41-
* Note that since we parse config during completion, the config itself may be broken at that moment,
42-
* so we should parse gracefully.
43-
*/
44-
@Suppress("LongParameterList")
45-
class Config(
46-
val shell: String,
47-
val commands: List<Command>,
48-
val commandsMap: Map<String, Command>,
49-
val env: Env,
50-
val before: String,
51-
val init: String,
52-
val mixins: Mixins,
53-
// Keywords that are used in the config
54-
val keywordsInConfig: Set<String>,
55-
) {
40+
var cmd = ""
41+
var cmdAsMap = emptyMap<String, String>()
42+
var env: Env = emptyMap()
5643

57-
companion object Parser {
58-
// TODO parse mixins
59-
fun parseFromPSI(file: PsiFile): Config {
60-
return when (val child = file.firstChild) {
61-
is YAMLDocument -> {
62-
when (val value = child.topLevelValue) {
63-
is YAMLMapping -> parseConfigFromMapping(value)
64-
else -> defaultConfig()
44+
when (val value = obj.value) {
45+
is YAMLMapping -> {
46+
value.keyValues.forEach {
47+
kv ->
48+
when (kv.keyText) {
49+
"depends" -> {
50+
depends = parseDepends(kv)
51+
}
52+
"cmd" -> {
53+
when (val cmdValue = kv.value) {
54+
is YAMLMapping -> {
55+
cmdAsMap = cmdValue.keyValues.associate {
56+
cmdEntry ->
57+
cmdEntry.keyText to cmdEntry.valueText
58+
}
59+
}
60+
else -> {
61+
cmd = parseCmd(kv)
62+
}
63+
}
64+
}
65+
"env" -> {
66+
env = parseEnv(kv)
67+
}
68+
}
6569
}
6670
}
67-
else -> defaultConfig()
6871
}
69-
}
7072

71-
private fun defaultConfig(): Config {
72-
return Config(
73-
"",
74-
emptyList(),
75-
emptyMap(),
76-
emptyMap(),
77-
"",
78-
"",
79-
emptyList(),
80-
emptySet(),
73+
return Command(
74+
name,
75+
cmd,
76+
cmdAsMap,
77+
env,
78+
depends,
79+
obj,
8180
)
8281
}
8382

84-
private fun parseEnv(keyValue: YAMLKeyValue): Env {
83+
fun parseDepends(obj: YAMLKeyValue): List<String> {
84+
return when (val value = obj.value) {
85+
is YAMLSequence -> value.items.mapNotNull { it.value?.text }
86+
else -> emptyList()
87+
}
88+
}
89+
90+
fun parseEnv(keyValue: YAMLKeyValue): Env {
8591
val value = keyValue.value as? YAMLMapping ?: return emptyMap()
8692

8793
return value.keyValues.associate { kv ->
8894
kv.keyText to parseEnvValue(kv)
8995
}
9096
}
9197

92-
private fun parseEnvValue(kv: YAMLKeyValue): EnvValue {
98+
fun parseEnvValue(kv: YAMLKeyValue): EnvValue {
9399
return when (val envValue = kv.value) {
94100
is YAMLScalar -> EnvValue.StringValue(envValue.textValue)
95101
is YAMLMapping -> parseMappingEnvValue(envValue)
96102
else -> EnvValue.StringValue("")
97103
}
98104
}
99105

100-
private fun parseMappingEnvValue(value: YAMLMapping): EnvValue {
106+
fun parseMappingEnvValue(value: YAMLMapping): EnvValue {
101107
value.keyValues.forEach { kv ->
102108
when (kv.keyText) {
103109
"sh" -> return EnvValue.ShMode(kv.valueText)
@@ -119,155 +125,48 @@ class Config(
119125
return EnvValue.StringValue("")
120126
}
121127

122-
private fun parseShell(keyValue: YAMLKeyValue): String {
128+
fun parseShell(keyValue: YAMLKeyValue): String {
123129
return keyValue.valueText
124130
}
125131

126-
private fun parseCmd(keyValue: YAMLKeyValue): String {
132+
fun parseCmd(keyValue: YAMLKeyValue): String {
127133
return when (val value = keyValue.value) {
128134
is YAMLScalar -> value.text
129135
is YAMLSequence -> value.items.mapNotNull { it.value?.text }.joinToString(" ")
130136
else -> ""
131137
}
132138
}
133139

134-
private fun parseDepends(keyValue: YAMLKeyValue): List<String> {
135-
return when (val value = keyValue.value) {
136-
is YAMLSequence -> value.items.mapNotNull { it.value?.text }
137-
else -> emptyList()
138-
}
139-
}
140-
141-
private fun parseBefore(keyValue: YAMLKeyValue): String {
140+
fun parseBefore(keyValue: YAMLKeyValue): String {
142141
return when (val value = keyValue.value) {
143142
is YAMLScalar -> value.textValue
144143
else -> ""
145144
}
146145
}
147146

148-
private fun parseInit(keyValue: YAMLKeyValue): String {
147+
fun parseInit(keyValue: YAMLKeyValue): String {
149148
return when (val value = keyValue.value) {
150149
is YAMLScalar -> value.textValue
151150
else -> ""
152151
}
153152
}
154153

155-
@Suppress("NestedBlockDepth")
156-
private fun parseCommand(keyValue: YAMLKeyValue): Command {
157-
val name = keyValue.keyText
158-
var cmd = ""
159-
var cmdAsMap = emptyMap<String, String>()
160-
var env: Env = emptyMap()
161-
var depends = emptyList<String>()
162-
163-
when (val value = keyValue.value) {
164-
is YAMLMapping -> {
165-
value.keyValues.forEach {
166-
kv ->
167-
when (kv.keyText) {
168-
"cmd" -> {
169-
170-
when (val cmdValue = kv.value) {
171-
is YAMLMapping -> {
172-
cmdAsMap = cmdValue.keyValues.associate {
173-
cmdEntry ->
174-
cmdEntry.keyText to cmdEntry.valueText
175-
}
176-
}
177-
else -> {
178-
cmd = parseCmd(kv)
179-
}
180-
}
181-
}
182-
"env" -> {
183-
env = parseEnv(kv)
184-
}
185-
"depends" -> {
186-
depends = parseDepends(kv)
187-
}
188-
}
189-
}
190-
}
191-
}
192-
193-
return Command(
194-
name,
195-
cmd,
196-
cmdAsMap,
197-
env,
198-
depends,
199-
)
200-
}
201-
202-
@Suppress("NestedBlockDepth")
203-
private fun parseConfigFromMapping(mapping: YAMLMapping): Config {
204-
var shell = ""
205-
val mixins = mutableListOf<Mixin>()
206-
val commands = mutableListOf<Command>()
207-
val commandsMap = mutableMapOf<String, Command>()
208-
var env: Env = emptyMap()
209-
var before = ""
210-
var init = ""
211-
val keywordsInConfig = mutableSetOf<String>()
212-
213-
mapping.keyValues.forEach {
214-
kv ->
215-
when (kv.keyText) {
216-
"shell" -> {
217-
shell = parseShell(kv)
218-
}
219-
"mixins" -> {
220-
when (val value = kv.value) {
221-
is YAMLSequence -> {
222-
mixins.addAll(
223-
value.items.mapNotNull { it.value }
224-
.map { when (it) {
225-
is YAMLScalar -> Mixin.Local(it.textValue)
226-
is YAMLMapping -> {
227-
val url = it.getKeyValueByKey("url")?.valueText ?: ""
228-
val version = it.getKeyValueByKey("version")?.valueText ?: ""
229-
Mixin.Remote(url, version)
230-
}
231-
else -> Mixin.Local("")
232-
} }
233-
)
234-
}
235-
}
236-
}
237-
"env" -> {
238-
env = parseEnv(kv)
239-
}
240-
"before" -> {
241-
before = parseBefore(kv)
242-
}
243-
"init" -> {
244-
init = parseInit(kv)
245-
}
246-
"commands" -> {
247-
when (val value = kv.value) {
154+
fun parseMixins(keyValue: YAMLKeyValue): Mixins {
155+
return when (val value = keyValue.value) {
156+
is YAMLSequence -> {
157+
value.items.mapNotNull { it.value }
158+
.map { when (it) {
159+
is YAMLScalar -> Mixin.Local(it.textValue)
248160
is YAMLMapping -> {
249-
value.keyValues.forEach { rawCommand ->
250-
val command = parseCommand(rawCommand)
251-
commands.add(command)
252-
commandsMap[command.name] = command
253-
}
161+
val url = it.getKeyValueByKey("url")?.valueText ?: ""
162+
val version = it.getKeyValueByKey("version")?.valueText ?: ""
163+
Mixin.Remote(url, version)
254164
}
255-
}
256-
}
165+
else -> Mixin.Local("")
166+
} }
257167
}
258-
keywordsInConfig.add(kv.keyText)
168+
else -> emptyList()
259169
}
260-
261-
return Config(
262-
shell,
263-
commands,
264-
commandsMap,
265-
env,
266-
before,
267-
init,
268-
mixins,
269-
keywordsInConfig,
270-
)
271170
}
272171
}
273172
}

0 commit comments

Comments
 (0)