finalize editor assistance

This commit is contained in:
marhali 2022-04-21 20:06:28 +02:00
parent 6e9d0671ca
commit fc107aa839
27 changed files with 536 additions and 309 deletions

View File

@ -9,6 +9,7 @@
### Added
- Key delimiters (namespace / section) can be configured
- Extract translation intention
- Full language support for Java, Kotlin, JavaScript / TypeScript, Vue and PHP
- Individual icon for tool-window and lookup items
- Dedicated configuration file (easy-i18n.xml) inside <kbd>.idea</kbd> folder

View File

@ -17,7 +17,7 @@ platformVersion = 2021.3
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins = org.jetbrains.kotlin, JavaScriptLanguage, org.jetbrains.plugins.vue:213.5744.223
platformPlugins = org.jetbrains.kotlin, JavaScriptLanguage, org.jetbrains.plugins.vue:213.5744.223, com.jetbrains.php:213.5744.279
# Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3
javaVersion = 11

View File

@ -3,14 +3,15 @@ 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;
import com.intellij.psi.PsiLiteralExpression;
/**
* Java specific completion contributor
* Java specific completion contributor.
* @author marhali
*/
public class JavaCompletionContributor extends CompletionContributor {
public JavaCompletionContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralValue.class), new KeyCompletionProvider());
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralExpression.class),
new KeyCompletionProvider());
}
}

View File

@ -0,0 +1,17 @@
package de.marhali.easyi18n.assistance.completion;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.lang.javascript.psi.JSLiteralExpression;
import com.intellij.patterns.PlatformPatterns;
/**
* JavaScript specific completion contributor.
* @author marhali
*/
public class JsCompletionContributor extends CompletionContributor {
public JsCompletionContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(JSLiteralExpression.class),
new KeyCompletionProvider());
}
}

View File

@ -0,0 +1,17 @@
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.jetbrains.php.lang.psi.elements.StringLiteralExpression;
/**
* Php specific completion contributor.
* @author marhali
*/
public class PhpCompletionContributor extends CompletionContributor {
public PhpCompletionContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(StringLiteralExpression.class),
new KeyCompletionProvider());
}
}

View File

