diff --git a/CHANGELOG.md b/CHANGELOG.md index 68f08f3a44e3a8f81f885f606c9c0dc242426522..6bddbc05b0d4c07863abf613ea69c7c7c36eb890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Solon Changelog +## [0.0.1-M9] +### Added +- [Feature] support yml key hint + ## [0.0.1-M8] ### Added - [Feature] Suppresses unused warnings for beans annotated with solons diff --git a/build.gradle.kts b/build.gradle.kts index 9ea453100651fc6adf0c5ccf9d42fd397d58359c..9b5003b7a48b5ba94d475f532a95254fab315500 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,7 @@ version = properties("pluginVersion") repositories { mavenCentral() } -dependencies{ +dependencies { // https://github.com/alibaba/fastjson2 implementation("com.alibaba.fastjson2:fastjson2:2.0.34") // https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 @@ -38,7 +38,6 @@ intellij { pluginName.set(properties("pluginName")) version.set(properties("platformVersion")) type.set(properties("platformType")) - // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file. plugins.set(properties("platformPlugins").split(',').map(String::trim).filter(String::isNotEmpty)) } @@ -62,24 +61,24 @@ tasks { // Extract the section from README.md and provide for the plugin's manifest pluginDescription.set( - file("README.md").readText().lines().run { - val start = "" - val end = "" - - if (!containsAll(listOf(start, end))) { - throw GradleException("Plugin description section not found in README.md:\n$start ... $end") - } - subList(indexOf(start) + 1, indexOf(end)) - }.joinToString("\n").let { markdownToHTML(it) } + file("README.md").readText().lines().run { + val start = "" + val end = "" + + if (!containsAll(listOf(start, end))) { + throw GradleException("Plugin description section not found in README.md:\n$start ... $end") + } + subList(indexOf(start) + 1, indexOf(end)) + }.joinToString("\n").let { markdownToHTML(it) } ) // Get the latest available change notes from the changelog file changeNotes.set(provider { with(changelog) { renderItem( - getOrNull(properties("pluginVersion")) - ?: runCatching { getLatest() }.getOrElse { getUnreleased() }, - Changelog.OutputType.HTML, + getOrNull(properties("pluginVersion")) + ?: runCatching { getLatest() }.getOrElse { getUnreleased() }, + Changelog.OutputType.HTML, ) } }) diff --git a/gradle.properties b/gradle.properties index 8573ec564cba52c07a71cf89300f145c7043bc02..f6ea53b15719e4d7b4ef11e21d9db457523ab309 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ pluginName = Solon pluginRepositoryUrl = https://gitee.com/noear/solon-idea-plugin # SemVer format -> https://semver.org -pluginVersion = 0.0.1-M8 +pluginVersion = 0.0.1-M9 # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild = 213 diff --git a/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/PropertiesCompletionProvider.java b/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/PropertiesCompletionProvider.java index e7cf1db409249d00506d83b1c59e06775b9191ae..f8b117b0c6c9eb238ffd0b0c44602267b68e0f6c 100644 --- a/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/PropertiesCompletionProvider.java +++ b/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/PropertiesCompletionProvider.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; public class PropertiesCompletionProvider extends CompletionProvider { + @Override protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet resultSet) { PsiElement element = parameters.getPosition(); @@ -35,7 +36,6 @@ public class PropertiesCompletionProvider extends CompletionProvider elementBuilders = new ArrayList<>(); if (property != null && element.getClass() == PropertyKeyImpl.class){ diff --git a/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/YamlCompletionContributor.java b/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/YamlCompletionContributor.java new file mode 100644 index 0000000000000000000000000000000000000000..7e55c6cffbb7ebbe190873d24de472145b495181 --- /dev/null +++ b/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/YamlCompletionContributor.java @@ -0,0 +1,18 @@ +package org.noear.solon.idea.plugin.suggestion.completion; + +import com.intellij.codeInsight.completion.CompletionContributor; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.lang.properties.PropertiesLanguage; +import com.intellij.patterns.PlatformPatterns; +import org.jetbrains.yaml.YAMLLanguage; + +public class YamlCompletionContributor extends CompletionContributor { + + public YamlCompletionContributor() { + extend( + CompletionType.BASIC, + PlatformPatterns.psiElement().withLanguage(YAMLLanguage.INSTANCE), + new YamlCompletionProvider() + ); + } +} diff --git a/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/YamlCompletionProvider.java b/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/YamlCompletionProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..5df4fde2e5411f8c7d8c603e46ee534e0dd18850 --- /dev/null +++ b/src/main/java/org/noear/solon/idea/plugin/suggestion/completion/YamlCompletionProvider.java @@ -0,0 +1,56 @@ +package org.noear.solon.idea.plugin.suggestion.completion; + +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionProvider; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.psi.impl.YAMLPlainTextImpl; +import org.noear.solon.idea.plugin.common.util.GenericUtil; +import org.noear.solon.idea.plugin.suggestion.service.SuggestionService; + +import java.util.ArrayList; +import java.util.List; + +public class YamlCompletionProvider extends CompletionProvider { + + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet resultSet) { + PsiElement element = parameters.getPosition(); + if (element instanceof PsiComment) { + return; + } + + Project project = element.getProject(); + SuggestionService suggestionService = SuggestionService.getInstance(project); + + if (!suggestionService.canProvideSuggestions()) { + return; + } + + YAMLPlainTextImpl yaml = getParentOfType(element, YAMLPlainTextImpl.class); + + String queryWithDotDelimitedPrefixes = GenericUtil.truncateIdeaDummyIdentifier(element); + List elementBuilders = new ArrayList<>(); + if (yaml != null && queryWithDotDelimitedPrefixes.contains(": ")) { + elementBuilders = suggestionService.findHintSuggestionsForQueryPrefix(queryWithDotDelimitedPrefixes, queryWithDotDelimitedPrefixes); + } else if (yaml != null) { + elementBuilders = suggestionService.findYamlSuggestionsForQueryPrefix(queryWithDotDelimitedPrefixes); + + } + assert elementBuilders != null; + elementBuilders.forEach(resultSet::addElement); + } + + private T getParentOfType(PsiElement element, Class clazz) { + PsiElement parent = element.getParent(); + if (parent.getClass() == clazz) { + return (T) parent; + } + return null; + } +} diff --git a/src/main/java/org/noear/solon/idea/plugin/suggestion/filetype/SolonYamlFileType.java b/src/main/java/org/noear/solon/idea/plugin/suggestion/filetype/SolonYamlFileType.java new file mode 100644 index 0000000000000000000000000000000000000000..ee2ab25efd7c12ced3f41bf3930500337dcd806f --- /dev/null +++ b/src/main/java/org/noear/solon/idea/plugin/suggestion/filetype/SolonYamlFileType.java @@ -0,0 +1,41 @@ +package org.noear.solon.idea.plugin.suggestion.filetype; + +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.util.NlsContexts; +import com.intellij.openapi.util.NlsSafe; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLLanguage; +import org.noear.solon.idea.plugin.SolonIcons; + +import javax.swing.*; + +public class SolonYamlFileType extends LanguageFileType { + + public static final SolonYamlFileType INSTANCE = new SolonYamlFileType(); + + private SolonYamlFileType() { + super(YAMLLanguage.INSTANCE,true); + } + + @Override + public @NonNls @NotNull String getName() { + return "solon-yaml-file"; + } + + @Override + public @NlsContexts.Label @NotNull String getDescription() { + return "Solon yaml file"; + } + + @Override + public @NlsSafe @NotNull String getDefaultExtension() { + return "yaml"; + } + + @Override + public @Nullable Icon getIcon(){ + return SolonIcons.SolonIcon_16x16; + } +} diff --git a/src/main/java/org/noear/solon/idea/plugin/suggestion/service/SuggestionService.java b/src/main/java/org/noear/solon/idea/plugin/suggestion/service/SuggestionService.java index e7cc8340b954cd0ee911341964ec0bab1296486e..e208d71884f3ccad212f1efe1beb559106436bee 100644 --- a/src/main/java/org/noear/solon/idea/plugin/suggestion/service/SuggestionService.java +++ b/src/main/java/org/noear/solon/idea/plugin/suggestion/service/SuggestionService.java @@ -2,15 +2,12 @@ package org.noear.solon.idea.plugin.suggestion.service; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.openapi.module.Module; -import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.List; -import java.util.Set; public interface SuggestionService { @@ -32,5 +29,7 @@ public interface SuggestionService { @Nullable List findHintSuggestionsForQueryPrefix(String key, String queryWithDotDelimitedPrefixes); + @Nullable + List findYamlSuggestionsForQueryPrefix(String queryWithDotDelimitedPrefixes); boolean canProvideSuggestions(); } diff --git a/src/main/java/org/noear/solon/idea/plugin/suggestion/service/SuggestionServiceImpl.java b/src/main/java/org/noear/solon/idea/plugin/suggestion/service/SuggestionServiceImpl.java index fd1bbbb78f7008ad9659374dfcf6177fb2db5dcf..2f7fbd82d9cf360c5cecd58ca71c6b3ab2349d7b 100644 --- a/src/main/java/org/noear/solon/idea/plugin/suggestion/service/SuggestionServiceImpl.java +++ b/src/main/java/org/noear/solon/idea/plugin/suggestion/service/SuggestionServiceImpl.java @@ -36,6 +36,8 @@ public class SuggestionServiceImpl implements SuggestionService { private Future currentExecution; private volatile boolean indexingInProgress; + private final String DELIMITER = "\\."; + public SuggestionServiceImpl() { this.propertiesSearchIndex = new PatriciaTrie<>(); this.hintsSearchIndex = new PatriciaTrie<>(); @@ -161,7 +163,7 @@ public class SuggestionServiceImpl implements SuggestionService { List builders = new ArrayList<>(); for (Map.Entry entry : sortedMap.entrySet()) { builders.add(toLookupElementBuilder(entry.getValue()).withInsertHandler((context, item) -> { - int index = queryWithDotDelimitedPrefixes.lastIndexOf("."); + int index = queryWithDotDelimitedPrefixes.lastIndexOf(DELIMITER); Editor editor = context.getEditor(); int startOffset = context.getStartOffset(); int endOffset = context.getTailOffset(); @@ -193,6 +195,37 @@ public class SuggestionServiceImpl implements SuggestionService { return builders; } + @Override + public @Nullable List findYamlSuggestionsForQueryPrefix(String queryWithDotDelimitedPrefixes) { + SortedMap sortedMap = this.propertiesSearchIndex.prefixMap(queryWithDotDelimitedPrefixes); + List builders = new ArrayList<>(); + for (Map.Entry entry : sortedMap.entrySet()) { + builders.add(toLookupElementBuilder(entry.getValue()).withInsertHandler((context, item) -> { + int index = queryWithDotDelimitedPrefixes.lastIndexOf(DELIMITER); + Editor editor = context.getEditor(); + int startOffset = context.getStartOffset(); + int endOffset = context.getTailOffset(); + Document document = editor.getDocument(); + String text = item.getLookupString(); + String[] count = text.split(DELIMITER); + StringBuffer resultText = new StringBuffer(); + for (int i = 0; i < count.length; i++) { + resultText.append(count[i]); + resultText.append(":\n"); + if(i == count.length-1){ + break; + } + resultText.append(" ".repeat(i + 1)); + } + + text = resultText.toString(); + document.replaceString(startOffset, endOffset, text); + editor.getCaretModel().moveToOffset(text.length()-1); + })); + } + return builders; + } + private LookupElementBuilder toLookupElementBuilder(SolonConfigurationMetadataHintValue hintValue) { LookupElementBuilder builder = LookupElementBuilder.create(hintValue.getValue()); if (hintValue.getDescription() != null) { diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index a355d2bd657abbf6db88aa5e3e60a9963bf7c69d..15a68e03dd6659dd42941175f936cb923704ac38 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -7,6 +7,7 @@ com.intellij.modules.platform com.intellij.modules.java com.intellij.properties + org.jetbrains.plugins.yaml org.jetbrains.idea.maven com.intellij.gradle @@ -27,10 +28,21 @@ fileNames="app.properties" patterns="app-*.properties"/> + + + +