reengineer editor assistance
Tasks Left - language support (vue, js / ts, kotlin, php) - Intention system is bounded to Java ATM
This commit is contained in:
parent
0a8a92d3f8
commit
6e9d0671ca
@ -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());
|
||||
}
|
||||
}
|
@ -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<CompletionParameters> 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<KeyPath> 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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
@ -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<String, String> results = new LinkedHashMap<>();
|
||||
|
||||
// Filter results for matching leafs (contextual and pluralization support)
|
||||
for (Map.Entry<String, TranslationNode> 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("<strong>").append(results.values().toArray()[0]).append("</strong>");
|
||||
builder.append(DocumentationMarkup.CONTENT_END);
|
||||
|
||||
} else { // Pluralization | Contextual relevant values
|
||||
builder.append(DocumentationMarkup.SECTIONS_START);
|
||||
|
||||
for (Map.Entry<String, String> entry : results.entrySet()) {
|
||||
builder.append(DocumentationMarkup.SECTION_HEADER_START);
|
||||
builder.append(entry.getKey()).append(":");
|
||||
builder.append(DocumentationMarkup.SECTION_SEPARATOR);
|
||||
builder.append("<p>");
|
||||
builder.append("<strong>").append(entry.getValue()).append("</strong>");
|
||||
}
|
||||
|
||||
builder.append(DocumentationMarkup.SECTIONS_END);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<FoldingDescriptor> descriptors = new ArrayList<>();
|
||||
|
||||
if(!isAssistance(root.getProject())) {
|
||||
return FoldingDescriptor.EMPTY;
|
||||
}
|
||||
|
||||
Collection<PsiLiteralExpression> 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);
|
||||
}
|
||||
}
|
@ -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<FoldingDescriptor> descriptors = new ArrayList<>();
|
||||
|
||||
if(!isAssistance(root.getProject())) {
|
||||
return FoldingDescriptor.EMPTY;
|
||||
}
|
||||
|
||||
Collection<KtStringTemplateEntry> 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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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<PsiElement> 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());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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<PsiElement> {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<CompletionParameters> {
|
||||
|
||||
@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<KeyPath> 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);
|
||||
}
|
||||
}
|
@ -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<PsiElement> {
|
||||
|
||||
@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:/]+$");
|
||||
}
|
||||
}
|
@ -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<PsiLiteralValue> literalValues = PsiTreeUtil.findChildrenOfType(root, PsiLiteralValue.class);
|
||||
List<FoldingDescriptor> 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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) };
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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) };
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,5 +1,27 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<lang.foldingBuilder language="JAVA" implementationClass="de.marhali.easyi18n.editor.generic.GenericFoldingBuilder" />
|
||||
<intentionAction>
|
||||
<className>de.marhali.easyi18n.assistance.intention.JavaExtractIntention</className>
|
||||
</intentionAction>
|
||||
|
||||
<psi.referenceContributor
|
||||
language="JAVA"
|
||||
implementation="de.marhali.easyi18n.assistance.reference.JavaKeyReferenceContributor"
|
||||
/>
|
||||
|
||||
<lang.foldingBuilder
|
||||
language="JAVA"
|
||||
implementationClass="de.marhali.easyi18n.assistance.folding.JavaFoldingBuilder"
|
||||
/>
|
||||
|
||||
<lang.documentationProvider
|
||||
language="JAVA"
|
||||
implementationClass="de.marhali.easyi18n.assistance.documentation.CommonDocumentationProvider"
|
||||
/>
|
||||
|
||||
<completion.contributor
|
||||
language="JAVA"
|
||||
implementationClass="de.marhali.easyi18n.assistance.completion.JavaCompletionContributor"
|
||||
/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
@ -1,6 +1,17 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<lang.foldingBuilder language="JavaScript" implementationClass="de.marhali.easyi18n.editor.generic.GenericFoldingBuilder" />
|
||||
<lang.foldingBuilder language="TypeScript" implementationClass="de.marhali.easyi18n.editor.generic.GenericFoldingBuilder" />
|
||||
<psi.referenceContributor
|
||||
language="JavaScript"
|
||||
implementation="de.marhali.easyi18n.assistance.reference.JsKeyReferenceContributor"
|
||||
/>
|
||||
|
||||
<lang.documentationProvider
|
||||
language="JavaScript"
|
||||
implementationClass="de.marhali.easyi18n.assistance.documentation.CommonDocumentationProvider"
|
||||
/>
|
||||
|
||||
<intentionAction>
|
||||
<className>de.marhali.easyi18n.assistance.intention.JsExtractIntention</className>
|
||||
</intentionAction>
|
||||
</extensions>
|
||||
</idea-plugin>
|
@ -1,11 +1,27 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<annotator language="kotlin" implementationClass="de.marhali.easyi18n.editor.kotlin.KotlinKeyAnnotator" />
|
||||
<intentionAction>
|
||||
<className>de.marhali.easyi18n.assistance.intention.KtExtractIntention</className>
|
||||
</intentionAction>
|
||||
|
||||
<completion.contributor language="kotlin"
|
||||
implementationClass="de.marhali.easyi18n.editor.kotlin.KotlinKeyCompletionContributor" />
|
||||
<psi.referenceContributor
|
||||
language="kotlin"
|
||||
implementation="de.marhali.easyi18n.assistance.reference.KtKeyReferenceContributor"
|
||||
/>
|
||||
|
||||
<psi.referenceContributor language="kotlin"
|
||||
implementation="de.marhali.easyi18n.editor.kotlin.KotlinKeyReferenceContributor" />
|
||||
<lang.documentationProvider
|
||||
language="kotlin"
|
||||
implementationClass="de.marhali.easyi18n.assistance.documentation.CommonDocumentationProvider"
|
||||
/>
|
||||
|
||||
<completion.contributor
|
||||
language="kotlin"
|
||||
implementationClass="de.marhali.easyi18n.assistance.completion.KtCompletionContributor"
|
||||
/>
|
||||
|
||||
<lang.foldingBuilder
|
||||
language="kotlin"
|
||||
implementationClass="de.marhali.easyi18n.assistance.folding.KtFoldingBuilder"
|
||||
/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
@ -34,15 +34,6 @@
|
||||
id="de.marhali.easyi18n.service.AppSettingsConfigurable"
|
||||
displayName="Easy I18n" nonDefaultProject="true"/>
|
||||
|
||||
<completion.contributor language="any"
|
||||
implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyCompletionContributor"/>
|
||||
|
||||
<annotator language=""
|
||||
implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyAnnotator"/>
|
||||
|
||||
<psi.referenceContributor
|
||||
implementation="de.marhali.easyi18n.editor.generic.GenericKeyReferenceContributor"/>
|
||||
|
||||
<notificationGroup displayType="BALLOON" id="Easy I18n Notification Group"/>
|
||||
|
||||
<errorHandler implementation="de.marhali.easyi18n.service.ErrorReportHandler"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user