@ -2,12 +2,17 @@ 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.lang.folding.FoldingDescriptor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import de.marhali.easyi18n.DataStore;
import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.assistance.OptionalAssistance;
import de.marhali.easyi18n.model.TranslationData;
import de.marhali.easyi18n.model.TranslationValue;
import de.marhali.easyi18n.settings.ProjectSettingsService;
import de.marhali.easyi18n.util.KeyPathConverter;
@ -15,25 +20,67 @@ import de.marhali.easyi18n.util.KeyPathConverter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* Language specific folding of translation key with preferred locale value.
* Language specific translation key folding with representative locale value.
* @author marhali
*/
abstract class AbstractFoldingBuilder extends FoldingBuilderEx implements OptionalAssistance {
protected static final FoldingGroup group = FoldingGroup.newGroup("EasyI18n key folding");
/**
* Extract all relevant folding regions for the desired root element.
* The implementation does not need to verify if the character literal is a valid translation.
* @param root Root element
* @return found regions
*/
abstract @NotNull List<Pair<String, PsiElement>> extractRegions(@NotNull PsiElement root);
/**
* 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
* Extract the text from the given node.
* @param node Node
* @return extracted text or null if not applicable
*/
protected @Nullable String getPlaceholderText(@NotNull Project project, @Nullable String text) {
abstract @Nullable String extractText(@NotNull ASTNode node);
@Override
public FoldingDescriptor @NotNull [] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) {
if(quick || !isAssistance(root.getProject())) {
return FoldingDescriptor.EMPTY;
}
List<FoldingDescriptor> descriptors = new ArrayList<>();
TranslationData data = InstanceManager.get(root.getProject()).store().getData();
KeyPathConverter converter = new KeyPathConverter(root.getProject());
for(Pair<String, PsiElement> region : extractRegions(root)) {
if(data.getTranslation(converter.fromString(region.first)) == null) {
continue;
}
TextRange range = new TextRange(region.second.getTextRange().getStartOffset() + 1,
region.second.getTextRange().getEndOffset() - 1);
// Some language implementations like [Vue Template] does not support FoldingGroup's
FoldingDescriptor descriptor = new FoldingDescriptor(region.second.getNode(), range);
descriptors.add(descriptor);
}
return descriptors.toArray(new FoldingDescriptor[0]);
}
@Override
public @Nullable String getPlaceholderText(@NotNull ASTNode node) {
String text = extractText(node);
if(text == null) {
return null;
}
Project project = node.getPsi().getProject();
DataStore store = InstanceManager.get(project).store();
KeyPathConverter converter = new KeyPathConverter(project);
TranslationValue localeValues = store.getData().getTranslation(converter.fromString(text));

View File

@ -1,66 +1,32 @@
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.openapi.util.Pair;
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;
import java.util.stream.Collectors;
/**
* 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]);
@NotNull List<Pair<String, PsiElement>> extractRegions(@NotNull PsiElement root) {
return PsiTreeUtil.findChildrenOfType(root, PsiLiteralExpression.class).stream().map(literalExpression ->
Pair.pair(String.valueOf(literalExpression.getValue()), (PsiElement) literalExpression))
.collect(Collectors.toList());
}
@Override
public @Nullable String getPlaceholderText(@NotNull ASTNode node) {
@Nullable String extractText(@NotNull ASTNode node) {
PsiLiteralExpression literalExpression = node.getPsi(PsiLiteralExpression.class);
String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null;
return getPlaceholderText(literalExpression.getProject(), value);
return String.valueOf(literalExpression.getValue());
}
}

View File

@ -0,0 +1,32 @@
package de.marhali.easyi18n.assistance.folding;
import com.intellij.lang.ASTNode;
import com.intellij.lang.javascript.psi.JSLiteralExpression;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.stream.Collectors;
/**
* JavaScript specific translation key folding.
* @author marhali
*/
public class JsFoldingBuilder extends AbstractFoldingBuilder {
@Override
@NotNull List<Pair<String, PsiElement>> extractRegions(@NotNull PsiElement root) {
return PsiTreeUtil.findChildrenOfType(root, JSLiteralExpression.class).stream().map(literalExpression ->
Pair.pair(literalExpression.getStringValue(), (PsiElement) literalExpression))
.collect(Collectors.toList());
}
@Override
@Nullable String extractText(@NotNull ASTNode node) {
JSLiteralExpression literalExpression = node.getPsi(JSLiteralExpression.class);
return literalExpression.getStringValue();
}
}

View File

@ -1,22 +1,16 @@
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.openapi.util.Pair;
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 org.jetbrains.kotlin.psi.KtStringTemplateExpression;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@ -25,39 +19,27 @@ import java.util.List;
*/
public class KtFoldingBuilder extends AbstractFoldingBuilder {
@Override
public FoldingDescriptor @NotNull [] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) {
List<FoldingDescriptor> descriptors = new ArrayList<>();
@NotNull List<Pair<String, PsiElement>> extractRegions(@NotNull PsiElement root) {
List<Pair<String, PsiElement>> regions = 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;
for (KtStringTemplateExpression templateExpression : PsiTreeUtil.findChildrenOfType(root, KtStringTemplateExpression.class)) {
for (KtStringTemplateEntry entry : templateExpression.getEntries()) {
regions.add(Pair.pair(entry.getText(), templateExpression));
break;
}
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]);
return regions;
}
@Override
public @Nullable String getPlaceholderText(@NotNull ASTNode node) {
KtStringTemplateEntry templateEntry = node.getPsi(KtStringTemplateEntry.class);
return getPlaceholderText(templateEntry.getProject(), templateEntry.getText());
@Nullable String extractText(@NotNull ASTNode node) {
KtStringTemplateExpression templateExpression = node.getPsi(KtStringTemplateExpression.class);
for (KtStringTemplateEntry entry : templateExpression.getEntries()) {
return entry.getText();
}
return null;
}
}

View File

@ -0,0 +1,31 @@
package de.marhali.easyi18n.assistance.folding;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.stream.Collectors;
/**
* Php specific translation key folding.
* @author marhali
*/
public class PhpFoldingBuilder extends AbstractFoldingBuilder {
@Override
@NotNull List<Pair<String, PsiElement>> extractRegions(@NotNull PsiElement root) {
return PsiTreeUtil.findChildrenOfType(root, StringLiteralExpression.class).stream().map(literalExpression ->
Pair.pair(literalExpression.getContents(), (PsiElement) literalExpression))
.collect(Collectors.toList());
}
@Override
@Nullable String extractText(@NotNull ASTNode node) {
StringLiteralExpression literalExpression = node.getPsi(StringLiteralExpression.class);
return literalExpression.getContents();
}
}

View File

@ -1,93 +0,0 @@
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;
}
}

