diff --git a/.gitignore b/.gitignore index 8c2dd28e..5b154cb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ out/ .idea/ +Yii2.jar diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..3e7c4856 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,32 @@ +Yii2 Support is free software. It is released under the terms of +the following BSD License. + +Copyright © 2017 by Vladislav Nikishin aka NVlad (wildvampir@gmail.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Yii2 Support nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index 816ce1dd..266ca15f 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -1,17 +1,23 @@ - com.nvlad.yii2-framework - Yii2 Framework - 0.1 + com.yii2support + Yii2 Support + 0.2.2 NVlad - most HTML tags may be used + Yii2 Support for PhpStorm
+
+ Features + ]]>
- most HTML tags may be used + ]]> @@ -27,7 +33,9 @@ com.intellij.modules.platform - + + + diff --git a/resources/icons/view.png b/resources/icons/view.png deleted file mode 100644 index 65da52b3..00000000 Binary files a/resources/icons/view.png and /dev/null differ diff --git a/resources/icons/view_dark.png b/resources/icons/view_dark.png deleted file mode 100644 index 956afaeb..00000000 Binary files a/resources/icons/view_dark.png and /dev/null differ diff --git a/src/com/yii2framework/completion/views/CompletionContributor.java b/src/com/yii2framework/completion/views/CompletionContributor.java deleted file mode 100644 index 4a3d20d8..00000000 --- a/src/com/yii2framework/completion/views/CompletionContributor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.yii2framework.completion.views; - -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.patterns.ElementPattern; -import com.intellij.patterns.PlatformPatterns; -import com.intellij.psi.PsiElement; -import com.jetbrains.php.lang.psi.elements.*; - -/** - * Created by NVlad on 27.12.2016. - */ -public class CompletionContributor extends com.intellij.codeInsight.completion.CompletionContributor { - public CompletionContributor() { - extend(CompletionType.BASIC, ElementPattern(), new CompletionProvider()); - } - - private static ElementPattern ElementPattern() { - return PlatformPatterns.psiElement(PsiElement.class) - .withParent(PlatformPatterns.psiElement(StringLiteralExpression.class) - .withParent(PlatformPatterns.psiElement(ParameterList.class) - .withParent(PlatformPatterns.psiElement(MethodReference.class)))); - } -} diff --git a/src/com/yii2support/common/Patterns.java b/src/com/yii2support/common/Patterns.java new file mode 100644 index 00000000..af03f373 --- /dev/null +++ b/src/com/yii2support/common/Patterns.java @@ -0,0 +1,27 @@ +package com.yii2support.common; + +import com.intellij.patterns.InitialPatternCondition; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.util.ArrayUtil; +import com.intellij.util.ProcessingContext; +import com.jetbrains.php.injection.PhpElementPattern.Capture; +import com.jetbrains.php.lang.psi.elements.MethodReference; +import org.jetbrains.annotations.Nullable; + +/** + * Created by NVlad on 12.01.2017. + */ +public class Patterns extends PlatformPatterns { + public static Capture methodWithName(String... methodNames) { + return new Capture<>(new InitialPatternCondition(MethodReference.class) { + @Override + public boolean accepts(@Nullable Object o, ProcessingContext context) { + if (o instanceof MethodReference) { + String methodReferenceName = ((MethodReference) o).getName(); + return methodReferenceName != null && ArrayUtil.contains(methodReferenceName, methodNames); + } + return super.accepts(o, context); + } + }); + } +} diff --git a/src/com/yii2support/i18n/CategoryLookupElement.java b/src/com/yii2support/i18n/CategoryLookupElement.java new file mode 100644 index 00000000..30d2de37 --- /dev/null +++ b/src/com/yii2support/i18n/CategoryLookupElement.java @@ -0,0 +1,41 @@ +package com.yii2support.i18n; + +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * Created by NVlad on 06.01.2017. + */ +public class CategoryLookupElement extends LookupElement { + private PsiElement myCategory; + + CategoryLookupElement(PsiElement category) { + myCategory = category; + } + + @NotNull + @Override + public String getLookupString() { + if (myCategory instanceof PsiFile) { + String filename = ((PsiFile) myCategory).getName(); + return filename.substring(0, filename.lastIndexOf(".")); + } + + return myCategory.getText(); + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + super.renderElement(presentation); + + if (myCategory instanceof PsiFile) { + PsiFile file = (PsiFile) myCategory; + String filename = file.getName(); + presentation.setIcon(file.getIcon(0)); + presentation.setItemText(filename.substring(0, filename.lastIndexOf("."))); + } + } +} diff --git a/src/com/yii2support/i18n/CompletionContributor.java b/src/com/yii2support/i18n/CompletionContributor.java new file mode 100644 index 00000000..1c4a3759 --- /dev/null +++ b/src/com/yii2support/i18n/CompletionContributor.java @@ -0,0 +1,39 @@ +package com.yii2support.i18n; + +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import com.jetbrains.php.lang.psi.elements.MethodReference; +import com.jetbrains.php.lang.psi.elements.ParameterList; +import com.yii2support.common.Patterns; +import org.jetbrains.annotations.NotNull; + +/** + * Created by NVlad on 06.01.2017. + */ +public class CompletionContributor extends com.intellij.codeInsight.completion.CompletionContributor { + public CompletionContributor() { + extend(CompletionType.BASIC, ElementPattern(), new CompletionProvider()); + } + + @Override + public boolean invokeAutoPopup(@NotNull PsiElement position, char typeChar) { + if (typeChar == '\'' || typeChar == '"') { + if (position instanceof LeafPsiElement && (position.getText().equals("$category") || position.getText().equals("$message"))) { + return true; + } + if (position.getNextSibling() instanceof ParameterList || position.getParent() instanceof MethodReference) { + return true; + } + } + + return false; + } + + private static ElementPattern ElementPattern() { + return PlatformPatterns.psiElement(PsiElement.class) + .withSuperParent(3, Patterns.methodWithName("t")); + } +} diff --git a/src/com/yii2support/i18n/CompletionProvider.java b/src/com/yii2support/i18n/CompletionProvider.java new file mode 100644 index 00000000..e13aee3b --- /dev/null +++ b/src/com/yii2support/i18n/CompletionProvider.java @@ -0,0 +1,61 @@ +package com.yii2support.i18n; + +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.psi.PsiElement; +import com.intellij.util.ProcessingContext; +import com.jetbrains.php.lang.psi.elements.*; +import org.jetbrains.annotations.NotNull; + +/** + * Created by NVlad on 06.01.2017. + */ +public class CompletionProvider extends com.intellij.codeInsight.completion.CompletionProvider { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) { + PhpPsiElement psiElement = (PhpPsiElement) parameters.getPosition().getParent(); + + MethodReference methodReference = (MethodReference) psiElement.getParent().getParent(); + PhpExpression classReference = methodReference.getClassReference(); + if (classReference != null && classReference.getName() != null) { + if (methodReference.isStatic() && classReference.getName().equals("Yii")) { + String methodName = methodReference.getName(); + if (methodName != null && methodReference.getParameterList() != null) { + PsiElement[] methodParameters = methodReference.getParameterList().getParameters(); + + int parameterIndex = -1; + for (int i = 0; i < methodParameters.length; i++) { + if (psiElement == methodParameters[i]) { + parameterIndex = i; + break; + } + } + + switch (parameterIndex) { + case 0: + fillCategories(psiElement, result); + break; + case 1: + if (methodParameters[0] instanceof StringLiteralExpression) { + String category = ((StringLiteralExpression) methodParameters[0]).getContents(); + fillMessages(psiElement, category, result); + } + break; + } + } + } + } + } + + private void fillCategories(PhpPsiElement element, CompletionResultSet result) { + for (PsiElement category : Util.getCategories(element)) { + result.addElement(new CategoryLookupElement(category)); + } + } + + private void fillMessages(PhpPsiElement element, String category, CompletionResultSet result) { + for (ArrayHashElement message : Util.getMessages(element, category)) { + result.addElement(new MessageLookupElement(element, message)); + } + } +} diff --git a/src/com/yii2support/i18n/MessageLookupElement.java b/src/com/yii2support/i18n/MessageLookupElement.java new file mode 100644 index 00000000..9c147ce2 --- /dev/null +++ b/src/com/yii2support/i18n/MessageLookupElement.java @@ -0,0 +1,120 @@ +package com.yii2support.i18n; + +import com.intellij.codeInsight.completion.InsertionContext; +import com.intellij.codeInsight.lookup.AutoCompletionPolicy; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.intellij.psi.PsiElement; +import com.jetbrains.php.lang.psi.elements.*; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by NVlad on 06.01.2017. + */ +public class MessageLookupElement extends LookupElement { + private PhpPsiElement myElement; + private ArrayHashElement myMessage; + + MessageLookupElement(PhpPsiElement element, ArrayHashElement message) { + myElement = element; + myMessage = message; + } + + @NotNull + @Override + public String getLookupString() { + return Util.PhpExpressionValue((PhpExpression) myMessage.getKey()); + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + super.renderElement(presentation); + + if (myMessage.getKey() instanceof StringLiteralExpression) { + presentation.setItemText(((StringLiteralExpression) myMessage.getKey()).getContents()); + presentation.setIcon(myMessage.getKey().getIcon(0)); + } + + PhpExpression value = (PhpExpression) myMessage.getValue(); + if (value != null) { + String text = Util.PhpExpressionValue(value); + + if (!text.isEmpty()) { + presentation.setTailText(" = " + text, true); + } + + presentation.setTypeText(value.getType().toString()); + presentation.setTypeGrayed(true); + } + } + + @Override + public void handleInsert(InsertionContext context) { + super.handleInsert(context); + + int suffixLength = myElement.getText().length() - 21 - myElement.getText().lastIndexOf("IntellijIdeaRulezzz "); + int blockStart = context.getSelectionEndOffset(); + context.getDocument().deleteString(blockStart, blockStart + suffixLength); + + if (myMessage.getValue() instanceof StringLiteralExpression) { + ArrayList matches = new ArrayList<>(); + + StringLiteralExpression value = (StringLiteralExpression) myMessage.getValue(); + + Pattern pointers = Pattern.compile("\\{([\\w\\d]+)[},]", Pattern.MULTILINE | Pattern.UNICODE_CASE); + Matcher matcher = pointers.matcher(value.getContents()); + while (matcher.find()) { + String match = matcher.group(1); + + if (!matches.contains(match)) { + matches.add(match); + } + } + + if (matches.size() > 0) { + ParameterList parameterList = (ParameterList) myElement.getParent(); + if (parameterList.getParameters().length == 2) { + + String params = ""; + if (matches.size() == 1 && matches.get(0).equals("0")) { + params = ", []"; + } else { + for (String match : matches) { + if (params.length() > 0) { + params = params + ", "; + } + params = params.concat("'" + match + "' => "); + } + params = ", [" + params + "]"; + } + + context.getDocument().insertString(context.getSelectionEndOffset() + 1, params); + } + } else { + cleanParams(context); + } + } else { + cleanParams(context); + } + } + + @Override + public AutoCompletionPolicy getAutoCompletionPolicy() { + return AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE; + } + + private void cleanParams(InsertionContext context) { + ParameterList parameterList = (ParameterList) myElement.getParent(); + if (parameterList.getParameters().length == 3) { + PsiElement[] parameters = parameterList.getParameters(); + int blockStart = context.getSelectionEndOffset() + 1; + int paramSpace = parameters[2].getTextRange().getStartOffset() - parameters[1].getTextRange().getEndOffset(); + int blockLength = parameters[2].getTextLength() + paramSpace; + context.getDocument().deleteString(blockStart, blockStart + blockLength); + } + } +} diff --git a/src/com/yii2support/i18n/Util.java b/src/com/yii2support/i18n/Util.java new file mode 100644 index 00000000..1cd14b2d --- /dev/null +++ b/src/com/yii2support/i18n/Util.java @@ -0,0 +1,146 @@ +package com.yii2support.i18n; + +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.jetbrains.php.lang.psi.elements.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +/** + * Created by NVlad on 06.01.2017. + */ +class Util { + @NotNull + static PsiElement[] getCategories(PhpPsiElement element) { + ArrayList categories = new ArrayList<>(); + + PsiDirectory directory = getDirectory(element); + if (directory != null) { + Collections.addAll(categories, directory.getFiles()); + } + + return categories.toArray(new PsiElement[categories.size()]); + } + + @NotNull + static ArrayHashElement[] getMessages(PhpPsiElement element, String category) { + ArrayList messages = new ArrayList<>(); + + PsiDirectory directory = getDirectory(element); + if (directory != null) { + PsiFile file = directory.findFile(category.concat(".php")); + if (file != null) { + messages.addAll(loadMessagesFromFile(file)); + } + } + + return messages.toArray(new ArrayHashElement[messages.size()]); + } +// +// public String[] getMessagePointers(String category, String message) { +// return new String[0]; +// } + + @NotNull + static String PhpExpressionValue(PhpExpression expression) { + if (expression instanceof StringLiteralExpression) { + return ((StringLiteralExpression) expression).getContents(); + } + if (expression instanceof ConstantReference) { + Constant constant = (Constant) ((ConstantReference) expression).resolve(); + if (constant != null) { + return PhpExpressionValue((PhpExpression) constant.getValue()); + } + } + if (expression instanceof ClassConstantReference) { + ClassReference classReference = (ClassReference) ((ClassConstantReference) expression).getClassReference(); + if (classReference != null) { + PhpClass phpClass = (PhpClass) classReference.resolve(); + if (phpClass != null) { + Field field = phpClass.findFieldByName(expression.getName(), true); + if (field != null) { + return PhpExpressionValue((PhpExpression) field.getDefaultValue()); + } + } + } + } + if (expression instanceof Variable) { + PhpExpression variable = (PhpExpression) ((Variable) expression).resolve(); + + if (variable != null && variable.getContext() instanceof AssignmentExpression) { + AssignmentExpression assignmentExpression = (AssignmentExpression) variable.getContext(); + return PhpExpressionValue((PhpExpression) assignmentExpression.getValue()); + } + } + if (expression instanceof ConcatenationExpression) { + ConcatenationExpression concatenation = (ConcatenationExpression) expression; + return PhpExpressionValue((PhpExpression) concatenation.getLeftOperand()) + PhpExpressionValue((PhpExpression) concatenation.getRightOperand()); + } + String expressionType = expression.getType().toString(); + if (expressionType.equals("int") || expressionType.equals("float")) { + return expression.getText(); + } + + return ""; + } + + @Nullable + private static PsiDirectory getDirectory(PsiElement element) { + PsiFile file = element.getContainingFile().getOriginalFile(); + String filename = file.getName(); + PsiDirectory directory = file.getParent(); + + filename = filename.substring(0, filename.lastIndexOf(".")); + + if (directory != null) { + if (filename.endsWith("Controller")) { + directory = directory.getParentDirectory(); + } else { + PsiDirectory messageParent = directory.findSubdirectory("messages"); + while (messageParent == null) { + directory = directory.getParentDirectory(); + if (directory == null) { + break; + } + messageParent = directory.findSubdirectory("messages"); + } + } + } + if (directory != null) { + directory = directory.findSubdirectory("messages"); + if (directory != null && directory.getSubdirectories().length > 0) { + directory = directory.getSubdirectories()[0]; + return directory; + } + } + + return null; + } + + private static Collection loadMessagesFromFile(PsiFile file) { + ArrayList result = new ArrayList<>(); + + GroupStatement groupStatement = (GroupStatement) file.getFirstChild(); + for (PsiElement element : groupStatement.getChildren()) { + if (element instanceof PhpReturn) { + if (((PhpReturn) element).getFirstPsiChild() instanceof ArrayCreationExpression) { + ArrayCreationExpression array = (ArrayCreationExpression) ((PhpReturn) element).getFirstPsiChild(); + if (array != null) { + for (ArrayHashElement hashElement : array.getHashElements()) { + result.add(hashElement); + } + } + } + + break; + } + } + + return result; + } +} diff --git a/src/com/yii2support/views/CompletionContributor.java b/src/com/yii2support/views/CompletionContributor.java new file mode 100644 index 00000000..bf451083 --- /dev/null +++ b/src/com/yii2support/views/CompletionContributor.java @@ -0,0 +1,39 @@ +package com.yii2support.views; + +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import com.jetbrains.php.lang.psi.elements.ParameterList; +import com.yii2support.common.Patterns; +import org.jetbrains.annotations.NotNull; + +/** + * Created by NVlad on 27.12.2016. + */ +public class CompletionContributor extends com.intellij.codeInsight.completion.CompletionContributor { + public CompletionContributor() { + extend(CompletionType.BASIC, ElementPattern(), new CompletionProvider()); + } + + @Override + public boolean invokeAutoPopup(@NotNull PsiElement position, char typeChar) { + if (typeChar == '\'' || typeChar == '"') { + if (position instanceof LeafPsiElement && position.getText().equals("$view")) { + return true; + } + if (position.getNextSibling() instanceof ParameterList) { + return true; + } + } + + return false; + } + + private static ElementPattern ElementPattern() { + + return PlatformPatterns.psiElement() + .withSuperParent(3, Patterns.methodWithName("render", "renderAjax", "renderPartial")); + } +} diff --git a/src/com/yii2framework/completion/views/CompletionProvider.java b/src/com/yii2support/views/CompletionProvider.java similarity index 52% rename from src/com/yii2framework/completion/views/CompletionProvider.java rename to src/com/yii2support/views/CompletionProvider.java index cb29aeaa..3fd708de 100644 --- a/src/com/yii2framework/completion/views/CompletionProvider.java +++ b/src/com/yii2support/views/CompletionProvider.java @@ -1,4 +1,4 @@ -package com.yii2framework.completion.views; +package com.yii2support.views; import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; @@ -6,31 +6,38 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; -import com.jetbrains.php.lang.psi.elements.PhpPsiElement; +import com.jetbrains.php.lang.psi.elements.MethodReference; import org.jetbrains.annotations.NotNull; /** * Created by NVlad on 27.12.2016. */ -public class CompletionProvider extends com.intellij.codeInsight.completion.CompletionProvider { +public class CompletionProvider extends com.intellij.codeInsight.completion.CompletionProvider { @Override protected void addCompletions(@NotNull CompletionParameters completionParameters, ProcessingContext processingContext, @NotNull CompletionResultSet completionResultSet) { PsiElement psiElement = completionParameters.getPosition(); - PhpPsiElement phpPsiElement = (PhpPsiElement) psiElement.getParent().getParent().getParent(); - String psiElementName = phpPsiElement.getName(); + MethodReference methodReference = (MethodReference) psiElement.getParent().getParent().getParent(); + String methodName = methodReference.getName(); - if (psiElementName != null && psiElementName.startsWith("render")) { - PsiDirectory viewsPath = getViewsPsiDirectory(completionParameters.getOriginalFile(), psiElement); - - if (viewsPath != null) { - String enteredText = psiElement.getText().replaceAll("IntellijIdeaRulezzz ", ""); - for (PsiDirectory psiDirectory : viewsPath.getSubdirectories()) { - completionResultSet.addElement(new DirectoryLookupElement(psiDirectory, enteredText)); + if (ArrayUtil.indexOf(methodReference.getParameters(), psiElement.getParent()) == 0) { + if (methodName != null) { + if (completionResultSet.getPrefixMatcher().getPrefix().contains("/")) { + String prefix = completionResultSet.getPrefixMatcher().getPrefix(); + prefix = prefix.substring(prefix.lastIndexOf("/") + 1); + completionResultSet = completionResultSet.withPrefixMatcher(prefix); } + PsiDirectory viewsPath = getViewsPsiDirectory(completionParameters.getOriginalFile(), psiElement); + + if (viewsPath != null) { + for (PsiDirectory psiDirectory : viewsPath.getSubdirectories()) { + completionResultSet.addElement(new DirectoryLookupElement(psiDirectory)); + } - for (PsiFile psiFile : viewsPath.getFiles()) { - completionResultSet.addElement(new ViewLookupElement(psiFile, enteredText)); + for (PsiFile psiFile : viewsPath.getFiles()) { + completionResultSet.addElement(new ViewLookupElement(psiFile)); + } } } } @@ -54,7 +61,11 @@ private PsiDirectory getViewsPsiDirectory(PsiFile psiFile, PsiElement psiElement } } - String enteredText = psiElement.getText().replaceAll("IntellijIdeaRulezzz ", ""); + String enteredText = psiElement.getText(); + int iir = enteredText.indexOf("IntellijIdeaRulezzz "); + if (iir != -1) { + enteredText = enteredText.substring(0, iir); + } String enteredPath = enteredText; if (enteredText.startsWith("/")) { while (psiDirectory != null && !psiDirectory.getName().equals("views")) { @@ -63,19 +74,23 @@ private PsiDirectory getViewsPsiDirectory(PsiFile psiFile, PsiElement psiElement enteredPath = enteredPath.substring(1); } - String directory; - while (!enteredPath.equals("")) { - if (enteredPath.contains("/")) { - directory = enteredPath.substring(0, enteredPath.indexOf("/")); - enteredPath = enteredPath.substring(directory.length() + 1); - psiDirectory = psiDirectory.findSubdirectory(directory); - } else { - psiDirectory = psiDirectory.findSubdirectory(enteredPath); + if (!enteredPath.endsWith("/") && enteredPath.contains("/")) { + enteredPath = enteredPath.substring(0, enteredPath.lastIndexOf("/") + 1); + if (enteredPath.length() == 1) { enteredPath = ""; } } - System.out.println(enteredPath); + if (enteredPath.endsWith("/")) { + String directory; + while (!enteredPath.equals("")) { + directory = enteredPath.substring(0, enteredPath.indexOf("/")); + enteredPath = enteredPath.substring(directory.length() + 1); + if (psiDirectory != null) { + psiDirectory = psiDirectory.findSubdirectory(directory); + } + } + } return psiDirectory; } diff --git a/src/com/yii2framework/completion/views/DirectoryLookupElement.java b/src/com/yii2support/views/DirectoryLookupElement.java similarity index 61% rename from src/com/yii2framework/completion/views/DirectoryLookupElement.java rename to src/com/yii2support/views/DirectoryLookupElement.java index a30d9594..4bedd3d3 100644 --- a/src/com/yii2framework/completion/views/DirectoryLookupElement.java +++ b/src/com/yii2support/views/DirectoryLookupElement.java @@ -1,4 +1,4 @@ -package com.yii2framework.completion.views; +package com.yii2support.views; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementPresentation; @@ -13,26 +13,16 @@ public class DirectoryLookupElement extends LookupElement { private Icon icon; private String name; - private String prefix; - private String lookup; - DirectoryLookupElement(PsiDirectory directory, String searchPrefix) { + DirectoryLookupElement(PsiDirectory directory) { icon = directory.getIcon(0); name = directory.getName(); - prefix = searchPrefix; - if (searchPrefix.startsWith("/")) { - prefix = prefix.substring(1); - } - if (prefix.length() > 0 && !prefix.endsWith("/")) { - prefix = prefix.concat("/"); - } - lookup = directory.getName().concat("/"); } @NotNull @Override public String getLookupString() { - return prefix.concat(lookup); + return name.concat("/"); } @Override diff --git a/src/com/yii2support/views/PsiReference.java b/src/com/yii2support/views/PsiReference.java new file mode 100644 index 00000000..ca1ce751 --- /dev/null +++ b/src/com/yii2support/views/PsiReference.java @@ -0,0 +1,108 @@ +package com.yii2support.views; + +import com.intellij.codeInsight.template.macro.SplitWordsMacro; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiReferenceBase; +import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Created by NVlad on 02.01.2017. + */ +public class PsiReference extends PsiReferenceBase { + private PsiElement myTarget; + + PsiReference(@NotNull PsiElement element) { + super(element); + } + + @Nullable + @Override + public PsiElement resolve() { + if (myTarget == null) { + PsiFile psiFile = getViewPsiFile(myElement); + if (psiFile != null) { + myTarget = psiFile.getOriginalElement(); + } + } + + return myTarget; + } + + @NotNull + @Override + public Object[] getVariants() { + return new Object[0]; + } + + private PsiFile getViewPsiFile(PsiElement psiElement) { + PsiFile psiFile = psiElement.getContainingFile(); + StringLiteralExpression expression = (StringLiteralExpression) psiElement; + String filename = expression.getContents(); + if (filename.contains("/")) { + filename = filename.substring(filename.lastIndexOf("/") + 1); + } + if (!filename.contains(".")) { + filename = filename.concat(".php"); + } + + PsiDirectory directory = getViewsPsiDirectory(psiFile, psiElement); + + if (directory == null) { + return null; + } + + return directory.findFile(filename); + } + + private PsiDirectory getViewsPsiDirectory(PsiFile psiFile, PsiElement psiElement) { + String fileName = psiFile.getName().substring(0, psiFile.getName().lastIndexOf(".")); + PsiDirectory psiDirectory = psiFile.getContainingDirectory(); + + if (fileName.endsWith("Controller")) { + psiDirectory = psiFile.getContainingDirectory().getParentDirectory(); + if (psiDirectory != null) { + psiDirectory = psiDirectory.findSubdirectory("views"); + + if (psiDirectory != null) { + String container = fileName.substring(0, fileName.length() - 10); + container = new SplitWordsMacro.LowercaseAndDash().convertString(container); + + psiDirectory = psiDirectory.findSubdirectory(container); + } + } + } + + String enteredText = ((StringLiteralExpression) psiElement).getContents(); + String enteredPath = enteredText; + if (enteredText.startsWith("/")) { + while (psiDirectory != null && !psiDirectory.getName().equals("views")) { + psiDirectory = psiDirectory.getParentDirectory(); + } + enteredPath = enteredPath.substring(1); + } + + if (!enteredPath.endsWith("/") && enteredPath.contains("/")) { + enteredPath = enteredPath.substring(0, enteredPath.lastIndexOf("/") + 1); + if (enteredPath.length() == 1) { + enteredPath = ""; + } + } + + if (enteredPath.endsWith("/")) { + String directory; + while (!enteredPath.equals("")) { + directory = enteredPath.substring(0, enteredPath.indexOf("/")); + enteredPath = enteredPath.substring(directory.length() + 1); + if (psiDirectory != null) { + psiDirectory = psiDirectory.findSubdirectory(directory); + } + } + } + + return psiDirectory; + } +} diff --git a/src/com/yii2support/views/PsiReferenceContributor.java b/src/com/yii2support/views/PsiReferenceContributor.java new file mode 100644 index 00000000..00fe9be5 --- /dev/null +++ b/src/com/yii2support/views/PsiReferenceContributor.java @@ -0,0 +1,25 @@ +package com.yii2support.views; + +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReferenceRegistrar; +import com.jetbrains.php.lang.psi.elements.MethodReference; +import com.jetbrains.php.lang.psi.elements.ParameterList; +import org.jetbrains.annotations.NotNull; + +/** + * Created by NVlad on 02.01.2017. + */ +public class PsiReferenceContributor extends com.intellij.psi.PsiReferenceContributor { + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar psiReferenceRegistrar) { + psiReferenceRegistrar.registerReferenceProvider(ElementPattern(), new PsiReferenceProvider()); + } + + private static ElementPattern ElementPattern() { + return PlatformPatterns.psiElement(PsiElement.class) + .withParent(PlatformPatterns.psiElement(ParameterList.class) + .withParent(PlatformPatterns.psiElement(MethodReference.class))); + } +} diff --git a/src/com/yii2support/views/PsiReferenceProvider.java b/src/com/yii2support/views/PsiReferenceProvider.java new file mode 100644 index 00000000..7f45aef3 --- /dev/null +++ b/src/com/yii2support/views/PsiReferenceProvider.java @@ -0,0 +1,24 @@ +package com.yii2support.views; + +import com.intellij.psi.PsiElement; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by NVlad on 02.01.2017. + */ +public class PsiReferenceProvider extends com.intellij.psi.PsiReferenceProvider { + @NotNull + @Override + public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) { + List references = new ArrayList<>(); + + PsiReference reference = new PsiReference(psiElement); + references.add(reference); + + return references.toArray(new PsiReference[references.size()]); + } +} diff --git a/src/com/yii2framework/completion/views/ViewLookupElement.java b/src/com/yii2support/views/ViewLookupElement.java similarity index 68% rename from src/com/yii2framework/completion/views/ViewLookupElement.java rename to src/com/yii2support/views/ViewLookupElement.java index 16e945df..64aa161d 100644 --- a/src/com/yii2framework/completion/views/ViewLookupElement.java +++ b/src/com/yii2support/views/ViewLookupElement.java @@ -1,20 +1,21 @@ -package com.yii2framework.completion.views; +package com.yii2support.views; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementPresentation; -import com.intellij.openapi.util.IconLoader; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + /** * Created by NVlad on 28.12.2016. */ public class ViewLookupElement extends LookupElement { private String name; private String tail; - private String prefix; + private Icon icon; - ViewLookupElement(PsiFile psiFile, String searchPrefix) { + ViewLookupElement(PsiFile psiFile) { String filename = psiFile.getName().substring(0, psiFile.getName().lastIndexOf(".")); if (filename.contains(".")) { name = psiFile.getName(); @@ -22,26 +23,20 @@ public class ViewLookupElement extends LookupElement { name = filename; tail = psiFile.getName().substring(filename.length()); } - prefix = searchPrefix; - if (searchPrefix.startsWith("/")) { - prefix = prefix.substring(1); - } - if (prefix.length() > 0 && !prefix.endsWith("/")) { - prefix = prefix.concat("/"); - } + icon = psiFile.getIcon(0); } @NotNull @Override public String getLookupString() { - return prefix.concat(name); + return name; } @Override public void renderElement(LookupElementPresentation presentation) { super.renderElement(presentation); - presentation.setIcon(IconLoader.getIcon("/icons/view.png")); + presentation.setIcon(icon); presentation.setItemText(name); presentation.setItemTextBold(true); if (tail != null) {