feat(zon): Code completion
This commit is contained in:
parent
211f2c8065
commit
b0b7a2cc7b
6 changed files with 171 additions and 20 deletions
|
@ -25,6 +25,7 @@ Changelog structure reference:
|
||||||
- Basic syntax highlighting
|
- Basic syntax highlighting
|
||||||
- Color settings page
|
- Color settings page
|
||||||
- Brace matching
|
- Brace matching
|
||||||
|
- Code completion
|
||||||
|
|
||||||
## [0.4.0]
|
## [0.4.0]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 FalsePattern
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* http://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.zon.completion;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.zon.parser.ZonFile;
|
||||||
|
import com.falsepattern.zigbrains.zon.psi.ZonProperty;
|
||||||
|
import com.falsepattern.zigbrains.zon.psi.ZonPropertyPlaceholder;
|
||||||
|
import com.falsepattern.zigbrains.zon.psi.ZonStruct;
|
||||||
|
import com.falsepattern.zigbrains.zon.psi.ZonTypes;
|
||||||
|
import com.falsepattern.zigbrains.zon.psi.impl.ZonPsiImplUtil;
|
||||||
|
import com.intellij.codeInsight.completion.CompletionContributor;
|
||||||
|
import com.intellij.codeInsight.completion.CompletionParameters;
|
||||||
|
import com.intellij.codeInsight.completion.CompletionProvider;
|
||||||
|
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||||
|
import com.intellij.codeInsight.completion.CompletionType;
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||||
|
import com.intellij.patterns.PlatformPatterns;
|
||||||
|
import com.intellij.util.ProcessingContext;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ZonCompletionContributor extends CompletionContributor {
|
||||||
|
private static final List<String> ZON_ROOT_KEYS = List.of("name", "version", "dependencies");
|
||||||
|
private static final List<String> ZON_DEP_KEYS = List.of("url", "hash");
|
||||||
|
public ZonCompletionContributor() {
|
||||||
|
extend(CompletionType.BASIC,
|
||||||
|
PlatformPatterns.psiElement()
|
||||||
|
.withParent(PlatformPatterns.psiElement(ZonTypes.PROPERTY_PLACEHOLDER))
|
||||||
|
.withSuperParent(3, PlatformPatterns.psiElement(ZonFile.class)),
|
||||||
|
new CompletionProvider<>() {
|
||||||
|
@Override
|
||||||
|
protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet result) {
|
||||||
|
var placeholder = (ZonPropertyPlaceholder) parameters.getPosition().getParent();
|
||||||
|
var zonStruct = (ZonStruct) placeholder.getParent();
|
||||||
|
var keys = ZonPsiImplUtil.getKeys(zonStruct);
|
||||||
|
doAddCompletions(placeholder.getText().startsWith("."), keys, ZON_ROOT_KEYS, result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
extend(CompletionType.BASIC,
|
||||||
|
PlatformPatterns.psiElement()
|
||||||
|
.withParent(PlatformPatterns.psiElement(ZonTypes.PROPERTY_PLACEHOLDER))
|
||||||
|
.withSuperParent(3, PlatformPatterns.psiElement(ZonTypes.VALUE))
|
||||||
|
.withSuperParent(6, PlatformPatterns.psiElement(ZonTypes.VALUE))
|
||||||
|
.withSuperParent(9, PlatformPatterns.psiElement(ZonFile.class)),
|
||||||
|
new CompletionProvider<>() {
|
||||||
|
@Override
|
||||||
|
protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet result) {
|
||||||
|
var placeholder = (ZonPropertyPlaceholder) parameters.getPosition().getParent();
|
||||||
|
var depStruct = (ZonStruct) placeholder.getParent();
|
||||||
|
var parentProperty = (ZonProperty) depStruct.getParent()
|
||||||
|
.getParent()
|
||||||
|
.getParent()
|
||||||
|
.getParent()
|
||||||
|
.getParent();
|
||||||
|
if (!"dependencies".equals(ZonPsiImplUtil.getText(parentProperty.getIdentifier()))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doAddCompletions(placeholder.getText().startsWith("."), ZonPsiImplUtil.getKeys(depStruct), ZON_DEP_KEYS, result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private static void doAddCompletions(boolean hasDot, Set<String> current, List<String> expected, CompletionResultSet result) {
|
||||||
|
for (var key: expected) {
|
||||||
|
if (current.contains(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.addElement(LookupElementBuilder.create(hasDot ? key : "." + key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,27 +34,42 @@ WHITE_SPACE=[\s]+
|
||||||
LINE_COMMENT="//" [^\n]* | "////" [^\n]*
|
LINE_COMMENT="//" [^\n]* | "////" [^\n]*
|
||||||
COMMENT="///".*
|
COMMENT="///".*
|
||||||
|
|
||||||
ID=[A-Za-z_][A-Za-z0-9_]* | "@\"" {STRING_CHAR}* \"
|
ID=[A-Za-z_][A-Za-z0-9_]*
|
||||||
|
|
||||||
STRING_CHAR=( [^\\\"] | \\[^] )
|
hex=[0-9a-fA-F]
|
||||||
STRING_LITERAL_SINGLE=\"{STRING_CHAR}*\"
|
char_escape
|
||||||
LINE_STRING=(\\\\ [^\n]* [ \n]*)+
|
= "\\x" {hex} {hex}
|
||||||
|
| "\\u{" {hex}+ "}"
|
||||||
|
| "\\" [nr\\t'\"]
|
||||||
|
|
||||||
|
string_char
|
||||||
|
= {char_escape}
|
||||||
|
| [^\\\"\n]
|
||||||
|
|
||||||
|
LINE_STRING=("\\\\" [^\n]* [ \n]*)+
|
||||||
|
|
||||||
|
%state STRING_LITERAL
|
||||||
|
%state ID_STRING
|
||||||
%%
|
%%
|
||||||
|
|
||||||
<YYINITIAL> {
|
|
||||||
{WHITE_SPACE} { return WHITE_SPACE; }
|
|
||||||
"." { return DOT; }
|
|
||||||
"{" { return LBRACE; }
|
|
||||||
"}" { return RBRACE; }
|
|
||||||
"=" { return EQ; }
|
|
||||||
"," { return COMMA; }
|
|
||||||
{COMMENT} { return COMMENT; }
|
|
||||||
{LINE_COMMENT} { return COMMENT; }
|
|
||||||
|
|
||||||
{ID} { return ID; }
|
<YYINITIAL> {WHITE_SPACE} { return WHITE_SPACE; }
|
||||||
{STRING_LITERAL_SINGLE} { return STRING_LITERAL_SINGLE; }
|
<YYINITIAL> "." { return DOT; }
|
||||||
{LINE_STRING} { return LINE_STRING; }
|
<YYINITIAL> "IntellijIdeaRulezzz" { return INTELLIJ_COMPLETION_DUMMY; }
|
||||||
}
|
<YYINITIAL> "{" { return LBRACE; }
|
||||||
|
<YYINITIAL> "}" { return RBRACE; }
|
||||||
|
<YYINITIAL> "=" { return EQ; }
|
||||||
|
<YYINITIAL> "," { return COMMA; }
|
||||||
|
<YYINITIAL> {COMMENT} { return COMMENT; }
|
||||||
|
<YYINITIAL> {LINE_COMMENT} { return COMMENT; }
|
||||||
|
|
||||||
[^] { return BAD_CHARACTER; }
|
<YYINITIAL> {ID} { return ID; }
|
||||||
|
<YYINITIAL> "@\"" { yybegin(ID_STRING); }
|
||||||
|
<ID_STRING> {string_char}*"\"" { yybegin(YYINITIAL); return ID; }
|
||||||
|
|
||||||
|
<YYINITIAL> "\"" { yybegin(STRING_LITERAL); }
|
||||||
|
<STRING_LITERAL> {string_char}*"\"" { yybegin(YYINITIAL); return STRING_LITERAL_SINGLE; }
|
||||||
|
<YYINITIAL> {LINE_STRING} { return LINE_STRING; }
|
||||||
|
|
||||||
|
|
||||||
|
[^] { yybegin(YYINITIAL); return BAD_CHARACTER; }
|
||||||
|
|
|
@ -42,9 +42,13 @@
|
||||||
|
|
||||||
zonFile ::= struct
|
zonFile ::= struct
|
||||||
|
|
||||||
struct ::= DOT LBRACE (property (COMMA property)* COMMA?)? RBRACE
|
struct ::= DOT LBRACE (property COMMA | property_placeholder COMMA?)* property? RBRACE
|
||||||
|
|
||||||
property ::= DOT ID EQ value
|
property ::= DOT identifier EQ value
|
||||||
|
|
||||||
|
identifier ::= ID
|
||||||
|
|
||||||
|
property_placeholder ::= DOT? INTELLIJ_COMPLETION_DUMMY
|
||||||
|
|
||||||
value ::= struct | STRING_LITERAL
|
value ::= struct | STRING_LITERAL
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 FalsePattern
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* http://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.zon.psi.impl;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.zon.psi.ZonIdentifier;
|
||||||
|
import com.falsepattern.zigbrains.zon.psi.ZonStruct;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ZonPsiImplUtil {
|
||||||
|
public static Set<String> getKeys(ZonStruct struct) {
|
||||||
|
var result = new HashSet<String>();
|
||||||
|
for (var property: struct.getPropertyList()) {
|
||||||
|
result.add(getText(property.getIdentifier()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getText(ZonIdentifier identifier) {
|
||||||
|
var idStr = identifier.getText();
|
||||||
|
if (idStr.startsWith("@")) {
|
||||||
|
return idStr.substring(2, idStr.length() - 2);
|
||||||
|
} else {
|
||||||
|
return idStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -96,6 +96,9 @@
|
||||||
|
|
||||||
<lang.braceMatcher language="Zon"
|
<lang.braceMatcher language="Zon"
|
||||||
implementationClass="com.falsepattern.zigbrains.zon.braces.ZonBraceMatcher"/>
|
implementationClass="com.falsepattern.zigbrains.zon.braces.ZonBraceMatcher"/>
|
||||||
|
|
||||||
|
<completion.contributor language="Zon"
|
||||||
|
implementationClass="com.falsepattern.zigbrains.zon.completion.ZonCompletionContributor"/>
|
||||||
<!-- endregion Zon -->
|
<!-- endregion Zon -->
|
||||||
|
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
Loading…
Add table
Reference in a new issue