View File

@ -0,0 +1,138 @@
package de.marhali.easyi18n.assistance.intention;
import com.intellij.codeInsight.intention.BaseElementAtCaretIntentionAction;
import com.intellij.codeInspection.util.IntentionFamilyName;
import com.intellij.codeInspection.util.IntentionName;
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.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.assistance.OptionalAssistance;
import de.marhali.easyi18n.dialog.AddDialog;
import de.marhali.easyi18n.dialog.EditDialog;
import de.marhali.easyi18n.model.KeyPath;
import de.marhali.easyi18n.model.Translation;
import de.marhali.easyi18n.model.TranslationData;
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;
import java.util.ResourceBundle;
/**
* Intention for translation related use-cases.
* Can be used to extract (create) translations or to edit existing ones.
* @author marhali
*/
abstract class AbstractTranslationIntention extends BaseElementAtCaretIntentionAction implements OptionalAssistance {
protected static final ResourceBundle bundle = ResourceBundle.getBundle("messages");
private boolean existingTranslation = false;
@Override
public @IntentionName @NotNull String getText() {
return existingTranslation
? bundle.getString("action.edit")
: bundle.getString("action.extract");
}
@Override
public @NotNull @IntentionFamilyName String getFamilyName() {
return "EasyI18n";
}
@Override
public boolean startInWriteAction() {
return false;
}
/**
* This is the only method a language-specific translation intention needs to implement.
* The implementation needs to verify element type and extract the relevant key literal or value.
* @param element Element at caret
* @return extract translation key (not verified!) or null if intention is not applicable for this element
*/
protected abstract @Nullable String extractText(@NotNull PsiElement element);
@NotNull TextRange convertRange(@NotNull TextRange input) {
return new TextRange(input.getStartOffset(), input.getEndOffset());
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
if(!isAssistance(project)) {
return false;
}
String text = extractText(element);
if(text != null) {
KeyPathConverter converter = new KeyPathConverter(project);
existingTranslation = InstanceManager.get(project).store().getData()
.getTranslation(converter.fromString(text)) != null;
}
return text != null;
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element)
throws IncorrectOperationException {
ProjectSettings settings = ProjectSettingsService.get(project).getState();
KeyPathConverter converter = new KeyPathConverter(settings);
String text = extractText(element);
if(text == null) {
throw new IncorrectOperationException("Cannot extract translation intention at caret");
}
TranslationData data = InstanceManager.get(project).store().getData();
KeyPath path = converter.fromString(text);
TranslationValue existingTranslation = data.getTranslation(path);
// Existing translation - edit dialog
if(existingTranslation != null) {
new EditDialog(project, new Translation(path, existingTranslation)).showAndHandle();
return;
}
// Extract translation by 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, path, null).showAndHandle();
return;
}
// Extract translation by preview locale value
AddDialog dialog = new AddDialog(project, new KeyPath(), text);
dialog.registerCallback(translationUpdate -> { // Replace text at caret with chosen translation key
if(editor != null) {
Document doc = editor.getDocument();
Caret caret = editor.getCaretModel().getPrimaryCaret();
TextRange range = convertRange(element.getTextRange());
WriteCommandAction.runWriteCommandAction(project, () ->
doc.replaceString(range.getStartOffset(), range.getEndOffset(),
converter.toString(translationUpdate.getChange().getKey())));
caret.removeSelection();
}
});
dialog.showAndHandle();
}
}

