diff --git a/src/main/java/de/marhali/easyi18n/assistance/completion/JavaCompletionContributor.java b/src/main/java/de/marhali/easyi18n/assistance/completion/JavaCompletionContributor.java new file mode 100644 index 0000000..8ebc10f --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/completion/JavaCompletionContributor.java @@ -0,0 +1,16 @@ +package de.marhali.easyi18n.assistance.completion; + +import com.intellij.codeInsight.completion.CompletionContributor; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiLiteralValue; + +/** + * Java specific completion contributor + * @author marhali + */ +public class JavaCompletionContributor extends CompletionContributor { + public JavaCompletionContributor() { + extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralValue.class), new KeyCompletionProvider()); + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/completion/KeyCompletionProvider.java b/src/main/java/de/marhali/easyi18n/assistance/completion/KeyCompletionProvider.java new file mode 100644 index 0000000..eccf9eb --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/completion/KeyCompletionProvider.java @@ -0,0 +1,60 @@ +package de.marhali.easyi18n.assistance.completion; + +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionProvider; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.IconLoader; +import com.intellij.util.ProcessingContext; + +import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.assistance.OptionalAssistance; +import de.marhali.easyi18n.model.KeyPath; +import de.marhali.easyi18n.model.Translation; +import de.marhali.easyi18n.model.TranslationData; +import de.marhali.easyi18n.settings.ProjectSettings; +import de.marhali.easyi18n.settings.ProjectSettingsService; +import de.marhali.easyi18n.util.KeyPathConverter; + +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.Set; + +/** + * Provides existing translation keys for code completion. + * @author marhali + */ +class KeyCompletionProvider extends CompletionProvider implements OptionalAssistance { + + private static final Icon icon = IconLoader.getIcon("/icons/translate13.svg", KeyCompletionProvider.class); + + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, + @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { + Project project = parameters.getOriginalFile().getProject(); + + if(!isAssistance(project)) { + return; + } + + ProjectSettings settings = ProjectSettingsService.get(project).getState(); + TranslationData data = InstanceManager.get(project).store().getData(); + Set fullKeys = data.getFullKeys(); + + for (KeyPath key : fullKeys) { + result.addElement(constructLookup(new Translation(key, data.getTranslation(key)), settings)); + } + } + + private LookupElement constructLookup(Translation translation, ProjectSettings settings) { + KeyPathConverter converter = new KeyPathConverter(settings); + + return LookupElementBuilder + .create(converter.toString(translation.getKey())) + .withTailText(" " + translation.getValue().get(settings.getPreviewLocale()), true) + .withIcon(icon); + } +} diff --git a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyCompletionContributor.java b/src/main/java/de/marhali/easyi18n/assistance/completion/KtCompletionContributor.java similarity index 60% rename from src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyCompletionContributor.java rename to src/main/java/de/marhali/easyi18n/assistance/completion/KtCompletionContributor.java index 30a6a57..eadffb5 100644 --- a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyCompletionContributor.java +++ b/src/main/java/de/marhali/easyi18n/assistance/completion/KtCompletionContributor.java @@ -1,19 +1,16 @@ -package de.marhali.easyi18n.editor.kotlin; +package de.marhali.easyi18n.assistance.completion; import com.intellij.codeInsight.completion.CompletionContributor; import com.intellij.codeInsight.completion.CompletionType; import com.intellij.patterns.PlatformPatterns; - -import de.marhali.easyi18n.editor.KeyCompletionProvider; import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry; /** - * Kotlin specific translation key completion contributor. + * Kotlin specific completion contributor. * @author marhali */ -public class KotlinKeyCompletionContributor extends CompletionContributor { - - public KotlinKeyCompletionContributor() { +public class KtCompletionContributor extends CompletionContributor { + public KtCompletionContributor() { extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(KtLiteralStringTemplateEntry.class), new KeyCompletionProvider()); } diff --git a/src/main/java/de/marhali/easyi18n/assistance/documentation/AbstractDocumentationProvider.java b/src/main/java/de/marhali/easyi18n/assistance/documentation/AbstractDocumentationProvider.java new file mode 100644 index 0000000..a2a1d10 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/documentation/AbstractDocumentationProvider.java @@ -0,0 +1,104 @@ +package de.marhali.easyi18n.assistance.documentation; + +import com.intellij.lang.documentation.DocumentationMarkup; +import com.intellij.lang.documentation.DocumentationProvider; +import com.intellij.openapi.project.Project; + +import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.assistance.OptionalAssistance; +import de.marhali.easyi18n.model.KeyPath; +import de.marhali.easyi18n.model.TranslationData; +import de.marhali.easyi18n.model.TranslationNode; +import de.marhali.easyi18n.settings.ProjectSettings; +import de.marhali.easyi18n.settings.ProjectSettingsService; +import de.marhali.easyi18n.util.KeyPathConverter; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.ResourceBundle; + +/** + * Provides locale values as documentation for translation keys. + * @author marhali + */ +abstract class AbstractDocumentationProvider implements DocumentationProvider, OptionalAssistance { + + private static final ResourceBundle bundle = ResourceBundle.getBundle("messages"); + + /** + * Checks if the provided key is a valid translation-key and generates the equivalent documentation for it. + * @param project Opened project + * @param key Designated translation key + * @return Generated documentation or null if not responsible + */ + protected @Nullable String generateDoc(@NotNull Project project, @Nullable String key) { + if(key == null || !isAssistance(project)) { + return null; + } + + ProjectSettings settings = ProjectSettingsService.get(project).getState(); + KeyPathConverter converter = new KeyPathConverter(settings); + KeyPath path = converter.fromString(key); + + // So we want to take care of context and pluralization here + // we should check the last key section for plural / context delims and if so provide all leafs within the last node + + if(path.isEmpty()) { + return null; + } + + TranslationData data = InstanceManager.get(project).store().getData(); + String leaf = path.remove(path.size() - 1); + TranslationNode leafNode = data.getRootNode(); + + for(String section : path) { + leafNode = leafNode.getChildren().get(section); + if(leafNode == null) { // Cannot resolve last node before leaf + return null; + } + } + + Map results = new LinkedHashMap<>(); + + // Filter results for matching leafs (contextual and pluralization support) + for (Map.Entry entry : leafNode.getChildren().entrySet()) { + if(entry.getKey().startsWith(leaf) && entry.getValue().isLeaf()) { + results.put(entry.getKey(), entry.getValue().getValue().get(settings.getPreviewLocale())); + } + } + + if(results.isEmpty()) { // No results to show + return null; + } + + StringBuilder builder = new StringBuilder(); + + builder.append(DocumentationMarkup.DEFINITION_START); + builder.append(bundle.getString("documentation")); + builder.append(DocumentationMarkup.DEFINITION_END); + + if(results.size() == 1) { // Single value + builder.append(DocumentationMarkup.CONTENT_START); + builder.append("").append(results.values().toArray()[0]).append(""); + builder.append(DocumentationMarkup.CONTENT_END); + + } else { // Pluralization | Contextual relevant values + builder.append(DocumentationMarkup.SECTIONS_START); + + for (Map.Entry entry : results.entrySet()) { + builder.append(DocumentationMarkup.SECTION_HEADER_START); + builder.append(entry.getKey()).append(":"); + builder.append(DocumentationMarkup.SECTION_SEPARATOR); + builder.append("

"); + builder.append("").append(entry.getValue()).append(""); + } + + builder.append(DocumentationMarkup.SECTIONS_END); + } + + return builder.toString(); + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/documentation/CommonDocumentationProvider.java b/src/main/java/de/marhali/easyi18n/assistance/documentation/CommonDocumentationProvider.java new file mode 100644 index 0000000..5ca0df0 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/documentation/CommonDocumentationProvider.java @@ -0,0 +1,26 @@ +package de.marhali.easyi18n.assistance.documentation; + +import com.intellij.psi.PsiElement; +import de.marhali.easyi18n.assistance.reference.PsiKeyReference; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.Nullable; + +/** + * Language unspecific documentation provider. Every supported language should register an extension to this EP. + * @author marhali + */ +public class CommonDocumentationProvider extends AbstractDocumentationProvider { + + @Override + public @Nullable + @Nls String generateDoc(PsiElement element, @Nullable PsiElement originalElement) { + if(!(element instanceof PsiKeyReference.TranslationReference)) { + return null; + } + + PsiKeyReference.TranslationReference keyReference = (PsiKeyReference.TranslationReference) element; + String value = keyReference.getName(); + + return generateDoc(element.getProject(), value); + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/folding/AbstractFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/assistance/folding/AbstractFoldingBuilder.java new file mode 100644 index 0000000..5637da7 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/folding/AbstractFoldingBuilder.java @@ -0,0 +1,53 @@ +package de.marhali.easyi18n.assistance.folding; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.folding.FoldingBuilderEx; +import com.intellij.openapi.editor.FoldingGroup; +import com.intellij.openapi.project.Project; + +import de.marhali.easyi18n.DataStore; +import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.assistance.OptionalAssistance; +import de.marhali.easyi18n.model.TranslationValue; +import de.marhali.easyi18n.settings.ProjectSettingsService; +import de.marhali.easyi18n.util.KeyPathConverter; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Language specific folding of translation key with preferred locale value. + * @author marhali + */ +abstract class AbstractFoldingBuilder extends FoldingBuilderEx implements OptionalAssistance { + + protected static final FoldingGroup group = FoldingGroup.newGroup("EasyI18n key folding"); + + /** + * Constructs the folding text for the provided text. + * @param project Opened project + * @param text Designated translation key + * @return Preferred locale value or null if translation does not exists + */ + protected @Nullable String getPlaceholderText(@NotNull Project project, @Nullable String text) { + if(text == null) { + return null; + } + + DataStore store = InstanceManager.get(project).store(); + KeyPathConverter converter = new KeyPathConverter(project); + TranslationValue localeValues = store.getData().getTranslation(converter.fromString(text)); + + if(localeValues == null) { + return null; + } + + String previewLocale = ProjectSettingsService.get(project).getState().getPreviewLocale(); + return localeValues.get(previewLocale); + } + + @Override + public boolean isCollapsedByDefault(@NotNull ASTNode node) { + return true; + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/folding/JavaFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/assistance/folding/JavaFoldingBuilder.java new file mode 100644 index 0000000..cac89f3 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/folding/JavaFoldingBuilder.java @@ -0,0 +1,66 @@ +package de.marhali.easyi18n.assistance.folding; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.folding.FoldingDescriptor; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.psi.util.PsiTreeUtil; + +import de.marhali.easyi18n.DataStore; +import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.util.KeyPathConverter; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Java specific translation key folding. + * @author marhali + */ +public class JavaFoldingBuilder extends AbstractFoldingBuilder { + + @Override + public FoldingDescriptor @NotNull [] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { + List descriptors = new ArrayList<>(); + + if(!isAssistance(root.getProject())) { + return FoldingDescriptor.EMPTY; + } + + Collection literalExpressions = + PsiTreeUtil.findChildrenOfType(root, PsiLiteralExpression.class); + + DataStore store = InstanceManager.get(root.getProject()).store(); + KeyPathConverter converter = new KeyPathConverter(root.getProject()); + + for(final PsiLiteralExpression literalExpression : literalExpressions) { + String value = literalExpression.getValue() instanceof String + ? (String) literalExpression.getValue() : null; + + if(value == null || store.getData().getTranslation(converter.fromString(value)) == null) { + continue; + } + + TextRange range = literalExpression.getTextRange(); + FoldingDescriptor descriptor = new FoldingDescriptor(literalExpression.getNode(), + new TextRange(range.getStartOffset() + 1, range.getEndOffset() - 1), group); + + descriptors.add(descriptor); + } + + return descriptors.toArray(new FoldingDescriptor[0]); + } + + @Override + public @Nullable String getPlaceholderText(@NotNull ASTNode node) { + PsiLiteralExpression literalExpression = node.getPsi(PsiLiteralExpression.class); + String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null; + return getPlaceholderText(literalExpression.getProject(), value); + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/folding/KtFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/assistance/folding/KtFoldingBuilder.java new file mode 100644 index 0000000..014bfa3 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/folding/KtFoldingBuilder.java @@ -0,0 +1,63 @@ +package de.marhali.easyi18n.assistance.folding; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.folding.FoldingDescriptor; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; + +import de.marhali.easyi18n.DataStore; +import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.util.KeyPathConverter; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.psi.KtStringTemplateEntry; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Kotlin specific translation-key folding. + * @author marhali + */ +public class KtFoldingBuilder extends AbstractFoldingBuilder { + @Override + public FoldingDescriptor @NotNull [] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { + List descriptors = new ArrayList<>(); + + if(!isAssistance(root.getProject())) { + return FoldingDescriptor.EMPTY; + } + + Collection templateEntries = + PsiTreeUtil.findChildrenOfType(root, KtStringTemplateEntry.class); + + DataStore store = InstanceManager.get(root.getProject()).store(); + KeyPathConverter converter = new KeyPathConverter(root.getProject()); + + for (KtStringTemplateEntry templateEntry : templateEntries) { + String value = templateEntry.getText(); + + if(value == null || store.getData().getTranslation(converter.fromString(value)) == null) { + continue; + } + + TextRange range = templateEntry.getTextRange(); + FoldingDescriptor descriptor = new FoldingDescriptor(templateEntry.getNode(), + new TextRange(range.getStartOffset(), range.getEndOffset()), group); + + descriptors.add(descriptor); + } + + return descriptors.toArray(new FoldingDescriptor[0]); + } + + @Override + public @Nullable String getPlaceholderText(@NotNull ASTNode node) { + KtStringTemplateEntry templateEntry = node.getPsi(KtStringTemplateEntry.class); + return getPlaceholderText(templateEntry.getProject(), templateEntry.getText()); + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/AbstractExtractIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/AbstractExtractIntention.java new file mode 100644 index 0000000..2f7c2bf --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/intention/AbstractExtractIntention.java @@ -0,0 +1,93 @@ +package de.marhali.easyi18n.assistance.intention; + +import com.intellij.codeInsight.intention.FileModifier; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Caret; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiEditorUtil; + +import com.siyeh.ipp.base.MutablyNamedIntention; + +import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.assistance.OptionalAssistance; +import de.marhali.easyi18n.dialog.AddDialog; +import de.marhali.easyi18n.model.KeyPath; +import de.marhali.easyi18n.model.TranslationData; +import de.marhali.easyi18n.settings.ProjectSettings; +import de.marhali.easyi18n.settings.ProjectSettingsService; +import de.marhali.easyi18n.util.KeyPathConverter; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ResourceBundle; + +/** + * Intention for extracting a translation. Either by translation key or preferred locale value + * @author marhali + */ +abstract class AbstractExtractIntention extends MutablyNamedIntention implements OptionalAssistance { + + protected static final ResourceBundle bundle = ResourceBundle.getBundle("messages"); + + @Override + public @NotNull String getFamilyName() { + return "EasyI18n"; + } + + @Override + public boolean startInWriteAction() { + return false; + } + + protected @NotNull String getTextForElement(@NotNull Project project, @Nullable String key) { + KeyPathConverter converter = new KeyPathConverter(project); + TranslationData data = InstanceManager.get(project).store().getData(); + + return key != null && data.getTranslation(converter.fromString(key)) != null + ? bundle.getString("action.edit") + : bundle.getString("action.extract"); + } + + protected void extractTranslation(@NotNull Project project, @NotNull String text, PsiElement psi) { + ProjectSettings settings = ProjectSettingsService.get(project).getState(); + KeyPathConverter converter = new KeyPathConverter(settings); + + // Extract translation key + // We assume that a text is a translation-key if it contains section delimiters and does not end with them + if(text.contains(settings.getSectionDelimiter()) && !text.endsWith(settings.getSectionDelimiter())) { + new AddDialog(project, converter.fromString(text), null).showAndHandle(); + + } else { // Extract translation value (here preview locale value) + AddDialog dialog = new AddDialog(project, new KeyPath(), text); + + // Replace editor caret with chosen translation key + dialog.registerCallback(translationUpdate -> { + Editor editor = PsiEditorUtil.findEditor(psi); + + if(editor != null) { + Document doc = editor.getDocument(); + Caret caret = editor.getCaretModel().getPrimaryCaret(); + int start = psi.getTextOffset() + 1; + int end = start + text.length(); + + WriteCommandAction.runWriteCommandAction(project, () -> + doc.replaceString(start, end, converter.toString(translationUpdate.getChange().getKey()))); + + caret.removeSelection(); + } + }); + + dialog.showAndHandle();; + } + } + + @Override + public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) { + return this; + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/JavaExtractIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/JavaExtractIntention.java new file mode 100644 index 0000000..d074d4f --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/intention/JavaExtractIntention.java @@ -0,0 +1,35 @@ +package de.marhali.easyi18n.assistance.intention; + +import com.intellij.codeInspection.util.IntentionName; +import com.intellij.psi.*; +import com.siyeh.ipp.base.PsiElementPredicate; +import org.jetbrains.annotations.NotNull; + +/** + * Java specific translation key intention. + * @author marhali + */ +public class JavaExtractIntention extends AbstractExtractIntention { + + @Override + protected @IntentionName String getTextForElement(PsiElement element) { + return getTextForElement(element.getProject(), (String) ((PsiLiteralExpression) element).getValue()); + } + + @Override + protected void processIntention(@NotNull PsiElement element) { + System.out.println("proci2"); + if(!(element instanceof PsiLiteralExpression) + || !(((PsiLiteralExpression) element).getValue() instanceof String)) { + return; + } + + extractTranslation(element.getProject(), (String) ((PsiLiteralExpression) element).getValue(), element); + } + + @Override + protected @NotNull PsiElementPredicate getElementPredicate() { + System.out.println("predi2"); + return element -> element instanceof PsiLiteralExpression; + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/JsExtractIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/JsExtractIntention.java new file mode 100644 index 0000000..5496802 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/intention/JsExtractIntention.java @@ -0,0 +1,40 @@ +package de.marhali.easyi18n.assistance.intention; + +import com.intellij.codeInspection.util.IntentionName; +import com.intellij.lang.javascript.psi.JSLiteralExpression; +import com.intellij.psi.PsiElement; +import com.siyeh.ipp.base.PsiElementPredicate; +import org.jetbrains.annotations.NotNull; + +/** + * JavaScript specific translation key intention. + * @author marhali + */ +// TODO: current implementation does not support other languages than Java +public class JsExtractIntention extends AbstractExtractIntention { + + @Override + public @NotNull String getFamilyName() { + return "JavaScript"; + } + + @Override + protected @IntentionName String getTextForElement(PsiElement element) { + return "HILFE"; + //return getTextForElement(element.getProject(), ((JSLiteralExpression) element).getStringValue()); + } + + @Override + protected void processIntention(@NotNull PsiElement element) { + if(!(element instanceof JSLiteralExpression) || ((JSLiteralExpression) element).getStringValue() == null) { + return; + } + + extractTranslation(element.getProject(), ((JSLiteralExpression) element).getStringValue(), element); + } + + @Override + protected @NotNull PsiElementPredicate getElementPredicate() { + return element -> true; + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/intention/KtExtractIntention.java b/src/main/java/de/marhali/easyi18n/assistance/intention/KtExtractIntention.java new file mode 100644 index 0000000..bdaf628 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/intention/KtExtractIntention.java @@ -0,0 +1,41 @@ +package de.marhali.easyi18n.assistance.intention; + +import com.intellij.codeInspection.util.IntentionName; +import com.intellij.psi.PsiElement; +import com.siyeh.ipp.base.PsiElementPredicate; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry; +import org.jetbrains.kotlin.psi.KtStringTemplateExpression; + +/** + * Kotlin specific translation key intention. + * @author marhali + */ +// TODO: kotlin impl does not work - no action +public class KtExtractIntention extends AbstractExtractIntention { + @Override + protected @IntentionName String getTextForElement(PsiElement element) { + return "hallo"; + //return getTextForElement(element.getProject(), element.getText()); + } + + @Override + protected void processIntention(@NotNull PsiElement element) { + System.out.println("Hallo"); + + if(!(element instanceof KtStringTemplateExpression)) { + System.out.println(element.getClass()); + return; + } + + System.out.println("hallo"); + + extractTranslation(element.getProject() , element.getText(), element); + } + + @Override + protected @NotNull PsiElementPredicate getElementPredicate() { + System.out.println("predi"); + return element -> element instanceof KtLiteralStringTemplateEntry; + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/AbstractKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/AbstractKeyReferenceContributor.java new file mode 100644 index 0000000..b964a4c --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/reference/AbstractKeyReferenceContributor.java @@ -0,0 +1,53 @@ +package de.marhali.easyi18n.assistance.reference; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.PsiReferenceContributor; +import de.marhali.easyi18n.InstanceManager; +import de.marhali.easyi18n.assistance.OptionalAssistance; +import de.marhali.easyi18n.model.KeyPath; +import de.marhali.easyi18n.model.Translation; +import de.marhali.easyi18n.model.TranslationValue; +import de.marhali.easyi18n.settings.ProjectSettings; +import de.marhali.easyi18n.settings.ProjectSettingsService; +import de.marhali.easyi18n.util.KeyPathConverter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Language specific translation key reference contributor. + * @author marhali + */ +abstract class AbstractKeyReferenceContributor extends PsiReferenceContributor implements OptionalAssistance { + /** + * Searches for relevant translation-key references + * @param project Opened project + * @param element Targeted element + * @param text Designated translation key + * @return Matched translation-key reference(s) + */ + protected @NotNull PsiReference[] getReferences( + @NotNull Project project, @NotNull PsiElement element, @Nullable String text) { + + if(text == null || text.isEmpty() || !isAssistance(project)) { + return PsiReference.EMPTY_ARRAY; + } + + ProjectSettings settings = ProjectSettingsService.get(project).getState(); + KeyPathConverter converter = new KeyPathConverter(settings); + + // TODO: We should provide multiple references if not a leaf node was provided (contextual / plurals support) + + KeyPath path = converter.fromString(text); + TranslationValue values = InstanceManager.get(project).store().getData().getTranslation(path); + + if(values == null) { // We only reference valid and existing translations + return PsiReference.EMPTY_ARRAY; + } + + return new PsiReference[] { + new PsiKeyReference(converter, new Translation(path, values), element) + }; + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/JavaKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/JavaKeyReferenceContributor.java new file mode 100644 index 0000000..bff2307 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/reference/JavaKeyReferenceContributor.java @@ -0,0 +1,40 @@ +package de.marhali.easyi18n.assistance.reference; + +import com.intellij.openapi.project.Project; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.*; + +import com.intellij.util.ProcessingContext; + +import org.jetbrains.annotations.NotNull; + +/** + * Java specific key reference binding. + * @author marhali + */ +public class JavaKeyReferenceContributor extends AbstractKeyReferenceContributor { + + // TODO: why not PsiLiteralExpression? + + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + registrar.registerReferenceProvider( + PlatformPatterns.psiElement(PsiLiteralValue.class), + getProvider()); + } + + private PsiReferenceProvider getProvider() { + return new PsiReferenceProvider() { + @Override + public PsiReference @NotNull [] getReferencesByElement( + @NotNull PsiElement element, @NotNull ProcessingContext context) { + + Project project = element.getProject(); + PsiLiteralValue literalValue = (PsiLiteralValue) element; + String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null; + + return getReferences(project, element, value); + } + }; + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/JsKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/JsKeyReferenceContributor.java new file mode 100644 index 0000000..6edd656 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/reference/JsKeyReferenceContributor.java @@ -0,0 +1,39 @@ +package de.marhali.easyi18n.assistance.reference; + +import com.intellij.lang.javascript.psi.JSLiteralExpression; +import com.intellij.openapi.project.Project; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.PsiReferenceProvider; +import com.intellij.psi.PsiReferenceRegistrar; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +/** + * JavaScript specific translation-key reference binding. + * @author marhali + */ +public class JsKeyReferenceContributor extends AbstractKeyReferenceContributor { + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + registrar.registerReferenceProvider( + PlatformPatterns.psiElement(JSLiteralExpression.class), + getProvider()); + } + + private PsiReferenceProvider getProvider() { + return new PsiReferenceProvider() { + @Override + public PsiReference @NotNull [] getReferencesByElement( + @NotNull PsiElement element, @NotNull ProcessingContext context) { + + Project project = element.getProject(); + JSLiteralExpression literalExpression = (JSLiteralExpression) element; + String value = literalExpression.getStringValue(); + + return getReferences(project, element, value); + } + }; + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/KtKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/assistance/reference/KtKeyReferenceContributor.java new file mode 100644 index 0000000..dc1b0e1 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/reference/KtKeyReferenceContributor.java @@ -0,0 +1,46 @@ +package de.marhali.easyi18n.assistance.reference; + +import com.intellij.openapi.project.Project; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.PsiReferenceProvider; +import com.intellij.psi.PsiReferenceRegistrar; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry; +import org.jetbrains.kotlin.psi.KtStringTemplateExpression; + +import java.util.Arrays; +import java.util.Optional; + +/** + * Kotlin specific translation-key reference binding. + * @author marhali + */ +public class KtKeyReferenceContributor extends AbstractKeyReferenceContributor { + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + registrar.registerReferenceProvider( + PlatformPatterns.psiElement().inside(KtStringTemplateExpression.class), + getProvider()); + } + + private PsiReferenceProvider getProvider() { + return new PsiReferenceProvider() { + @Override + public PsiReference @NotNull [] getReferencesByElement( + @NotNull PsiElement element, @NotNull ProcessingContext context) { + + Optional targetElement = Arrays.stream(element.getChildren()).filter(child -> + child instanceof KtLiteralStringTemplateEntry).findAny(); + + if(targetElement.isEmpty()) { + return PsiReference.EMPTY_ARRAY; + } + + return getReferences(element.getProject(), element, targetElement.get().getText()); + } + }; + } +} diff --git a/src/main/java/de/marhali/easyi18n/assistance/reference/PsiKeyReference.java b/src/main/java/de/marhali/easyi18n/assistance/reference/PsiKeyReference.java new file mode 100644 index 0000000..58a45e7 --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/assistance/reference/PsiKeyReference.java @@ -0,0 +1,72 @@ +package de.marhali.easyi18n.assistance.reference; + +import com.intellij.navigation.ItemPresentation; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReferenceBase; +import com.intellij.psi.SyntheticElement; +import com.intellij.psi.impl.FakePsiElement; + +import de.marhali.easyi18n.dialog.AddDialog; +import de.marhali.easyi18n.dialog.EditDialog; +import de.marhali.easyi18n.model.Translation; +import de.marhali.easyi18n.util.KeyPathConverter; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * References translation keys inside editor with corresponding {@link EditDialog} / {@link AddDialog}. + * @author marhali + */ +public class PsiKeyReference extends PsiReferenceBase { + + private final @NotNull Translation translation; + private final @NotNull KeyPathConverter converter; + + protected PsiKeyReference( + @NotNull KeyPathConverter converter, @NotNull Translation translation, @NotNull PsiElement element) { + + super(element, true); + this.translation = translation; + this.converter = converter; + } + + public @NotNull String getKey() { + return converter.toString(translation.getKey()); + } + + @Override + public @Nullable PsiElement resolve() { + return new TranslationReference(); + } + + public class TranslationReference extends FakePsiElement implements SyntheticElement { + @Override + public PsiElement getParent() { + return myElement; + } + + @Override + public void navigate(boolean requestFocus) { + new EditDialog(getProject(), translation).showAndHandle(); + } + + @Override + public String getPresentableText() { + return getKey(); + } + + @Override + public String getName() { + return getKey(); + } + + @Override + public @Nullable TextRange getTextRange() { + TextRange rangeInElement = getRangeInElement(); + TextRange elementRange = myElement.getTextRange(); + return elementRange != null ? rangeInElement.shiftRight(elementRange.getStartOffset()) : rangeInElement; + } + } +} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java b/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java deleted file mode 100644 index aa3139a..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/KeyAnnotator.java +++ /dev/null @@ -1,61 +0,0 @@ -package de.marhali.easyi18n.editor; - -import com.intellij.lang.annotation.AnnotationHolder; -import com.intellij.lang.annotation.HighlightSeverity; -import com.intellij.openapi.project.Project; - -import de.marhali.easyi18n.InstanceManager; -import de.marhali.easyi18n.model.KeyPath; -import de.marhali.easyi18n.model.KeyPathConverter; -import de.marhali.easyi18n.model.TranslationNode; - -import de.marhali.easyi18n.settings.ProjectSettings; -import de.marhali.easyi18n.settings.ProjectSettingsService; -import org.jetbrains.annotations.NotNull; - -/** - * Superclass for managing key annotations. - * @author marhali - */ -public class KeyAnnotator { - - /** - * Adds annotations for i18n keys with content preview for preferred locale. - * @param key I18n key extracted by psi element - * @param project Project instance - * @param holder Annotation holder - */ - protected void annotate(@NotNull String key, @NotNull Project project, @NotNull AnnotationHolder holder) { - // Do not annotate keys if service is disabled - if(!ProjectSettingsService.get(project).getState().isAssistance()) { - return; - } - - ProjectSettings state = ProjectSettingsService.get(project).getState(); - //String pathPrefix = state.getPathPrefix(); - // TODO: Path prefix removal - String pathPrefix = ""; - String previewLocale = state.getPreviewLocale(); - - KeyPathConverter converter = new KeyPathConverter(project); - - String searchKey = key.length() >= pathPrefix.length() - ? key.substring(pathPrefix.length()) - : key; - - if(searchKey.startsWith(KeyPath.DELIMITER)) { - searchKey = searchKey.substring(KeyPath.DELIMITER.length()); - } - - TranslationNode node = InstanceManager.get(project).store().getData().getNode(converter.split(searchKey)); - - if(node == null) { // Unknown translation. Just ignore it - return; - } - - String tooltip = node.isLeaf() ? "I18n(" + previewLocale + ": " + node.getValue().get(previewLocale) + ")" - : "I18n ([])"; - - holder.newAnnotation(HighlightSeverity.INFORMATION, tooltip).create(); - } -} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java b/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java deleted file mode 100644 index ac899d2..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/KeyCompletionProvider.java +++ /dev/null @@ -1,64 +0,0 @@ -package de.marhali.easyi18n.editor; - -import com.intellij.codeInsight.completion.*; -import com.intellij.codeInsight.lookup.*; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.project.*; -import com.intellij.util.*; - -import de.marhali.easyi18n.DataStore; -import de.marhali.easyi18n.InstanceManager; -import de.marhali.easyi18n.model.KeyPath; -import de.marhali.easyi18n.model.Translation; - -import de.marhali.easyi18n.settings.ProjectSettingsService; -import org.jetbrains.annotations.*; - -import java.util.*; - -/** - * I18n translation key completion provider. - * @author marhali - */ -public class KeyCompletionProvider extends CompletionProvider { - - @Override - protected void addCompletions(@NotNull CompletionParameters parameters, - @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { - - Project project = parameters.getOriginalFile().getProject(); - - // Do not annotate keys if service is disabled - if(!ProjectSettingsService.get(project).getState().isAssistance()) { - return; - } - - DataStore store = InstanceManager.get(project).store(); - - String previewLocale = ProjectSettingsService.get(project).getState().getPreviewLocale(); - //String pathPrefix = ProjectSettingsService.get(project).getState().getPathPrefix(); - // TODO: Path prefix removal - String pathPrefix = ""; - - if(pathPrefix.length() > 0 && !pathPrefix.endsWith(KeyPath.DELIMITER)) { - pathPrefix += KeyPath.DELIMITER; - } - - Set fullKeys = store.getData().getFullKeys(); - - for(KeyPath currentKey : fullKeys) { - result.addElement(createElement( - pathPrefix, - currentKey, - previewLocale, - Objects.requireNonNull(store.getData().getTranslation(currentKey)) - )); - } - } - - private LookupElement createElement(String prefix, KeyPath path, String locale, Translation translation) { - return LookupElementBuilder.create(prefix + path.toSimpleString()) - .withIcon(AllIcons.Actions.PreserveCaseHover) - .appendTailText(" I18n(" + locale + ": " + translation.get(locale) + ")", true); - } -} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/KeyReference.java b/src/main/java/de/marhali/easyi18n/editor/KeyReference.java deleted file mode 100644 index d848bc1..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/KeyReference.java +++ /dev/null @@ -1,93 +0,0 @@ -package de.marhali.easyi18n.editor; - -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.*; -import com.intellij.psi.impl.FakePsiElement; - -import de.marhali.easyi18n.InstanceManager; -import de.marhali.easyi18n.dialog.AddDialog; -import de.marhali.easyi18n.dialog.EditDialog; -import de.marhali.easyi18n.model.KeyPath; -import de.marhali.easyi18n.model.KeyPathConverter; -import de.marhali.easyi18n.model.KeyedTranslation; -import de.marhali.easyi18n.model.Translation; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Go to declaration reference for i18n keys. - * @author marhali - */ -public class KeyReference extends PsiReferenceBase { - - @Nullable private final String myKey; - - public KeyReference(@NotNull final PsiElement element) { - this(element, (String)null); - } - - public KeyReference(@NotNull final PsiElement element, @Nullable final String myKey) { - super(element, true); - this.myKey = myKey; - } - - public KeyReference(@NotNull final PsiElement element, @NotNull TextRange textRange) { - this(element, textRange, null); - } - - public KeyReference(@NotNull PsiElement element, TextRange textRange, @Nullable String myKey) { - super(element, textRange, true); - this.myKey = myKey; - } - - @Override - public @Nullable PsiElement resolve() { - return new TranslationKey(); - } - - public String getKey() { - return myKey != null ? myKey : getValue(); - } - - class TranslationKey extends FakePsiElement implements SyntheticElement { - @Override - public PsiElement getParent() { - return myElement; - } - - @Override - public void navigate(boolean requestFocus) { - KeyPathConverter converter = new KeyPathConverter(getProject()); - KeyPath path = converter.split(getKey()); - Translation translation = InstanceManager.get(getProject()).store().getData().getTranslation(path); - - if(translation != null) { - new EditDialog(getProject(), new KeyedTranslation(path, translation)).showAndHandle(); - } else { - new AddDialog(getProject(), path).showAndHandle(); - } - } - - @Override - public String getPresentableText() { - return getKey(); - } - - @Override - public String getName() { - return getKey(); - } - - @Override - public @Nullable TextRange getTextRange() { - final TextRange rangeInElement = getRangeInElement(); - final TextRange elementRange = myElement.getTextRange(); - return elementRange != null ? rangeInElement.shiftRight(elementRange.getStartOffset()) : rangeInElement; - } - } - - public static boolean isReferencable(String value) { - return value.matches("^[^\\s:/]+$"); - } -} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java deleted file mode 100644 index a54310b..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericFoldingBuilder.java +++ /dev/null @@ -1,87 +0,0 @@ -package de.marhali.easyi18n.editor.generic; - -import com.intellij.lang.ASTNode; -import com.intellij.lang.folding.FoldingBuilderEx; -import com.intellij.lang.folding.FoldingDescriptor; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiLiteralValue; -import com.intellij.psi.util.PsiTreeUtil; - -import de.marhali.easyi18n.DataStore; -import de.marhali.easyi18n.InstanceManager; -import de.marhali.easyi18n.model.KeyPathConverter; -import de.marhali.easyi18n.model.Translation; -import de.marhali.easyi18n.settings.ProjectSettingsService; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * Translation key folding with actual value based on i18n instance. - * @author marhali - */ -public class GenericFoldingBuilder extends FoldingBuilderEx { - - @Override - public FoldingDescriptor @NotNull [] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { - Collection literalValues = PsiTreeUtil.findChildrenOfType(root, PsiLiteralValue.class); - List descriptors = new ArrayList<>(); - - if(!ProjectSettingsService.get(root.getProject()).getState().isAssistance()) { - return FoldingDescriptor.EMPTY; - } - - DataStore store = InstanceManager.get(root.getProject()).store(); - KeyPathConverter converter = new KeyPathConverter(root.getProject()); - - for(final PsiLiteralValue literalValue : literalValues) { - String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null; - - // Undefined string literal or not a translation - if(value == null || store.getData().getTranslation(converter.split(value)) == null) { - continue; - } - - descriptors.add(new FoldingDescriptor(literalValue.getNode(), - new TextRange(literalValue.getTextRange().getStartOffset() + 1, - literalValue.getTextRange().getEndOffset() - 1))); - } - - return descriptors.toArray(new FoldingDescriptor[0]); - } - - @Nullable - @Override - public String getPlaceholderText(@NotNull ASTNode node) { - PsiLiteralValue literalValue = node.getPsi(PsiLiteralValue.class); - String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null; - - if(value == null) { - return null; - } - - DataStore store = InstanceManager.get(literalValue.getProject()).store(); - KeyPathConverter converter = new KeyPathConverter(literalValue.getProject()); - - Translation translation = store.getData().getTranslation(converter.split(value)); - - if(translation == null) { - return null; - } - - String previewLocale = ProjectSettingsService.get(literalValue.getProject()).getState().getPreviewLocale(); - - return translation.get(previewLocale); - } - - @Override - public boolean isCollapsedByDefault(@NotNull ASTNode node) { - return true; - } -} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyAnnotator.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyAnnotator.java deleted file mode 100644 index 8de8149..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyAnnotator.java +++ /dev/null @@ -1,33 +0,0 @@ -package de.marhali.easyi18n.editor.generic; - -import com.intellij.lang.annotation.AnnotationHolder; -import com.intellij.lang.annotation.Annotator; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiLiteralValue; - -import de.marhali.easyi18n.editor.KeyAnnotator; - -import org.jetbrains.annotations.NotNull; - -/** - * Translation key annotator for generic languages which support {@link PsiLiteralValue}. - * @author marhali - */ -public class GenericKeyAnnotator extends KeyAnnotator implements Annotator { - - @Override - public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { - if(!(element instanceof PsiLiteralValue)) { - return; - } - - PsiLiteralValue literalValue = (PsiLiteralValue) element; - String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null; - - if(value == null) { - return; - } - - annotate(value, element.getProject(), holder); - } -} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyCompletionContributor.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyCompletionContributor.java deleted file mode 100644 index a8ed832..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyCompletionContributor.java +++ /dev/null @@ -1,24 +0,0 @@ -package de.marhali.easyi18n.editor.generic; - -import com.intellij.codeInsight.completion.CompletionContributor; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.patterns.*; -import com.intellij.psi.*; -import com.intellij.psi.xml.*; -import de.marhali.easyi18n.editor.KeyCompletionProvider; - -/** - * Translation key completion for generic languages which support {@link PsiLiteralValue}. - * @author marhali - */ -public class GenericKeyCompletionContributor extends CompletionContributor { - - public GenericKeyCompletionContributor() { - extend(CompletionType.BASIC, PlatformPatterns.psiElement(PlainTextTokenTypes.PLAIN_TEXT), - new KeyCompletionProvider()); - extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(XmlElement.class), - new KeyCompletionProvider()); - extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralValue.class), - new KeyCompletionProvider()); - } -} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java deleted file mode 100644 index 9d05418..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/generic/GenericKeyReferenceContributor.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.marhali.easyi18n.editor.generic; - -import com.intellij.patterns.PlatformPatterns; -import com.intellij.psi.*; -import com.intellij.util.ProcessingContext; - -import de.marhali.easyi18n.InstanceManager; -import de.marhali.easyi18n.editor.KeyReference; -import de.marhali.easyi18n.model.KeyPathConverter; - -import de.marhali.easyi18n.settings.ProjectSettingsService; -import org.jetbrains.annotations.NotNull; - -/** - * Generic translation key reference contributor. - * @author marhali - */ -public class GenericKeyReferenceContributor extends PsiReferenceContributor { - @Override - public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { - registrar.registerReferenceProvider(PlatformPatterns.psiElement(PsiLiteralValue.class), getProvider()); - } - - private PsiReferenceProvider getProvider() { - return new PsiReferenceProvider() { - @Override - public PsiReference @NotNull [] getReferencesByElement( - @NotNull PsiElement element, @NotNull ProcessingContext context) { - - PsiLiteralValue literalValue = (PsiLiteralValue) element; - String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null; - - if(value == null) { - return PsiReference.EMPTY_ARRAY; - } - - // Do not reference keys if service is disabled - if(!ProjectSettingsService.get(element.getProject()).getState().isAssistance()) { - return PsiReference.EMPTY_ARRAY; - } - - KeyPathConverter converter = new KeyPathConverter(element.getProject()); - - if(InstanceManager.get(element.getProject()).store().getData().getTranslation(converter.split(value)) == null) { - if(!KeyReference.isReferencable(value)) { // Creation policy - return PsiReference.EMPTY_ARRAY; - } - } - - return new PsiReference[] { new KeyReference(element, value) }; - } - }; - } -} diff --git a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyAnnotator.java b/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyAnnotator.java deleted file mode 100644 index 4e9cfe3..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyAnnotator.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.marhali.easyi18n.editor.kotlin; - -import com.intellij.lang.annotation.AnnotationHolder; -import com.intellij.lang.annotation.Annotator; -import com.intellij.psi.PsiElement; - -import de.marhali.easyi18n.editor.KeyAnnotator; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry; - -/** - * Kotlin specific translation key annotator - * @author marhali - */ -public class KotlinKeyAnnotator extends KeyAnnotator implements Annotator { - - @Override - public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { - if(!(element instanceof KtLiteralStringTemplateEntry)) { - return; - } - - String value = element.getText(); - - if(value == null) { - return; - } - - annotate(value, element.getProject(), holder); - } -} \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java b/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java deleted file mode 100644 index fe37717..0000000 --- a/src/main/java/de/marhali/easyi18n/editor/kotlin/KotlinKeyReferenceContributor.java +++ /dev/null @@ -1,59 +0,0 @@ -package de.marhali.easyi18n.editor.kotlin; - -import com.intellij.patterns.PlatformPatterns; -import com.intellij.psi.*; - -import com.intellij.util.ProcessingContext; - -import de.marhali.easyi18n.InstanceManager; -import de.marhali.easyi18n.editor.KeyReference; -import de.marhali.easyi18n.model.KeyPathConverter; - -import de.marhali.easyi18n.settings.ProjectSettingsService; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry; -import org.jetbrains.kotlin.psi.KtStringTemplateExpression; - -/** - * Kotlin translation key reference contributor. - * @author marhali - */ -public class KotlinKeyReferenceContributor extends PsiReferenceContributor { - - @Override - public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { - registrar.registerReferenceProvider(PlatformPatterns.psiElement().inside(KtStringTemplateExpression.class), getProvider()); - } - - private PsiReferenceProvider getProvider() { - return new PsiReferenceProvider() { - @Override - public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { - String value = null; - - for (PsiElement child : element.getChildren()) { - if(child instanceof KtLiteralStringTemplateEntry) { - value = child.getText(); - } - } - - if(value == null) { - return PsiReference.EMPTY_ARRAY; - } - - // Do not reference keys if service is disabled - if(!ProjectSettingsService.get(element.getProject()).getState().isAssistance()) { - return PsiReference.EMPTY_ARRAY; - } - - KeyPathConverter converter = new KeyPathConverter(element.getProject()); - - if(InstanceManager.get(element.getProject()).store().getData().getNode(converter.split(value)) == null) { - return PsiReference.EMPTY_ARRAY; - } - - return new PsiReference[] { new KeyReference(element, value) }; - } - }; - } -} diff --git a/src/main/resources/META-INF/de.marhali.easyi18n-java.xml b/src/main/resources/META-INF/de.marhali.easyi18n-java.xml index 4bf69d7..43a9382 100644 --- a/src/main/resources/META-INF/de.marhali.easyi18n-java.xml +++ b/src/main/resources/META-INF/de.marhali.easyi18n-java.xml @@ -1,5 +1,27 @@ - + + de.marhali.easyi18n.assistance.intention.JavaExtractIntention + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/META-INF/de.marhali.easyi18n-javascript.xml b/src/main/resources/META-INF/de.marhali.easyi18n-javascript.xml index 132273b..2c12e83 100644 --- a/src/main/resources/META-INF/de.marhali.easyi18n-javascript.xml +++ b/src/main/resources/META-INF/de.marhali.easyi18n-javascript.xml @@ -1,6 +1,17 @@ - - + + + + + + de.marhali.easyi18n.assistance.intention.JsExtractIntention + \ No newline at end of file diff --git a/src/main/resources/META-INF/de.marhali.easyi18n-kotlin.xml b/src/main/resources/META-INF/de.marhali.easyi18n-kotlin.xml index fe81e94..b1b898b 100644 --- a/src/main/resources/META-INF/de.marhali.easyi18n-kotlin.xml +++ b/src/main/resources/META-INF/de.marhali.easyi18n-kotlin.xml @@ -1,11 +1,27 @@ - + + de.marhali.easyi18n.assistance.intention.KtExtractIntention + - + - + + + + + \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 8df51ed..b1274f6 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -34,15 +34,6 @@ id="de.marhali.easyi18n.service.AppSettingsConfigurable" displayName="Easy I18n" nonDefaultProject="true"/> - - - - - -