├── .gitignore ├── 1c-bitrix.png ├── LICENSE.txt ├── README.md ├── bitrix.jar ├── resources └── META-INF │ └── plugin.xml └── src └── pro └── opcode └── bitrix ├── BitrixFramework.java ├── BxReference.java ├── BxReferenceContributors.java ├── BxReferencePatterns.java ├── actions ├── BxNewFileAction.java └── BxNewSectionAction.java ├── api ├── BxComponent.java └── BxCore.java ├── completions ├── BxComponentCompletion.java └── BxComponentTemplateCompletion.java ├── references ├── BxApplicationIncludeFileReference.java ├── BxComponentIncludeReference.java ├── BxComponentReference.java ├── BxComponentTemplateReference.java ├── BxPathReference.java └── BxTemplateReference.java ├── resources ├── fileTemplates │ ├── bxSimplePage.php.ft │ ├── bxSimplePageModern.php.ft │ ├── bxSimpleSectionConfig.php.ft │ ├── bxSimpleSectionIndex.php.ft │ └── bxSimpleService.php.ft ├── icon.bx.png └── icon.bx@2x.png └── types └── BxSuperglobalsProvider.java /.gitignore: -------------------------------------------------------------------------------- 1 | /samples 2 | /.idea 3 | /*.iml 4 | /out 5 | bxfs.old.versions 6 | -------------------------------------------------------------------------------- /1c-bitrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vizh/bxfs/c1596d8d8b3bfb4757365c95aca3f2056b898a41/1c-bitrix.png -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Maksim Makhiuk (star.absorber@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bitrix Framework Support # 2 | 3 | Bitrix is popular in the former Soviet Union region, so there is no much sense to me and you to communicate in a foreign language. But you can feel free to write me in English anyway. 4 | 5 | ### Функционал: ### 6 | 7 | * Поддержка папок bitrix и local. 8 | * Переход на файл компонента, шаблона компонента (поддерживаются Twig и Smarty), шаблона сайта а так же на директории и файлы, найденные в строковых переменных. 9 | * Переход на файл включаемой области при клике в вызове на значение ключа 'AREA_FILE_SUFFIX'. 10 | * Корректное определение типов и автокомплит для [специальных переменных](http://dev.1c-bitrix.ru/api_help/main/general/magic_vars.php) и [переменных шаблона](http://dev.1c-bitrix.ru/learning/course/?COURSE_ID=43&LESSON_ID=2829#variables). 11 | * Автокомплит компонента и его шаблона в процессе набора $APPLICATION→IncludeComponent(...) и CBitrixComponent::includeComponentClass(...) 12 | * Решена проблема с подсветкой bitrix как неразрешённого пути в вызовах require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php"); и похожих конструкциях. 13 | * Безопасный рефакторинг файлов с автоматическим обновлением их вызовов в строковых переменных. 14 | * Поиск использований, например файла some.css, в вызовах $APPLICATION→SetAdditionalCSS('...some.css'), во всех файлах проекта. 15 | * Шаблоны создания типовых страниц и разделов сайта. 16 | 17 | [Демо-видео](http://www.youtube.com/watch?v=37w7U65nVRU) 18 | 19 | Пожелания и сообщения об ошибках можете отправлять на почту или оставлять в Кабинете. Там же можете [посмотреть планы](http://redmine.vizh.ru/projects/proj060/roadmap) по развитию. 20 | 21 | ### История версий ### 22 | 23 | **0.1.8** 24 | * Исправлена ошибка Short name 'PhpIncludeInspection' is not unique для новой версии PhpStorm 25 | 26 | **0.1.7** 27 | * Исправление ошибок. 28 | 29 | **0.1.6** 30 | * Автокомплит следующим суперглобальным переменным в .parameters.php: $componentName, $templateProperties, $arCurrentValues, $arComponentParameters и $componentPath; 31 | * Автокомплит следующим суперглобальным переменным в component.php: $componentName, $componentTemplate, $parentComponentName, $parentComponentPath и $parentComponentTemplate. 32 | 33 | **0.1.5** 34 | * Автокомплит компонента, его шаблона и переход к ним в вызове CBitrixComponent::includeComponentClass(...). 35 | 36 | **0.1.4** 37 | * Несколько типовых шаблонов в диалоге создания страницы. 38 | 39 | **0.1.3** 40 | * Доступность переменных $arResult, $arParams, $componentPath и подобных им в файлах result_modifier.php. 41 | 42 | **0.1.2** 43 | * Создание типового раздела Битрикс сайта. 44 | 45 | **0.1.1** 46 | * Особая обработка путей в вызовах $APPLICATION→IncludeFile() в [соответствии с документацией Битрикс](http://dev.1c-bitrix.ru/api_help/main/reference/cmain/includefile.php); 47 | * Создание типовой страницы Битрикс сайта. 48 | 49 | **0.1** 50 | * Ошибка определения ссылок на файлы в строках с конкатенацией; 51 | * Автокомплит шаблона компонента в процессе набора $APPLICATION→IncludeComponent("bitrix:component", ...) 52 | 53 | **0.0.9** 54 | * Переход к коду компонента в class.php, если он есть и к component.php в противном случае; 55 | * Поддержка нестандартных расширений для шаблонов компонентов: template.twig, template.tpl; 56 | * Исправлена ошибка: BxPathReference has unsatisfied dependency. 57 | 58 | **0.0.8** 59 | * Переход на файлы header.php и footer.php шаблонов сайта; 60 | * При поиске шаблонов компонента был опущен третий шаг [алгоритма поиска шаблона компонента](http://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&LESSON_ID=2829#template_search). 61 | 62 | **0.0.7** 63 | * Корректное определение файлов в строках с конкатенацией, например в 'ind'.'ex.c'.'ss' или $APPLICATION→SetAdditionalCSS($APPLICATION→GetCurDir().'/some.css'); 64 | * Доступность переменных $arResult, $arParams и $componentPath в файлах component.php; 65 | * Поддержка PhpStorm. 66 | 67 | **0.0.6** 68 | * Решена проблема с подсветкой bitrix в вызовах require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include.php"); 69 | * Поддержка безопасного удаления файлов с предупреждением о их использованиях в вызовах, например $APPLICATION→SetAdditionalCSS('/some.css'); 70 | * Поддержка переименования и перемещения файлов с автоматическим обновлением их вызовов, например $APPLICATION→SetAdditionalCSS('/some.css'); 71 | * Поиск использований, например файла some.css, в вызовах $APPLICATION→SetAdditionalCSS('...some.css'), во всех файлах проекта; 72 | * Вышеперечисленную "магию" лучше посмотреть [наглядно](http://www.youtube.com/watch?v=37w7U65nVRU). В целом, тема интересная и есть куда развивать: автокомплит, например, создание отсутствующего файла и т.п. 73 | 74 | **0.0.5** 75 | * Решена проблема с подсветкой bitrix в вызовах require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php"); 76 | * Автокомплит переменных, доступных в шаблоне компонента. Это $arResult, $arParams, $componentPath и другие, [описанные тут](http://dev.1c-bitrix.ru/learning/course/?COURSE_ID=43&LESSON_ID=2829#variables). 77 | 78 | **0.0.4** 79 | * Автокомплит компонента в процессе набора $APPLICATION→IncludeComponent(...) 80 | 81 | **0.0.3** 82 | * Переход на директории и файлы, найденные в строковых переменных. 83 | 84 | **0.0.2** 85 | * Корректное определение типов и автокомплит для [специальных переменных](http://dev.1c-bitrix.ru/api_help/main/general/magic_vars.php) $APPLICATION, $USER и $DB. 86 | 87 | **0.0.1** 88 | * Переход на шаблон компонента, расположенный внутри (bitrix|local)/templates/... 89 | * Переход на файл включаемой области при клике в вызове на значение ключа 'AREA_FILE_SUFFIX'; 90 | * Поддержка папок bitrix и local. 91 | 92 | -------------------------------------------------------------------------------- /bitrix.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vizh/bxfs/c1596d8d8b3bfb4757365c95aca3f2056b898a41/bitrix.jar -------------------------------------------------------------------------------- /resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | pro.opcode.bitrix 3 | Bitrix Framework Support 4 | 0.1.9 5 | opCode 6 | 7 | Bitrix is popular in the former Soviet Union region, so there is no much sense to me and you to communicate in a foreign language. But you can feel free to write me in English anyway.

9 |

Функционал:

10 | 21 |

Демо-видео

22 |

Пожелания и сообщения об ошибках можете отправлять на почту или оставлять в Кабинете. Там же можете посмотреть планы по развитию.

23 | ]]>
24 | 25 | 0.1.9

30 |

0.1.7

33 |

0.1.6

37 |

0.1.5

40 |

0.1.4

43 |

0.1.3

46 |

0.1.2

49 |

0.1.1

53 |

0.1

57 |

0.0.9

62 |

0.0.8

66 |

0.0.7

71 |

0.0.6

78 |

0.0.5

82 |

0.0.4

85 |

0.0.3

88 |

0.0.2

91 |

0.0.1

96 | ]]>
97 | 98 | 99 | com.intellij.modules.lang 100 | com.jetbrains.php 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | pro.opcode.bitrix.BitrixFramework 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
-------------------------------------------------------------------------------- /src/pro/opcode/bitrix/BitrixFramework.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix; 2 | 3 | import com.intellij.ProjectTopics; 4 | import com.intellij.ide.fileTemplates.FileTemplate; 5 | import com.intellij.ide.fileTemplates.FileTemplateManager; 6 | import com.intellij.openapi.components.ProjectComponent; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.roots.ModuleRootEvent; 9 | import com.intellij.openapi.roots.ModuleRootListener; 10 | import com.intellij.openapi.util.IconLoader; 11 | import com.intellij.util.ResourceUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import javax.swing.*; 15 | import java.io.IOException; 16 | import java.util.HashMap; 17 | import java.util.Optional; 18 | 19 | public class BitrixFramework implements ProjectComponent, ModuleRootListener { 20 | public static final Icon bxIcon; 21 | 22 | private final Project project; 23 | // public static VirtualFile[] projectSourceRoots = new VirtualFile[]{}; 24 | // public static VirtualFile[] projectResourceRoots = new VirtualFile[]{}; 25 | private static final HashMap templates = new HashMap<>(); 26 | 27 | static { 28 | bxIcon = IconLoader.getIcon("/pro/opcode/bitrix/resources/icon.bx.png"); 29 | 30 | templates.put("Битрикс - Страница", "bxSimplePage"); 31 | templates.put("Битрикс - Страница (модерн)", "bxSimplePageModern"); 32 | templates.put("Битрикс - Сервис", "bxSimpleService"); 33 | templates.put("Битрикс - Раздел (настройки)", "bxSimpleSectionConfig"); 34 | templates.put("Битрикс - Раздел (титульная)", "bxSimpleSectionIndex"); 35 | } 36 | 37 | public BitrixFramework(@NotNull Project project) { 38 | this.project = project; 39 | } 40 | 41 | @Override 42 | public void projectOpened() { 43 | // projectSourceRoots = ProjectRootManager.getInstance(project).getContentSourceRoots(); 44 | // for (VirtualFile resourceRoot : WebResourcesPathsConfiguration.getInstance(project).getResourceDirectories()) { 45 | // projectResourceRoots = Arrays.copyOf(projectResourceRoots, projectResourceRoots.length + 1); 46 | // projectResourceRoots[projectResourceRoots.length - 1] = resourceRoot; 47 | // } 48 | project.getMessageBus().connect(project).subscribe(ProjectTopics.PROJECT_ROOTS, this); 49 | 50 | /* Шаблоны страниц */ 51 | FileTemplateManager templateManager = FileTemplateManager.getInstance(project); 52 | 53 | for (String templateName : templates.keySet()) { 54 | if (null == templateManager.findInternalTemplate(templateName)) { 55 | Optional content = getResourceFileContent( 56 | "fileTemplates/" + templates.get(templateName) + ".php.ft"); 57 | 58 | if (content.isPresent()) { 59 | FileTemplate template 60 | = templateManager.addTemplate(templateName, "php"); 61 | 62 | template.setText(content.get()); 63 | template.setReformatCode(true); 64 | } 65 | } 66 | } 67 | } 68 | 69 | @Override 70 | public void projectClosed() { 71 | } 72 | 73 | @Override 74 | public void initComponent() { 75 | } 76 | 77 | @Override 78 | public void disposeComponent() { 79 | } 80 | 81 | @NotNull 82 | @Override 83 | public String getComponentName() { 84 | return "BitrixFramework"; 85 | } 86 | 87 | @Override 88 | public void beforeRootsChange(ModuleRootEvent moduleRootEvent) { 89 | } 90 | 91 | @Override 92 | public void rootsChanged(ModuleRootEvent moduleRootEvent) { 93 | // projectSourceRoots = ProjectRootManager.getInstance(project).getContentSourceRoots(); 94 | // projectResourceRoots = new VirtualFile[0]; 95 | // for (VirtualFile resourceRoot : WebResourcesPathsConfiguration.getInstance(project).getResourceDirectories()) { 96 | // projectResourceRoots = Arrays.copyOf(projectResourceRoots, projectResourceRoots.length + 1); 97 | // projectResourceRoots[projectResourceRoots.length - 1] = resourceRoot; 98 | // } 99 | } 100 | 101 | @NotNull 102 | private Optional getResourceFileContent(@NotNull String resourceFilePath) { 103 | try { 104 | return Optional.of(ResourceUtil.loadText(BitrixFramework.class.getResource( 105 | "/pro/opcode/bitrix/resources/" + resourceFilePath 106 | ))); 107 | } 108 | catch (IOException e) { 109 | return Optional.empty(); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/BxReference.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix; 2 | 3 | import com.intellij.openapi.util.TextRange; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiReference; 6 | import com.intellij.util.IncorrectOperationException; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | public abstract class BxReference implements PsiReference 11 | { 12 | private PsiElement element; 13 | 14 | public BxReference(PsiElement element) { 15 | this.element = element; 16 | } 17 | 18 | @Override 19 | public PsiElement getElement() { 20 | return element; 21 | } 22 | 23 | @Override 24 | public TextRange getRangeInElement() { 25 | return new TextRange(1, getCanonicalText().length() - 1); 26 | } 27 | 28 | @Nullable 29 | @Override 30 | public abstract PsiElement resolve(); 31 | 32 | @NotNull 33 | @Override 34 | public String getCanonicalText() { 35 | return element.getText(); 36 | } 37 | 38 | @Override 39 | public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { 40 | return null; 41 | } 42 | 43 | @Override 44 | public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { 45 | return resolve(); 46 | } 47 | 48 | @Override 49 | public boolean isReferenceTo(PsiElement element) { 50 | PsiElement resolvedElement = resolve(); 51 | return resolvedElement != null 52 | && resolvedElement.equals(element); 53 | } 54 | 55 | @NotNull 56 | @Override 57 | public Object[] getVariants() { 58 | return EMPTY_ARRAY; 59 | } 60 | 61 | @Override 62 | public boolean isSoft() { 63 | return false; 64 | } 65 | 66 | public PsiReference[] getReference() { 67 | return resolve() == null ? EMPTY_ARRAY : new PsiReference[]{this}; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/BxReferenceContributors.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix; 2 | 3 | import com.intellij.psi.*; 4 | import com.intellij.util.ProcessingContext; 5 | import org.jetbrains.annotations.NotNull; 6 | import pro.opcode.bitrix.references.*; 7 | 8 | public class BxReferenceContributors extends PsiReferenceContributor 9 | { @Override 10 | public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { 11 | // provider for component name of $APPLICATION->IncludeComponent() call 12 | registrar.registerReferenceProvider(BxReferencePatterns.bxComponentReference(), new PsiReferenceProvider() { 13 | @NotNull @Override 14 | public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { 15 | return new BxComponentReference(element).getReference(); 16 | }}); 17 | 18 | // provider for component template name of $APPLICATION->IncludeComponent() call 19 | registrar.registerReferenceProvider(BxReferencePatterns.bxComponentTemplateReference(), new PsiReferenceProvider(){ 20 | @NotNull @Override 21 | public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { 22 | return new BxComponentTemplateReference(element).getReference(); 23 | }}); 24 | 25 | // provider for include file of $APPLICATION->IncludeComponent('bitrix:main.include') call 26 | registrar.registerReferenceProvider(BxReferencePatterns.bxComponentMainIncludeReference(), new PsiReferenceProvider(){ 27 | @NotNull @Override 28 | public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { 29 | return new BxComponentIncludeReference(element).getReference(); 30 | }}); 31 | 32 | /* Обработчик $APPLICATION->IncludeFile() */ 33 | registrar.registerReferenceProvider(BxReferencePatterns.bxApplicationIncludeFileReference(), new PsiReferenceProvider() { 34 | @NotNull @Override 35 | public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext processingContext) { 36 | return new BxApplicationIncludeFileReference(element).getReference(); 37 | } 38 | }); 39 | 40 | /* Образботчик строковых переменных содержащих путь */ 41 | registrar.registerReferenceProvider(BxReferencePatterns.bxPathReference(), new PsiReferenceProvider(){ 42 | @NotNull @Override 43 | public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { 44 | return new BxPathReference(element).getReference(); 45 | }}); 46 | 47 | /* Обработчик подключений bitrix/header.php и bitrix/footer.php */ 48 | registrar.registerReferenceProvider(BxReferencePatterns.bxTemplateReference(), new PsiReferenceProvider(){ 49 | @NotNull @Override 50 | public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { 51 | return new BxTemplateReference(element).getReference(); 52 | }}); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/BxReferencePatterns.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix; 2 | 3 | import com.intellij.patterns.InitialPatternCondition; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiErrorElement; 6 | import com.intellij.psi.impl.source.tree.LeafPsiElement; 7 | import com.intellij.util.ProcessingContext; 8 | import com.jetbrains.php.injection.PhpElementPattern; 9 | import com.jetbrains.php.lang.parser.PhpElementTypes; 10 | import com.jetbrains.php.lang.psi.elements.*; 11 | import org.jetbrains.annotations.Nullable; 12 | import pro.opcode.bitrix.api.BxCore; 13 | import pro.opcode.bitrix.references.BxTemplateReference; 14 | 15 | public class BxReferencePatterns 16 | { 17 | /** 18 | * Capturing first parameter of $APPLICATION->IncludeComponent() call 19 | */ 20 | public static PhpElementPattern.Capture bxComponentReference() { 21 | return new PhpElementPattern.Capture(new InitialPatternCondition(StringLiteralExpression.class) { 22 | @Override 23 | public boolean accepts(@Nullable Object o, ProcessingContext context) { 24 | assert o != null && (o instanceof StringLiteralExpression || o instanceof LeafPsiElement); 25 | /* LeafPsiElement - это недописанный элемент, которому необходим автокомплит. Сам элемент - его предок. */ 26 | return !(o instanceof LeafPsiElement && !((o = ((LeafPsiElement) o).getParent()) instanceof StringLiteralExpression)) 27 | && isValidComponentCall(o) 28 | && isParameterDepth(o, 1); 29 | 30 | } 31 | }); 32 | } 33 | 34 | /** 35 | * Capturing second parameter of $APPLICATION->IncludeComponent() call 36 | */ 37 | public static PhpElementPattern.Capture bxComponentTemplateReference() { 38 | return new PhpElementPattern.Capture(new InitialPatternCondition(StringLiteralExpression.class) { 39 | @Override 40 | public boolean accepts(@Nullable Object o, ProcessingContext context) { 41 | /* LeafPsiElement - это недописанный элемент, которому необходим автокомплит. Сам элемент - его предок. */ 42 | return !(o instanceof LeafPsiElement && !((o = ((LeafPsiElement) o).getParent()) instanceof StringLiteralExpression)) 43 | && isValidComponentCall(o) 44 | && isParameterDepth(o, 2); 45 | } 46 | }); 47 | } 48 | 49 | /** 50 | * Capture of usage some includes 51 | */ 52 | public static PhpElementPattern.Capture bxComponentMainIncludeReference() { 53 | return new PhpElementPattern.Capture(new InitialPatternCondition(StringLiteralExpression.class) { 54 | @Override 55 | public boolean accepts(@Nullable Object o, ProcessingContext context) { 56 | assert o != null && o instanceof StringLiteralExpression; 57 | /* Filter for non array value elements */ 58 | PhpPsiElement arValue = (PhpPsiElement) ((PhpPsiElement) o).getParent(); if (arValue.getNode().getElementType() != PhpElementTypes.ARRAY_VALUE) { 59 | // System.out.println("Текущий элемент не является значением массива"); 60 | return false; 61 | } 62 | 63 | /* Элемент должен быть значением ассоциативного массива */ 64 | PhpPsiElement arElement = (PhpPsiElement) arValue.getParent(); if (arElement.getNode().getElementType() != PhpElementTypes.HASH_ARRAY_ELEMENT) { 65 | // System.out.println("Текущий элемент не является значением ассоциативного массива"); 66 | return false; 67 | } 68 | 69 | /* Элемент должен быть значением строкового ключа AREA_FILE_SUFFIX ассоциативного массива */ 70 | PhpPsiElement arKey = ((ArrayHashElement)arElement).getKey(); if (arKey == null || arKey.getNode().getElementType() != PhpElementTypes.STRING || !((StringLiteralExpression) arKey).getContents().equals("AREA_FILE_SUFFIX")) { 71 | // System.out.println("Текущий элемент не является значением строкового ключа AREA_FILE_SUFFIX ассоциативного массива"); 72 | return false; 73 | } 74 | 75 | /* Элемент должен быть значением ключа массива, который является параметров вызова $APPLICATION->IncludeComponent('bitrix:main.include') */ 76 | return isValidComponentCall(arKey.getParent().getParent().getParent(), "bitrix:main.include"); 77 | 78 | } 79 | }); 80 | } 81 | 82 | public static PhpElementPattern.Capture bxApplicationIncludeFileReference() { 83 | return new PhpElementPattern.Capture(new InitialPatternCondition(StringLiteralExpression.class) { 84 | @Override 85 | public boolean accepts(@Nullable Object o, ProcessingContext context) { 86 | assert o != null && (o instanceof StringLiteralExpression || o instanceof LeafPsiElement); 87 | /* LeafPsiElement - это недописанный элемент, которому необходим автокомплит. Сам элемент - его предок. */ 88 | return !(o instanceof LeafPsiElement && !((o = ((LeafPsiElement) o).getParent()) instanceof StringLiteralExpression)) 89 | && isValidApplicationIncludeFileCall(o); 90 | 91 | } 92 | }); 93 | } 94 | 95 | /** 96 | * Захват строк, содержащих пути к файлам / папкам 97 | */ 98 | public static PhpElementPattern.Capture bxPathReference() { 99 | return new PhpElementPattern.Capture(new InitialPatternCondition(StringLiteralExpression.class) { 100 | @Override 101 | public boolean accepts(@Nullable Object o, ProcessingContext context) { 102 | assert o != null && (o instanceof StringLiteralExpression || o instanceof LeafPsiElement); 103 | /* LeafPsiElement - это недописанный элемент, которому необходим автокомплит. Сам элемент - его предок. */ 104 | return !(o instanceof LeafPsiElement && !((o = ((LeafPsiElement) o).getParent()) instanceof StringLiteralExpression)) 105 | && !isValidApplicationIncludeFileCall(o) 106 | && BxCore.isFilenameValid(((StringLiteralExpression) o).getContents()); 107 | 108 | } 109 | }); 110 | } 111 | 112 | /** 113 | * Захват подключения bitrix/header.php и bitrix/footer.php 114 | */ 115 | public static PhpElementPattern.Capture bxTemplateReference() { 116 | return new PhpElementPattern.Capture(new InitialPatternCondition(StringLiteralExpression.class) { 117 | @Override 118 | public boolean accepts(@Nullable Object o, ProcessingContext context) { 119 | assert o != null && o instanceof StringLiteralExpression; 120 | return BxTemplateReference.bxTemplateReferenceTargets.containsKey(((StringLiteralExpression) o).getContents()); 121 | } 122 | }); 123 | } 124 | 125 | /** 126 | * Is the element is a parameter of $APPLICATION->IncludeComponent() call 127 | */ 128 | private static boolean isValidApplicationIncludeFileCall(Object o) { 129 | PsiElement parameters = ((PsiElement) o).getParent(); if (parameters instanceof ParameterList) { 130 | PsiElement method = parameters.getParent(); if (method instanceof MethodReference) { 131 | PsiElement clazz = ((MethodReference) method).getClassReference(); if (clazz instanceof Variable) { 132 | return !((MethodReference) method).isStatic() 133 | && "APPLICATION".equals(((Variable) clazz).getName()) 134 | && "IncludeFile".equals(((MethodReference) method).getName()); 135 | } 136 | } 137 | } 138 | return false; 139 | } 140 | 141 | /** 142 | * Is the element is a parameter of $APPLICATION->IncludeComponent() call 143 | */ 144 | private static boolean isValidComponentCall(Object o, String component) { 145 | PsiElement parameters = ((PsiElement) o).getParent(); if (parameters instanceof ParameterList) { 146 | if (component != null) { 147 | PsiElement[] params = ((ParameterList) parameters).getParameters(); if (params.length == 0 || params[0].getNode().getElementType() != PhpElementTypes.STRING || !((StringLiteralExpression) params[0]).getContents().equals(component)) 148 | return false; 149 | } 150 | PsiElement psiMethod = parameters.getParent(); if (psiMethod instanceof MethodReference) { 151 | MethodReference method = (MethodReference) psiMethod; 152 | /* CBitrixComponent::includeComponentClass() */ 153 | if (method.getClassReference() instanceof ClassReference && method.isStatic()) 154 | return "CBitrixComponent".equals(method.getClassReference().getName()) 155 | && "includeComponentClass".equals(method.getName()); 156 | /* $APPLICATION->IncludeComponent() */ 157 | if (method.getClassReference() instanceof Variable && !method.isStatic()) 158 | return "APPLICATION".equals(method.getClassReference().getName()) 159 | && "IncludeComponent".equals(method.getName()); 160 | } 161 | } 162 | return false; 163 | } 164 | 165 | private static boolean isValidComponentCall(Object o) { 166 | return isValidComponentCall(o, null); 167 | } 168 | 169 | /** 170 | * Is the element have expected position in method parameters list 171 | * and all previous parameters is valid 172 | */ 173 | private static boolean isParameterDepth(Object o, int depth) { 174 | PsiElement[] parameters = ((ParameterList) ((PsiElement) o).getParent()).getParameters(); 175 | /* Если параметров меньше, чем необходимо - облом */ 176 | if (parameters.length < depth) 177 | return false; 178 | /* Все предыдущие параметры должны быть корректными */ 179 | if (depth > 1) for (int i = 0; i < depth; i++) { 180 | if (parameters[i] instanceof PsiErrorElement) 181 | return false; 182 | } 183 | /* Проверяем, что указанный параметр имеет правильную глубину вложенности */ 184 | return parameters[depth - 1].equals(o); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/actions/BxNewFileAction.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.actions; 2 | 3 | import com.intellij.ide.actions.CreateFileFromTemplateAction; 4 | import com.intellij.ide.actions.CreateFileFromTemplateDialog; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.PsiDirectory; 7 | import pro.opcode.bitrix.BitrixFramework; 8 | 9 | public class BxNewFileAction extends CreateFileFromTemplateAction 10 | { 11 | public BxNewFileAction() { 12 | super("Страница", "Битрикс: Создание новой страницы", BitrixFramework.bxIcon); 13 | } 14 | 15 | @Override 16 | protected void buildDialog(Project project, PsiDirectory psiDirectory, CreateFileFromTemplateDialog.Builder builder) { 17 | builder.setTitle("Битрикс: Новая страница") 18 | .addKind("Страница", BitrixFramework.bxIcon, "Битрикс - Страница") 19 | .addKind("Страница (модерн)", BitrixFramework.bxIcon, "Битрикс - Страница (модерн)") 20 | .addKind("Сервис", BitrixFramework.bxIcon, "Битрикс - Сервис"); 21 | } 22 | 23 | @Override 24 | protected String getActionName(PsiDirectory psiDirectory, String s, String s1) { 25 | return "Битрикс: Новая страница"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/actions/BxNewSectionAction.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.actions; 2 | 3 | import com.intellij.ide.IdeView; 4 | import com.intellij.ide.actions.CreateDirectoryOrPackageHandler; 5 | import com.intellij.ide.fileTemplates.FileTemplate; 6 | import com.intellij.ide.fileTemplates.FileTemplateManager; 7 | import com.intellij.ide.fileTemplates.FileTemplateUtil; 8 | import com.intellij.ide.util.DirectoryChooserUtil; 9 | import com.intellij.openapi.actionSystem.AnAction; 10 | import com.intellij.openapi.actionSystem.AnActionEvent; 11 | import com.intellij.openapi.actionSystem.LangDataKeys; 12 | import com.intellij.openapi.project.DumbAware; 13 | import com.intellij.openapi.project.Project; 14 | import com.intellij.openapi.ui.Messages; 15 | import com.intellij.psi.PsiDirectory; 16 | import com.intellij.psi.PsiElement; 17 | import org.jetbrains.annotations.NotNull; 18 | import pro.opcode.bitrix.BitrixFramework; 19 | 20 | import java.util.Properties; 21 | 22 | public class BxNewSectionAction extends AnAction implements DumbAware 23 | { 24 | public BxNewSectionAction() { 25 | super("Раздел", "Битрикс: Создание нового раздела", BitrixFramework.bxIcon); 26 | } 27 | 28 | @Override 29 | public void actionPerformed(@NotNull AnActionEvent event) { 30 | IdeView view 31 | = event.getData(LangDataKeys.IDE_VIEW); 32 | 33 | if (view != null) { 34 | Project project 35 | = event.getProject(); 36 | 37 | if (project != null) { 38 | PsiDirectory directory 39 | = DirectoryChooserUtil.getOrChooseDirectory(view); 40 | 41 | if (directory != null) { 42 | CreateDirectoryOrPackageHandler validator 43 | = new CreateDirectoryOrPackageHandler(project, directory, true, "\\/"); 44 | 45 | // Сообщение не нужно, так как заголовок окна и так близко. Они резонируют. 46 | Messages.showInputDialog(project, null, "Битрикс: Создание Нового Раздела", BitrixFramework.bxIcon, "", validator); 47 | 48 | PsiElement result = validator.getCreatedElement(); 49 | if (result instanceof PsiDirectory) { 50 | PsiDirectory createdDir = (PsiDirectory) result; 51 | 52 | FileTemplateManager templateManager 53 | = FileTemplateManager.getInstance(project); 54 | 55 | FileTemplate cfgTemplate = templateManager.findInternalTemplate("Битрикс - Раздел (настройки)"); 56 | FileTemplate idxTemplate = templateManager.findInternalTemplate("Битрикс - Раздел (титульная)"); 57 | 58 | Properties properties 59 | = FileTemplateManager.getInstance(project).getDefaultProperties(); 60 | 61 | try { 62 | PsiElement cfgFile = FileTemplateUtil.createFromTemplate(cfgTemplate, ".section", properties, createdDir); 63 | PsiElement idxFile = FileTemplateUtil.createFromTemplate(idxTemplate, "index", properties, createdDir); 64 | 65 | view.selectElement(idxFile); 66 | } 67 | catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | @Override 77 | public boolean isDumbAware() { 78 | return false; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/api/BxComponent.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.api; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import com.intellij.psi.PsiElement; 6 | import com.jetbrains.php.lang.psi.elements.ParameterList; 7 | import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | 13 | public class BxComponent 14 | { 15 | public String vendor; 16 | public String component; 17 | public String template; 18 | 19 | private Project project; 20 | 21 | public BxComponent(PsiElement element) { 22 | project = element.getProject(); 23 | 24 | PsiElement[] parameters = ((ParameterList) element.getParent()) 25 | .getParameters(); 26 | 27 | String[] cmpParts = ((StringLiteralExpression) parameters[0]).getContents().split(":"); 28 | vendor = cmpParts[0].isEmpty() ? null : cmpParts[0]; 29 | component = cmpParts.length > 1 ? cmpParts[1] : null; 30 | 31 | if (parameters.length > 1 && parameters[1] instanceof StringLiteralExpression) { 32 | template = ((StringLiteralExpression) parameters[1]).getContents(); if (template.isEmpty()) 33 | template = ".default"; 34 | } 35 | } 36 | 37 | public VirtualFile getComponentFile(String path) { 38 | return BxCore.findFile(project.getBaseDir(), "/{local,bitrix}/components/%s/%s/%s", vendor, component, path); 39 | } 40 | 41 | public VirtualFile getComponentTemplateFile(String path) { 42 | if (vendor != null && component != null && template != null) { 43 | for (String search : new String[]{"{local,bitrix}/templates/*/components/%s/%s/%s/%s", "{local,bitrix}/components/%s/%s/templates/%s/%s"}) { 44 | VirtualFile founded = BxCore.findFile(project.getBaseDir(), search, vendor, component, template, path); if (founded != null) 45 | return founded; 46 | } 47 | } 48 | return null; 49 | } 50 | 51 | public VirtualFile[] getPossibleTemplates() { 52 | List foundedTemplates = new ArrayList(); 53 | 54 | if (vendor != null && component != null) { 55 | for (String search : new String[]{"{local,bitrix}/templates/*/components/%s/%s/*", "{local,bitrix}/components/%s/%s/templates/*"}) { 56 | VirtualFile[] templates = BxCore.findFiles(project.getBaseDir(), search, vendor, component); if (templates != null) 57 | foundedTemplates.addAll(Arrays.asList(templates)); 58 | } 59 | } 60 | 61 | return foundedTemplates.toArray(new VirtualFile[foundedTemplates.size()]); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/api/BxCore.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.api; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import com.intellij.psi.PsiDirectory; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiFile; 8 | import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | public class BxCore 17 | { 18 | private Project project; 19 | private static final String[] BitrixPaths = {"local", "bitrix"}; 20 | 21 | public BxCore(Project project) { 22 | this.project = project; 23 | } 24 | 25 | @Nullable 26 | public static BxComponent getComponent(PsiElement element) { 27 | return element instanceof StringLiteralExpression 28 | ? new BxComponent(element) 29 | : null; 30 | } 31 | 32 | /* Проверяет, есть ли в текущем проекте папка (bitrix|local)/components/bitrix */ 33 | public boolean isComponentsFolderExists() { 34 | for (String bitrixPath : BitrixPaths) { 35 | VirtualFile componentsDir = project.getBaseDir().findFileByRelativePath(bitrixPath + "/components/bitrix"); 36 | if (componentsDir != null && componentsDir.isDirectory() && componentsDir.exists()) 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | /* Возвращает список всех доступных шаблонов сайтов */ 43 | public VirtualFile[] getSiteTemplates() { 44 | List templates = new ArrayList(); 45 | for (String bitrixPath : BitrixPaths) { 46 | VirtualFile templatesDir = project.getBaseDir().findChild("templates"); if (templatesDir != null && templatesDir.isDirectory()) { 47 | for (VirtualFile templateDir : templatesDir.getChildren()) if (templateDir != null && templateDir.isDirectory()) { 48 | VirtualFile templateComponent; 49 | if ((templateComponent = templateDir.findChild("header.php")) != null && !templateComponent.isDirectory() && templateComponent.isValid() 50 | && (templateComponent = templateDir.findChild("footer.php")) != null && !templateComponent.isDirectory() && templateComponent.isValid()) 51 | templates.add(templateDir); 52 | } 53 | } 54 | } 55 | return templates.toArray(new VirtualFile[templates.size()]); 56 | } 57 | 58 | /* Возвращает список указанных компонентов всех доступных шаблонов сайтов, где они есть */ 59 | public VirtualFile[] getSiteTemplatesComponents(String templateComponent) { 60 | List templates = new ArrayList(); 61 | for (String bitrixPath : BitrixPaths) { 62 | VirtualFile templatesDir = project.getBaseDir().findFileByRelativePath(bitrixPath + "/templates"); if (templatesDir != null && templatesDir.isDirectory()) { 63 | for (VirtualFile templateDir : templatesDir.getChildren()) if (templateDir != null && templateDir.isDirectory()) { 64 | VirtualFile component = templateDir.findChild(templateComponent); if (component != null && !component.isDirectory() && component.isValid()) 65 | templates.add(component); 66 | } 67 | } 68 | } 69 | return templates.toArray(new VirtualFile[templates.size()]); 70 | } 71 | 72 | /* Возвращает список всех доступных компонентов */ 73 | public VirtualFile[] getComponents() { 74 | List components = new ArrayList(); 75 | for (String bitrixPath : BitrixPaths) { 76 | VirtualFile vendorsDir = project.getBaseDir().findFileByRelativePath(bitrixPath + "/components"); if (vendorsDir != null && vendorsDir.isDirectory()) { 77 | for (VirtualFile componentsDir : vendorsDir.getChildren()) if (componentsDir != null && componentsDir.isDirectory()) { 78 | Collections.addAll(components, componentsDir.getChildren()); 79 | } 80 | } 81 | } 82 | return components.toArray(new VirtualFile[components.size()]); 83 | } 84 | 85 | public VirtualFile[] getComponentVendors() { 86 | List vendors = new ArrayList(); 87 | for (String bitrixPath : BitrixPaths) { 88 | VirtualFile vendorsDir = project.getBaseDir().findFileByRelativePath(bitrixPath + "/components"); if (vendorsDir != null && vendorsDir.isDirectory()) { 89 | Collections.addAll(vendors, vendorsDir.getChildren()); 90 | } 91 | } 92 | return vendors.toArray(new VirtualFile[vendors.size()]); 93 | } 94 | 95 | public VirtualFile getPageIncludeFile(PsiElement element, String suffix) { 96 | 97 | assert element != null 98 | && element.getContainingFile() != null 99 | && element.getContainingFile().getParent() != null; 100 | 101 | PsiFile founded = getPageIncludeFile( 102 | element.getContainingFile().getParent(), 103 | ((StringLiteralExpression) element).getContents(), 104 | suffix 105 | ); 106 | 107 | return founded == null ? null : founded.getVirtualFile(); 108 | } 109 | 110 | public static boolean isFilenameValid(String fileName) { 111 | return fileName.matches("^[/^\\-_.A-Za-z0-9]+$"); 112 | /* Лучший, но более медленный вариант: 113 | try { 114 | new File(fileName).getCanonicalPath(); 115 | return true; 116 | } catch (IOException e) { 117 | return false; 118 | } 119 | */ 120 | } 121 | 122 | @Nullable 123 | public static VirtualFile findFile(VirtualFile baseDir, String path, String... vars) { 124 | VirtualFile[] files = findFiles(baseDir, path, vars); 125 | return files == null ? null : files[0]; 126 | } 127 | 128 | @Nullable 129 | public static VirtualFile[] findFiles(VirtualFile baseDir, String path, String... vars) { 130 | if (vars.length > 0) 131 | path = String.format(path, vars); 132 | 133 | List result = new ArrayList(); 134 | List buffer = new ArrayList(); 135 | 136 | VirtualFile child; 137 | 138 | result.add(baseDir); 139 | 140 | for (String pathComponent : path.split("/")) if (!pathComponent.isEmpty()) { 141 | for (VirtualFile parent : result) { 142 | /* Перечисления */ 143 | if (pathComponent.startsWith("{") && pathComponent.endsWith("}")) { 144 | for (String enumeration : pathComponent.substring(1, pathComponent.length() - 1).split(",")) 145 | if ((child = parent.findChild(enumeration)) != null) 146 | buffer.add(child); 147 | continue; 148 | } 149 | /* Любой деть */ 150 | if (pathComponent.equals("*")) { 151 | buffer.addAll(Arrays.asList(parent.getChildren())); 152 | continue; 153 | } 154 | /* Родитель */ 155 | if (pathComponent.equals("..")) { 156 | buffer.add(parent.getParent()); 157 | continue; 158 | } 159 | /* Конкретный деть */ 160 | if ((child = parent.findChild(pathComponent)) != null) { 161 | buffer.add(child); 162 | } 163 | } 164 | result.clear(); result.addAll(buffer); 165 | buffer.clear(); 166 | } 167 | 168 | /* Вместопустых массивов возвращаем null */ 169 | if (result.isEmpty()) 170 | return null; 171 | 172 | /* Если путь оканчивается на /, то проверим что все результаты являются директориями */ 173 | if (path.endsWith("/")) { 174 | for (VirtualFile file : result) { 175 | if (file.isDirectory()) 176 | buffer.add(file); 177 | } 178 | result.clear(); result.addAll(buffer); 179 | buffer.clear(); 180 | } 181 | 182 | return result.toArray(new VirtualFile[result.size()]); 183 | } 184 | 185 | private PsiFile getPageIncludeFile(PsiDirectory directory, String name, String suffix) { 186 | PsiFile file; if ((file = directory.findFile(String.format("%s_%s.php", suffix, name))) == null && suffix.equals("sect") && directory.getParent() != null) 187 | file = getPageIncludeFile(directory.getParent(), name, suffix); 188 | 189 | return file; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/completions/BxComponentCompletion.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.completions; 2 | 3 | import com.intellij.codeInsight.completion.*; 4 | import com.intellij.codeInsight.lookup.LookupElementBuilder; 5 | import com.intellij.openapi.vfs.VirtualFile; 6 | import com.intellij.util.ProcessingContext; 7 | import org.jetbrains.annotations.NotNull; 8 | import pro.opcode.bitrix.BxReferencePatterns; 9 | import pro.opcode.bitrix.api.BxCore; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | public class BxComponentCompletion extends CompletionContributor 15 | { 16 | /* Тут перечислены компоненты для автокомплита в случае, если проект 17 | * не содержит папки с компонентами bitrix */ 18 | private static List bxComponents = Arrays.asList( 19 | "advertising.banner", 20 | "bitrixcloud.mobile.monitoring.detail", 21 | "bitrixcloud.mobile.monitoring.edit", 22 | "bitrixcloud.mobile.monitoring.list", 23 | "bitrixcloud.mobile.monitoring.push", 24 | "bizproc.document", 25 | "bizproc.document.history", 26 | "bizproc.log", 27 | "bizproc.task", 28 | "bizproc.task.list", 29 | "bizproc.wizards", 30 | "bizproc.wizards.index", 31 | "bizproc.wizards.list", 32 | "bizproc.wizards.log", 33 | "bizproc.wizards.new", 34 | "bizproc.wizards.setvar", 35 | "bizproc.wizards.start", 36 | "bizproc.wizards.task", 37 | "bizproc.wizards.view", 38 | "bizproc.workflow.edit", 39 | "bizproc.workflow.info", 40 | "bizproc.workflow.list", 41 | "bizproc.workflow.setvar", 42 | "bizproc.workflow.start", 43 | "blog", 44 | "blog.blog", 45 | "blog.blog.draft", 46 | "blog.blog.edit", 47 | "blog.blog.favorite", 48 | "blog.blog.moderation", 49 | "blog.calendar", 50 | "blog.category", 51 | "blog.commented_posts", 52 | "blog.friends", 53 | "blog.group.blog", 54 | "blog.groups", 55 | "blog.info", 56 | "blog.menu", 57 | "blog.metaweblog", 58 | "blog.new_blogs", 59 | "blog.new_comments", 60 | "blog.new_posts", 61 | "blog.new_posts.list", 62 | "blog.popular_blogs", 63 | "blog.popular_posts", 64 | "blog.post", 65 | "blog.post.comment", 66 | "blog.post.edit", 67 | "blog.post.trackback", 68 | "blog.post.trackback.get", 69 | "blog.rss", 70 | "blog.rss.all", 71 | "blog.rss.link", 72 | "blog.search", 73 | "blog.user", 74 | "blog.user.group", 75 | "blog.user.settings", 76 | "blog.user.settings.edit", 77 | "breadcrumb", 78 | "calendar.events.list", 79 | "calendar.grid", 80 | "calendar.livefeed.edit", 81 | "calendar.livefeed.view", 82 | "catalog", 83 | "catalog.brandblock", 84 | "catalog.comments", 85 | "catalog.compare.list", 86 | "catalog.compare.result", 87 | "catalog.element", 88 | "catalog.filter", 89 | "catalog.link.list", 90 | "catalog.main", 91 | "catalog.search", 92 | "catalog.section", 93 | "catalog.section.list", 94 | "catalog.sections.top", 95 | "catalog.set.constructor", 96 | "catalog.smart.filter", 97 | "catalog.socnets.buttons", 98 | "catalog.tabs", 99 | "catalog.top", 100 | "controller.shared.add", 101 | "controller.site.control", 102 | "controller.site.list", 103 | "currency.rates", 104 | "desktop", 105 | "event_list", 106 | "fileman.light_editor", 107 | "form", 108 | "form.result.edit", 109 | "form.result.list", 110 | "form.result.list.my", 111 | "form.result.new", 112 | "form.result.view", 113 | "forum", 114 | "forum.comments", 115 | "forum.help", 116 | "forum.index", 117 | "forum.interface", 118 | "forum.message.approve", 119 | "forum.message.move", 120 | "forum.message.send", 121 | "forum.message.template", 122 | "forum.pm.edit", 123 | "forum.pm.folder", 124 | "forum.pm.list", 125 | "forum.pm.read", 126 | "forum.pm.search", 127 | "forum.post_form", 128 | "forum.rss", 129 | "forum.rules", 130 | "forum.search", 131 | "forum.statistic", 132 | "forum.subscribe.list", 133 | "forum.topic.active", 134 | "forum.topic.last", 135 | "forum.topic.list", 136 | "forum.topic.move", 137 | "forum.topic.new", 138 | "forum.topic.read", 139 | "forum.topic.reviews", 140 | "forum.topic.search", 141 | "forum.user.list", 142 | "forum.user.post", 143 | "forum.user.profile.edit", 144 | "forum.user.profile.view", 145 | "furniture.catalog.index", 146 | "furniture.catalog.random", 147 | "furniture.vacancies", 148 | "highloadblock.list", 149 | "highloadblock.view", 150 | "iblock.button.element", 151 | "iblock.button.element.add", 152 | "iblock.button.element.search", 153 | "iblock.element.add", 154 | "iblock.element.add.form", 155 | "iblock.element.add.list", 156 | "iblock.tv", 157 | "iblock.vote", 158 | "iblock.wizard", 159 | "idea", 160 | "idea.category.list", 161 | "idea.comment.list", 162 | "idea.detail", 163 | "idea.edit", 164 | "idea.filter", 165 | "idea.list", 166 | "idea.popup", 167 | "idea.rss", 168 | "idea.search", 169 | "idea.statistic", 170 | "idea.subscribe", 171 | "idea.tags", 172 | "im.messenger", 173 | "infoportal.element.add.form", 174 | "learning.chapter.detail", 175 | "learning.course", 176 | "learning.course.contents", 177 | "learning.course.detail", 178 | "learning.course.list", 179 | "learning.course.tree", 180 | "learning.lesson.detail", 181 | "learning.search", 182 | "learning.student.certificates", 183 | "learning.student.gradebook", 184 | "learning.student.profile", 185 | "learning.student.transcript", 186 | "learning.test", 187 | "learning.test.list", 188 | "learning.test.self", 189 | "lists", 190 | "lists.element.edit", 191 | "lists.element.navchain", 192 | "lists.field.edit", 193 | "lists.fields", 194 | "lists.file", 195 | "lists.list", 196 | "lists.list.edit", 197 | "lists.lists", 198 | "lists.menu", 199 | "lists.sections", 200 | "main.calendar", 201 | "main.clock", 202 | "main.colorpicker", 203 | "main.feedback", 204 | "main.file.input", 205 | "main.include", 206 | "main.informer", 207 | "main.interface.filter", 208 | "main.interface.form", 209 | "main.interface.grid", 210 | "main.interface.toolbar", 211 | "main.lookup.input", 212 | "main.map", 213 | "main.post.form", 214 | "main.post.list", 215 | "main.profile", 216 | "main.register", 217 | "main.share", 218 | "main.site.selector", 219 | "main.tree.selector", 220 | "main.user.link", 221 | "map.google.search", 222 | "map.google.system", 223 | "map.google.view", 224 | "map.yandex.search", 225 | "map.yandex.system", 226 | "map.yandex.view", 227 | "menu", 228 | "menu.sections", 229 | "mobileapp.auth", 230 | "mobileapp.edit", 231 | "mobileapp.filter", 232 | "mobileapp.interface.checkboxes", 233 | "mobileapp.interface.radiobuttons", 234 | "mobileapp.interface.topswitchers", 235 | "mobileapp.list", 236 | "mobileapp.list.enclosed", 237 | "mobileapp.menu", 238 | "mobileapp.push", 239 | "news", 240 | "news.calendar", 241 | "news.detail", 242 | "news.index", 243 | "news.line", 244 | "news.list", 245 | "photo", 246 | "photo.detail", 247 | "photogallery", 248 | "photogallery.detail", 249 | "photogallery.detail.comment", 250 | "photogallery.detail.edit", 251 | "photogallery.detail.list", 252 | "photogallery.detail.list.ex", 253 | "photogallery.gallery.edit", 254 | "photogallery.gallery.list", 255 | "photogallery.imagerotator", 256 | "photogallery.interface", 257 | "photogallery.section", 258 | "photogallery.section.edit", 259 | "photogallery.section.edit.icon", 260 | "photogallery.section.list", 261 | "photogallery.upload", 262 | "photogallery_user", 263 | "photogallery.user", 264 | "photo.random", 265 | "photo.section", 266 | "photo.sections.top", 267 | "player", 268 | "pull.request", 269 | "rating.result", 270 | "rating.vote", 271 | "rss.out", 272 | "rss.show", 273 | "search.form", 274 | "search.page", 275 | "search.suggest.input", 276 | "search.tags.cloud", 277 | "search.tags.input", 278 | "search.title", 279 | "socialnetwork", 280 | "socialnetwork.activity", 281 | "socialnetwork.admin.set", 282 | "socialnetwork.bizproc", 283 | "socialnetwork.bizproc_edit", 284 | "socialnetwork.blog.blog", 285 | "socialnetwork.blog.draft", 286 | "socialnetwork.blog.menu", 287 | "socialnetwork.blog.moderation", 288 | "socialnetwork.blog.post", 289 | "socialnetwork.blog.post.comment", 290 | "socialnetwork.blog.post.edit", 291 | "socialnetwork.blog.rss", 292 | "socialnetwork.events", 293 | "socialnetwork.events_dyn", 294 | "socialnetwork.features", 295 | "socialnetwork.forum.post_form", 296 | "socialnetwork.forum.topic.last", 297 | "socialnetwork.forum.topic.list", 298 | "socialnetwork.forum.topic.new", 299 | "socialnetwork.forum.topic.read", 300 | "socialnetwork_group", 301 | "socialnetwork.group", 302 | "socialnetwork.group_ban", 303 | "socialnetwork.group_create", 304 | "socialnetwork.group_create.ex", 305 | "socialnetwork.group_delete", 306 | "socialnetwork.group.iframe.popup", 307 | "socialnetwork.group_list", 308 | "socialnetwork.group_menu", 309 | "socialnetwork.group_mods", 310 | "socialnetwork.group_requests", 311 | "socialnetwork.group_request_search", 312 | "socialnetwork.group_requests.ex", 313 | "socialnetwork.group_requests_out", 314 | "socialnetwork.group_request_user", 315 | "socialnetwork.group_search", 316 | "socialnetwork.group.selector", 317 | "socialnetwork.group_top", 318 | "socialnetwork.group_users", 319 | "socialnetwork.group_users.ex", 320 | "socialnetwork.log.entry", 321 | "socialnetwork.log.ex", 322 | "socialnetwork.log.filter", 323 | "socialnetwork.log.rss", 324 | "socialnetwork.log.rss.link", 325 | "socialnetwork.menu", 326 | "socialnetwork.message_form", 327 | "socialnetwork.messages_chat", 328 | "socialnetwork.messages_input", 329 | "socialnetwork.messages_menu", 330 | "socialnetwork.messages_output", 331 | "socialnetwork.messages_requests", 332 | "socialnetwork.messages_users", 333 | "socialnetwork.messages_users_messages", 334 | "socialnetwork.reindex", 335 | "socialnetwork.subscribe", 336 | "socialnetwork.subscribe_list", 337 | "socialnetwork_user", 338 | "socialnetwork.user_ban", 339 | "socialnetwork.user_birthday", 340 | "socialnetwork.user_friends", 341 | "socialnetwork.user_friends_add", 342 | "socialnetwork.user_friends_delete", 343 | "socialnetwork.user_friends.ex", 344 | "socialnetwork.user_groups", 345 | "socialnetwork.user_groups.link.add", 346 | "socialnetwork.user_groups.search_form", 347 | "socialnetwork.user_leave_group", 348 | "socialnetwork.user_menu", 349 | "socialnetwork.user_profile", 350 | "socialnetwork.user_profile_edit", 351 | "socialnetwork.user_request_group", 352 | "socialnetwork.user_requests.ex", 353 | "socialnetwork.user_search", 354 | "socialnetwork.user_search_input", 355 | "socialnetwork.user_settings_edit", 356 | "socserv.auth.form", 357 | "socserv.auth.split", 358 | "statistic.table", 359 | "subscribe.edit", 360 | "subscribe.form", 361 | "subscribe.index", 362 | "subscribe.news", 363 | "subscribe.simple", 364 | "support.faq", 365 | "support.faq.element.detail", 366 | "support.faq.element.list", 367 | "support.faq.section.list", 368 | "support.ticket", 369 | "support.ticket.edit", 370 | "support.ticket.list", 371 | "support.wizard", 372 | "system.auth.authorize", 373 | "system.auth.changepasswd", 374 | "system.auth.confirmation", 375 | "system.auth.forgotpasswd", 376 | "system.auth.form", 377 | "system.auth.initialize", 378 | "system.auth.registration", 379 | "system.field.edit", 380 | "system.field.view", 381 | "system.pagenavigation", 382 | "system.show_message", 383 | "voting.current", 384 | "voting.form", 385 | "voting.list", 386 | "voting.result", 387 | "voting.vote.edit", 388 | "webservice.checkauth", 389 | "webservice.server", 390 | "webservice.statistic", 391 | "wiki", 392 | "wiki.categories", 393 | "wiki.category", 394 | "wiki.discussion", 395 | "wiki.edit", 396 | "wiki.history", 397 | "wiki.history.diff", 398 | "wiki.menu", 399 | "wiki.show" 400 | ); 401 | 402 | /** 403 | * Построение автокомплита компонента в процессе набора $APPLICATION->IncludeComponent(...) 404 | */ 405 | public BxComponentCompletion() { 406 | extend(CompletionType.BASIC, BxReferencePatterns.bxComponentReference(), new CompletionProvider() { 407 | public void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet resultSet) { 408 | BxCore bitrix = new BxCore(parameters.getPosition().getProject()); 409 | 410 | if (!bitrix.isComponentsFolderExists()) 411 | for (String component : bxComponents) 412 | resultSet.addElement(LookupElementBuilder.create("bitrix:" + component)); 413 | 414 | for (VirtualFile component : bitrix.getComponents()) 415 | resultSet.addElement(LookupElementBuilder.create(String.format("%s:%s", 416 | component.getParent().getName(), 417 | component.getName() 418 | ))); 419 | } 420 | }); 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/completions/BxComponentTemplateCompletion.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.completions; 2 | 3 | import com.intellij.codeInsight.completion.*; 4 | import com.intellij.codeInsight.lookup.LookupElementBuilder; 5 | import com.intellij.openapi.vfs.VirtualFile; 6 | import com.intellij.psi.impl.source.tree.LeafPsiElement; 7 | import com.intellij.util.ProcessingContext; 8 | import org.jetbrains.annotations.NotNull; 9 | import pro.opcode.bitrix.BxReferencePatterns; 10 | import pro.opcode.bitrix.api.BxComponent; 11 | import pro.opcode.bitrix.api.BxCore; 12 | 13 | public class BxComponentTemplateCompletion extends CompletionContributor 14 | { 15 | /** 16 | * Построение автокомплита компонента в процессе набора $APPLICATION->IncludeComponent(...) 17 | */ 18 | public BxComponentTemplateCompletion() { 19 | extend(CompletionType.BASIC, BxReferencePatterns.bxComponentTemplateReference(), new CompletionProvider() { 20 | public void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet resultSet) { 21 | assert parameters.getPosition() instanceof LeafPsiElement; 22 | BxComponent bxComponent = BxCore.getComponent(parameters.getPosition().getParent()); 23 | for (VirtualFile template : bxComponent.getPossibleTemplates()) 24 | resultSet.addElement(LookupElementBuilder.create(template.getName())); 25 | // for (VirtualFile component : bitrix.getComponents()) 26 | // resultSet.addElement(LookupElementBuilder.create(String.format("%s:%s", 27 | // component.getParent().getName(), 28 | // component.getName() 29 | // ))); 30 | } 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/references/BxApplicationIncludeFileReference.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.references; 2 | 3 | import com.intellij.openapi.vfs.VirtualFile; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiReference; 6 | import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | import pro.opcode.bitrix.BxReference; 10 | import pro.opcode.bitrix.api.BxCore; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class BxApplicationIncludeFileReference extends BxReference 16 | { 17 | public BxApplicationIncludeFileReference(PsiElement element) { 18 | super(element); 19 | } 20 | 21 | @Nullable 22 | @Override 23 | public PsiElement resolve() { 24 | String path = ((StringLiteralExpression) getElement()).getContents(); 25 | /* Если путь к файлу включаемой области является абсолютным, то делегируем работу BxPathReference */ 26 | if (path.startsWith("/")) 27 | return new BxPathReference(getElement()).resolve(); 28 | /* Работаем по алгоритму, описанному тут: http://dev.1c-bitrix.ru/api_help/main/reference/cmain/includefile.php */ 29 | VirtualFile file = BxCore.findFile(getElement().getProject().getBaseDir(), "{local,bitrix}/templates/*/" + path); if (file == null) 30 | return null; 31 | 32 | return file.isDirectory() ? getElement().getManager().findDirectory(file) : getElement().getManager().findFile(file); 33 | } 34 | 35 | @NotNull 36 | public PsiReference[] getReference() { 37 | String path = ((StringLiteralExpression) getElement()).getContents(); 38 | /* Если путь к файлу включаемой области является абсолютным, то делегируем работу BxPathReference */ 39 | if (path.startsWith("/")) 40 | return new BxPathReference(getElement()).getReference(); 41 | /* Собираем все возможные варианты ссылки на включаемый файл, которые только сможем найти */ 42 | VirtualFile[] files = BxCore.findFiles(getElement().getProject().getBaseDir(), "{local,bitrix}/templates/*/" + path); if (files == null) 43 | return EMPTY_ARRAY; 44 | /* Строим список вариантов переходов на найденные файлы */ 45 | List references = new ArrayList(); 46 | for (final VirtualFile file : files) { 47 | references.add(new BxReference(getElement()) { 48 | @Nullable @Override public PsiElement resolve() { 49 | return getElement().getManager().findFile(file); 50 | } 51 | }); 52 | } 53 | 54 | return references.toArray(new PsiReference[references.size()]); 55 | } 56 | 57 | @Override 58 | public boolean isSoft() { 59 | return true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/references/BxComponentIncludeReference.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.references; 2 | 3 | import com.intellij.openapi.vfs.VirtualFile; 4 | import com.intellij.psi.PsiElement; 5 | import com.jetbrains.php.lang.parser.PhpElementTypes; 6 | import com.jetbrains.php.lang.psi.elements.ArrayCreationExpression; 7 | import com.jetbrains.php.lang.psi.elements.ArrayHashElement; 8 | import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; 9 | import com.jetbrains.php.lang.psi.elements.impl.ArrayCreationExpressionImpl; 10 | import org.jetbrains.annotations.Nullable; 11 | import pro.opcode.bitrix.BxReference; 12 | import pro.opcode.bitrix.api.BxCore; 13 | 14 | public class BxComponentIncludeReference extends BxReference 15 | { 16 | public BxComponentIncludeReference(PsiElement element) { 17 | super(element); 18 | } 19 | 20 | @Nullable 21 | @Override 22 | public PsiElement resolve() { 23 | BxCore bitrix = new BxCore(getElement().getProject()); 24 | String inclusionType = null; 25 | 26 | for (ArrayHashElement arElement : ((ArrayCreationExpression) getElement().getParent().getParent().getParent()).getHashElements()) { 27 | if (arElement.getKey() instanceof StringLiteralExpression && ((StringLiteralExpression) arElement.getKey()).getContents().equals("AREA_FILE_SHOW") && arElement.getValue() instanceof StringLiteralExpression) 28 | inclusionType = ((StringLiteralExpression) arElement.getValue()).getContents(); 29 | } 30 | 31 | if (inclusionType != null) { 32 | VirtualFile componentTemplateFile = bitrix.getPageIncludeFile( 33 | getElement(), 34 | inclusionType.equals("page") ? "index" : "sect" 35 | ); 36 | 37 | if (componentTemplateFile != null) 38 | return getElement().getManager().findFile(componentTemplateFile); 39 | } 40 | 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/references/BxComponentReference.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.references; 2 | 3 | import com.intellij.openapi.vfs.VirtualFile; 4 | import com.intellij.psi.PsiElement; 5 | import org.jetbrains.annotations.Nullable; 6 | import pro.opcode.bitrix.BxReference; 7 | import pro.opcode.bitrix.api.BxComponent; 8 | import pro.opcode.bitrix.api.BxCore; 9 | 10 | public class BxComponentReference extends BxReference 11 | { 12 | public BxComponentReference(PsiElement element) { 13 | super(element); 14 | } 15 | 16 | @Nullable 17 | @Override 18 | public PsiElement resolve() { 19 | BxComponent component 20 | = BxCore.getComponent(getElement()); 21 | 22 | if (component != null) { 23 | VirtualFile componentFile 24 | = component.getComponentFile("{class.php,component.php}"); 25 | 26 | if (componentFile != null) 27 | return getElement().getManager().findFile(componentFile); 28 | } 29 | 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/references/BxComponentTemplateReference.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.references; 2 | 3 | import com.intellij.openapi.vfs.VirtualFile; 4 | import com.intellij.psi.PsiElement; 5 | import org.jetbrains.annotations.Nullable; 6 | import pro.opcode.bitrix.BxReference; 7 | import pro.opcode.bitrix.api.BxCore; 8 | 9 | public class BxComponentTemplateReference extends BxReference 10 | { 11 | public BxComponentTemplateReference(PsiElement element) { 12 | super(element); 13 | } 14 | 15 | @Nullable 16 | @Override 17 | public PsiElement resolve() { 18 | VirtualFile componentTemplateFile = BxCore.getComponent(getElement()).getComponentTemplateFile("{template.php,template.twig,template.tpl}"); if (componentTemplateFile != null) 19 | return getElement().getManager().findFile(componentTemplateFile); 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/references/BxPathReference.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.references; 2 | 3 | import com.intellij.notification.Notification; 4 | import com.intellij.notification.NotificationType; 5 | import com.intellij.notification.Notifications; 6 | import com.intellij.openapi.vfs.VirtualFile; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiFile; 9 | import com.intellij.util.IncorrectOperationException; 10 | import com.jetbrains.php.lang.psi.elements.*; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | import pro.opcode.bitrix.BxReference; 14 | 15 | /* toDo: В процессе переименования файлов с такими ссылками как 'ind'.'ex.c'.'ss' теряется их связь с файлом */ 16 | /* toDo: Найти способ определения того, что метод checkComplicatedElement вообще необходим. Есть подозрение, что от него нет проку. */ 17 | public class BxPathReference extends BxReference 18 | { 19 | public BxPathReference(PsiElement element) { 20 | super(element); 21 | } 22 | 23 | @Nullable 24 | @Override 25 | public PsiElement resolve() { 26 | return resolve((StringLiteralExpression) getElement()); 27 | } 28 | 29 | @Nullable 30 | public PsiElement resolve(StringLiteralExpression element) { 31 | String path = element.getContents(); 32 | /* Если строка является частью объединения строк, то соберём кусочки паззла */ 33 | if (element.getParent() instanceof BinaryExpression) { 34 | BinaryExpression binaryExpression = (BinaryExpression) element.getParent(); 35 | if (binaryExpression.getOperationType() != null && binaryExpression.getOperationType().toString().equals("dot")) { 36 | String pathResolved = resolveConcatenation(binaryExpression); if (pathResolved != null) 37 | path = pathResolved.replace("//", "/"); /* DOCUMENT_URL может оканчиваться, а может и не оканчиваться на /, потому есть свобода сделать это */ 38 | } 39 | } 40 | 41 | VirtualFile baseDir = path.startsWith("/") 42 | ? element.getProject().getBaseDir() 43 | : element.getContainingFile().getVirtualFile().getParent(); 44 | 45 | if (baseDir == null) 46 | return null; 47 | 48 | VirtualFile file 49 | = baseDir.findFileByRelativePath(path); 50 | 51 | if (file == null) 52 | return null; 53 | 54 | return file.isDirectory() 55 | ? element.getManager().findDirectory(file) 56 | : element.getManager().findFile(file); 57 | } 58 | 59 | public String resolveConcatenation(BinaryExpression binaryExpression) { 60 | String result = ""; 61 | for (PsiElement operand : binaryExpression.getChildren()) { 62 | /* Вложенные конкатенации */ 63 | if (operand instanceof BinaryExpression) { 64 | String recursionResult = resolveConcatenation((BinaryExpression) operand); if (recursionResult == null) 65 | return null; 66 | result += recursionResult; 67 | continue; 68 | } 69 | /* Простые строки */ 70 | if (operand instanceof StringLiteralExpression) { 71 | result += ((StringLiteralExpression) operand).getContents(); 72 | continue; 73 | } 74 | /* Переменные $_SERVER['DOCUMENT_ROOT'] */ 75 | if (operand instanceof ArrayAccessExpression && operand.getText().replace('"', '\'').equals("$_SERVER['DOCUMENT_ROOT']")) { 76 | result += "/"; 77 | continue; 78 | /* Рабочий, но уж очень громоздкий способ... Простое сравнение строк менее ресурсоёмко. 79 | PsiElement value = ((ArrayAccessExpression) operand).getValue(); if (value != null && value instanceof Variable) { 80 | String valueName = ((Variable) value).getName(); if (valueName != null && valueName.equals("_SERVER")) { 81 | PsiElement index = ((ArrayAccessExpression) operand).getIndex(); if (index != null) { 82 | PsiElement indexValue = ((ArrayIndex) index).getValue(); if (indexValue != null && indexValue instanceof StringLiteralExpression) { 83 | String indexName = ((StringLiteralExpression) indexValue).getContents(); if (indexName.equals("DOCUMENT_ROOT")) { 84 | result += "/"; 85 | continue; 86 | } 87 | } 88 | } 89 | 90 | } 91 | } 92 | */ 93 | } 94 | /* Вызов $APPLICATION->sDirPath */ 95 | if (operand instanceof FieldReference && operand.getText().toLowerCase().equals("$application->sdirpath")) { 96 | String resolvedPath = operand.getContainingFile().getContainingDirectory().getVirtualFile().getCanonicalPath(); if (resolvedPath == null) 97 | return null; 98 | result += resolvedPath.replace(operand.getProject().getBasePath(), "") + "/"; 99 | continue; 100 | } 101 | /* Вызов $APPLICATION->GetCurDir() */ 102 | if (operand instanceof MethodReference && operand.getText().toLowerCase().equals("$application->getcurdir()")) { 103 | String resolvedPath = operand.getContainingFile().getContainingDirectory().getVirtualFile().getCanonicalPath(); if (resolvedPath == null) 104 | return null; 105 | result += resolvedPath.replace(operand.getProject().getBasePath(), "") + "/"; 106 | continue; 107 | } 108 | 109 | return null; 110 | } 111 | 112 | return result; 113 | } 114 | 115 | @Override 116 | public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { 117 | PsiElement resolved = resolve(); 118 | StringLiteralExpression element = (StringLiteralExpression) getElement(); 119 | if (resolved instanceof PsiFile) { 120 | /* Запускаем переименование */ 121 | String resolvedFileName = ((PsiFile) resolved).getName(); 122 | String elementContents = element.getContents(); 123 | elementContents = elementContents.substring(0, elementContents.lastIndexOf(resolvedFileName)) + newElementName; 124 | element.updateText(elementContents); 125 | /* Проверим, не потеряли ли ссылку на файл */ 126 | checkComplicatedElement(element); 127 | } 128 | 129 | return element; 130 | } 131 | 132 | @Override 133 | public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { 134 | StringLiteralExpression currentElement = (StringLiteralExpression) getElement(); 135 | if (element instanceof PsiFile) { 136 | String elementPath = ((PsiFile) element).getVirtualFile().getPath(); 137 | String projectPath = element.getProject().getBasePath(); 138 | /* Обновляем содержимое текущего элемента */ 139 | currentElement.updateText(elementPath.replace(projectPath, "")); 140 | /* Проверим, не потеряли ли ссылку на файл */ 141 | checkComplicatedElement(currentElement); 142 | } 143 | 144 | return currentElement; 145 | } 146 | 147 | private void checkComplicatedElement(StringLiteralExpression element) { 148 | /* Исключительно в целях самоконтроля, в случае составной ссылки, проверим что связь с файлом не утеряна */ 149 | if (element.getParent() instanceof BinaryExpression && resolve(element) == null) { 150 | String projectPath = element.getProject().getBasePath(); 151 | String elementFile = element.getContainingFile().getVirtualFile().getCanonicalPath(); if (elementFile == null) 152 | elementFile = "Неизвестный файл"; 153 | 154 | Notifications.Bus.notify( 155 | new Notification("Bitrix Framework Support", "Потенциальная проблема", "Перемещение файлов, ссылки на которых содержат конкатинацию, потенциально могут сработать неверно. Проверьте, всё ли хорошо тут " + elementFile.replace(projectPath, ""), NotificationType.ERROR) 156 | ); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/references/BxTemplateReference.java: -------------------------------------------------------------------------------- 1 | package pro.opcode.bitrix.references; 2 | 3 | import com.intellij.openapi.vfs.VirtualFile; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiReference; 6 | import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | import pro.opcode.bitrix.BxReference; 10 | import pro.opcode.bitrix.api.BxCore; 11 | 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | 16 | public class BxTemplateReference extends BxReference 17 | { 18 | private enum bxTemplatePart { 19 | HEADER, 20 | FOOTER 21 | } 22 | 23 | public static HashMap bxTemplateReferenceTargets = new HashMap(); static { 24 | bxTemplateReferenceTargets.put("/bitrix/header.php", bxTemplatePart.HEADER); 25 | bxTemplateReferenceTargets.put("/bitrix/footer.php", bxTemplatePart.FOOTER); 26 | } 27 | 28 | public BxTemplateReference(PsiElement element) { 29 | super(element); 30 | } 31 | 32 | @Nullable 33 | @Override 34 | public PsiElement resolve() { 35 | StringLiteralExpression element = (StringLiteralExpression) getElement(); 36 | VirtualFile[] siteTemplates = new BxCore(getElement().getProject()).getSiteTemplatesComponents(bxTemplateReferenceTargets.get(element.getContents()).name().toLowerCase() + ".php"); 37 | if (siteTemplates.length > 0) 38 | return element.getManager().findFile(siteTemplates[0]); 39 | 40 | return null; 41 | } 42 | 43 | @NotNull 44 | public PsiReference[] getReference() { 45 | List references = new ArrayList(); 46 | for (final VirtualFile template : new BxCore(getElement().getProject()).getSiteTemplatesComponents(bxTemplateReferenceTargets.get(((StringLiteralExpression) getElement()).getContents()).name().toLowerCase() + ".php")) { 47 | references.add(new BxReference(getElement()) { 48 | @Nullable @Override public PsiElement resolve() { 49 | return getElement().getManager().findFile(template); 50 | } 51 | }); 52 | } 53 | 54 | return references.toArray(new PsiReference[references.size()]); 55 | } 56 | 57 | @Override 58 | public boolean isSoft() { 59 | return true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/resources/fileTemplates/bxSimplePage.php.ft: -------------------------------------------------------------------------------- 1 | SetTitle("Новая страница"); 4 | ?> 5 | 6 | Text here.... 7 | 8 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/resources/fileTemplates/bxSimplePageModern.php.ft: -------------------------------------------------------------------------------- 1 | SetTitle('Новая страница'); 4 | \$APPLICATION->SetPageProperty('title', ''); 5 | \$APPLICATION->SetPageProperty('description', ''); 6 | 7 | ?> 8 | 9 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/resources/fileTemplates/bxSimpleSectionConfig.php.ft: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/resources/fileTemplates/bxSimpleSectionIndex.php.ft: -------------------------------------------------------------------------------- 1 | SetTitle("Новый раздел"); 4 | ?> 5 | 6 | Text here.... 7 | 8 | -------------------------------------------------------------------------------- /src/pro/opcode/bitrix/resources/fileTemplates/bxSimpleService.php.ft: -------------------------------------------------------------------------------- 1 | scopeFileNames; 26 | 27 | public BxSuperglobal(String className, List scopeFileNames) { 28 | this.className = className; 29 | this.scopeFileNames = scopeFileNames; 30 | } 31 | } 32 | 33 | private static final HashMap bxSuperglobals = new HashMap(); static { 34 | bxSuperglobals.put("APPLICATION", new BxSuperglobal("CMain", null)); 35 | bxSuperglobals.put("USER", new BxSuperglobal("CUser", null)); 36 | bxSuperglobals.put("DB", new BxSuperglobal("CDatabase", null)); 37 | bxSuperglobals.put("this", new BxSuperglobal("CBitrixComponentTemplate", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php" ))); 38 | bxSuperglobals.put("component", new BxSuperglobal("CBitrixComponent", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php" ))); 39 | bxSuperglobals.put("arResult", new BxSuperglobal("GLOBALS", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php", "component.php" ))); 40 | bxSuperglobals.put("arParams", new BxSuperglobal("GLOBALS", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php", "component.php" ))); 41 | bxSuperglobals.put("arLangMessages", new BxSuperglobal("GLOBALS", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php" ))); 42 | bxSuperglobals.put("templateName", new BxSuperglobal("php_errormsg", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php" ))); 43 | bxSuperglobals.put("templateData", new BxSuperglobal("php_errormsg", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php" ))); 44 | bxSuperglobals.put("templateFile", new BxSuperglobal("php_errormsg", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php" ))); 45 | bxSuperglobals.put("templateFolder", new BxSuperglobal("php_errormsg", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php" ))); 46 | bxSuperglobals.put("parentTemplateFolder", new BxSuperglobal("php_errormsg", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php" ))); 47 | bxSuperglobals.put("parentComponentName", new BxSuperglobal("php_errormsg", Arrays.asList( "component.php" ))); 48 | bxSuperglobals.put("parentComponentPath", new BxSuperglobal("php_errormsg", Arrays.asList( "component.php" ))); 49 | bxSuperglobals.put("parentComponentTemplate", new BxSuperglobal("php_errormsg", Arrays.asList( "component.php" ))); 50 | bxSuperglobals.put("componentPath", new BxSuperglobal("php_errormsg", Arrays.asList("template.php", "result_modifier.php", "component_epilog.php", "component.php", ".parameters.php" ))); 51 | bxSuperglobals.put("componentName", new BxSuperglobal("php_errormsg", Arrays.asList( "component.php", ".parameters.php" ))); 52 | bxSuperglobals.put("componentTemplate", new BxSuperglobal("php_errormsg", Arrays.asList( "component.php" ))); 53 | bxSuperglobals.put("templateProperties", new BxSuperglobal("php_errormsg", Arrays.asList( ".parameters.php" ))); 54 | bxSuperglobals.put("arCurrentValues", new BxSuperglobal("php_errormsg", Arrays.asList( ".parameters.php" ))); 55 | bxSuperglobals.put("arComponentParameters", new BxSuperglobal("php_errormsg", Arrays.asList( ".parameters.php" ))); 56 | } 57 | 58 | public BxSuperglobalsProvider() { 59 | extend(CompletionType.BASIC, PlatformPatterns.psiElement(PhpTokenTypes.VARIABLE).withLanguage(PhpLanguage.INSTANCE), new CompletionProvider() { 60 | public void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet resultSet) { 61 | String currentFileName = parameters.getOriginalFile().getName(); 62 | for (String variable : bxSuperglobals.keySet()) { 63 | BxSuperglobal superglobal = bxSuperglobals.get(variable); 64 | if (superglobal.scopeFileNames == null || superglobal.scopeFileNames.contains(currentFileName)) 65 | resultSet.addElement(LookupElementBuilder.create("$" + variable)); 66 | } 67 | } 68 | }); 69 | } 70 | 71 | @Override 72 | public char getKey() { 73 | return 'Я'; 74 | } 75 | 76 | @Nullable 77 | @Override 78 | public String getType(PsiElement e) { 79 | if (e instanceof Variable) { 80 | BxSuperglobal superglobal = bxSuperglobals.get(((Variable) e).getName()); if (superglobal != null) { 81 | if (superglobal.scopeFileNames == null || superglobal.scopeFileNames.contains(e.getContainingFile().getName())) 82 | return superglobal.className; 83 | } 84 | } 85 | 86 | return null; 87 | } 88 | 89 | @Override 90 | public Collection getBySignature(String expression, Project project) { 91 | for (BxSuperglobal superglobal : bxSuperglobals.values()) 92 | if (superglobal.className.equals(expression)) { 93 | if (superglobal.className.equals("GLOBALS") || superglobal.className.equals("php_errormsg")) { 94 | return Arrays.asList(PhpPsiElementFactory.createVariable(project, superglobal.className, true)); 95 | } else { 96 | return PhpIndex.getInstance(project).getClassesByFQN(expression); 97 | } 98 | } 99 | 100 | return Collections.emptySet(); 101 | } 102 | } --------------------------------------------------------------------------------