View File

@ -1,35 +0,0 @@
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;
}
}

View File

@ -0,0 +1,27 @@
package de.marhali.easyi18n.assistance.intention;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Java specific translation intention.
* @author marhali
*/
public class JavaTranslationIntention extends AbstractTranslationIntention {
@Override
protected @Nullable String extractText(@NotNull PsiElement element) {
if(!(element.getParent() instanceof PsiLiteralExpression)) {
return null;
}
return String.valueOf(((PsiLiteralExpression) element.getParent()).getValue());
}
@Override
@NotNull TextRange convertRange(@NotNull TextRange input) {
return new TextRange(input.getStartOffset() + 1, input.getEndOffset() - 1);
}
}

View File

@ -1,40 +0,0 @@
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;
}
}

View File

@ -0,0 +1,28 @@
package de.marhali.easyi18n.assistance.intention;
import com.intellij.lang.javascript.psi.JSLiteralExpression;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* JavaScript specific translation key intention.
* @author marhali
*/
public class JsTranslationIntention extends AbstractTranslationIntention {
@Override
protected @Nullable String extractText(@NotNull PsiElement element) {
if(!(element.getParent() instanceof JSLiteralExpression)) {
return null;
}
return ((JSLiteralExpression) element.getParent()).getStringValue();
}
@Override
@NotNull TextRange convertRange(@NotNull TextRange input) {
return new TextRange(input.getStartOffset() + 1, input.getEndOffset() - 1);
}
}

View File

@ -1,41 +0,0 @@
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;
}
}

View File

@ -0,0 +1,23 @@
package de.marhali.easyi18n.assistance.intention;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
/**
* Kotlin specific translation key intention.
* @author marhali
*/
public class KtTranslationIntention extends AbstractTranslationIntention {
@Override
protected @Nullable String extractText(@NotNull PsiElement element) {
if(!(element.getParent() instanceof KtLiteralStringTemplateEntry)) {
return null;
}
KtLiteralStringTemplateEntry expression = (KtLiteralStringTemplateEntry) element.getParent();
return expression.getText();
}
}

View File

@ -0,0 +1,23 @@
package de.marhali.easyi18n.assistance.intention;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Php specific translation intention
* @author marhali
*/
public class PhpTranslationIntention extends AbstractTranslationIntention {
@Override
protected @Nullable String extractText(@NotNull PsiElement element) {
if(!(element.getParent() instanceof StringLiteralExpression)) {
return null;
}
return ((StringLiteralExpression) element.getParent()).getContents();
}
}

View File

@ -4,6 +4,7 @@ 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;
@ -14,12 +15,10 @@ import org.jetbrains.annotations.NotNull;
*/
public class JavaKeyReferenceContributor extends AbstractKeyReferenceContributor {
// TODO: why not PsiLiteralExpression?
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(
PlatformPatterns.psiElement(PsiLiteralValue.class),
PlatformPatterns.psiElement(PsiLiteralExpression.class),
getProvider());
}
@ -30,8 +29,10 @@ public class JavaKeyReferenceContributor extends AbstractKeyReferenceContributor
@NotNull PsiElement element, @NotNull ProcessingContext context) {
Project project = element.getProject();
PsiLiteralValue literalValue = (PsiLiteralValue) element;
String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null;
PsiLiteralExpression literalExpression = (PsiLiteralExpression) element;
String value = literalExpression.getValue() instanceof String
? (String) literalExpression.getValue()
: null;
return getReferences(project, element, value);
}

View File

@ -0,0 +1,37 @@
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 com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import org.jetbrains.annotations.NotNull;
/**
* Php specific key reference binding
*/
public class PhpKeyReferenceContributor extends AbstractKeyReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(
PlatformPatterns.psiElement(StringLiteralExpression.class),
getProvider());
}
private PsiReferenceProvider getProvider() {
return new PsiReferenceProvider() {
@Override
public PsiReference @NotNull [] getReferencesByElement(
@NotNull PsiElement element, @NotNull ProcessingContext context) {
Project project = element.getProject();
StringLiteralExpression literalExpression = (StringLiteralExpression) element;
return getReferences(project, element, literalExpression.getContents());
}
};
}
}

View File

@ -1,7 +1,7 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<intentionAction>
<className>de.marhali.easyi18n.assistance.intention.JavaExtractIntention</className>
<className>de.marhali.easyi18n.assistance.intention.JavaTranslationIntention</className>
</intentionAction>
<psi.referenceContributor

View File

@ -10,8 +10,36 @@
implementationClass="de.marhali.easyi18n.assistance.documentation.CommonDocumentationProvider"
/>
<!-- JavaScript plugin also includes TypeScript -->
<lang.documentationProvider
language="TypeScript"
implementationClass="de.marhali.easyi18n.assistance.documentation.CommonDocumentationProvider"
/>
<!-- JavaScript plugin also includes TypeScript -->
<lang.foldingBuilder
language="TypeScript"
implementationClass="de.marhali.easyi18n.assistance.folding.JsFoldingBuilder"
/>
<!-- JavaScript plugin also includes TypeScript JSX -->
<lang.foldingBuilder
language="TypeScript JSX"
implementationClass="de.marhali.easyi18n.assistance.folding.JsFoldingBuilder"
/>
<lang.foldingBuilder
language="JavaScript"
implementationClass="de.marhali.easyi18n.assistance.folding.JsFoldingBuilder"
/>
<intentionAction>
<className>de.marhali.easyi18n.assistance.intention.JsExtractIntention</className>
<className>de.marhali.easyi18n.assistance.intention.JsTranslationIntention</className>
</intentionAction>
<completion.contributor
language="JavaScript"
implementationClass="de.marhali.easyi18n.assistance.completion.JsCompletionContributor"
/>
</extensions>
</idea-plugin>

View File

@ -1,7 +1,7 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<intentionAction>
<className>de.marhali.easyi18n.assistance.intention.KtExtractIntention</className>
<className>de.marhali.easyi18n.assistance.intention.KtTranslationIntention</className>
</intentionAction>
<psi.referenceContributor

View File

@ -0,0 +1,27 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<intentionAction>
<className>de.marhali.easyi18n.assistance.intention.PhpTranslationIntention</className>
</intentionAction>
<psi.referenceContributor
language="PHP"
implementation="de.marhali.easyi18n.assistance.reference.PhpKeyReferenceContributor"
/>
<lang.foldingBuilder
language="PHP"
implementationClass="de.marhali.easyi18n.assistance.folding.PhpFoldingBuilder"
/>
<lang.documentationProvider
language="PHP"
implementationClass="de.marhali.easyi18n.assistance.documentation.CommonDocumentationProvider"
/>
<completion.contributor
language="PHP"
implementationClass="de.marhali.easyi18n.assistance.completion.PhpCompletionContributor"
/>
</extensions>
</idea-plugin>

View File

@ -1,6 +1,15 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<lang.foldingBuilder language="HTML"
implementationClass="de.marhali.easyi18n.editor.generic.GenericFoldingBuilder" />
<lang.foldingBuilder language="VueJS" implementationClass="de.marhali.easyi18n.assistance.folding.JsFoldingBuilder" />
<lang.documentationProvider
language="VueJS"
implementationClass="de.marhali.easyi18n.assistance.documentation.CommonDocumentationProvider"
/>
<lang.documentationProvider
language="Vue"
implementationClass="de.marhali.easyi18n.assistance.documentation.CommonDocumentationProvider"
/>
</extensions>
</idea-plugin>

View File

@ -13,6 +13,7 @@
<depends optional="true" config-file="de.marhali.easyi18n-javascript.xml">JavaScript</depends>
<depends optional="true" config-file="de.marhali.easyi18n-java.xml">com.intellij.java</depends>
<depends optional="true" config-file="de.marhali.easyi18n-vue.xml">org.jetbrains.plugins.vue</depends>
<depends optional="true" config-file="de.marhali.easyi18n-php.xml">com.jetbrains.php</depends>
<actions>
<action