├── .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 | * Переход на файл включаемой области при клике в вызове $APPLICATION→IncludeComponent('bitrix:main.include', ...);?> на значение ключа '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 | * Переход на файл включаемой области при клике в вызове $APPLICATION→IncludeComponent('bitrix:main.include', ...);?> на значение ключа '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 |
11 | - Поддержка папок bitrix и local.
12 | - Переход на файл компонента, шаблона компонента (поддерживаются Twig и Smarty), шаблона сайта а так же на директории и файлы, найденные в строковых переменных.
13 | - Переход на файл включаемой области при клике в вызове $APPLICATION->IncludeComponent('bitrix:main.include', ...);?> на значение ключа 'AREA_FILE_SUFFIX'.
14 | - Корректное определение типов и автокомплит для специальных переменных и переменных шаблона.
15 | - Автокомплит компонента и его шаблона в процессе набора $APPLICATION->IncludeComponent(...) и CBitrixComponent::includeComponentClass(...)
16 | - Решена проблема с подсветкой bitrix как неразрешённого пути в вызовах require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php"); и похожих конструкциях.
17 | - Безопасный рефакторинг файлов с автоматическим обновлением их вызовов в строковых переменных.
18 | - Поиск использований, например файла some.css, в вызовах $APPLICATION->SetAdditionalCSS('...some.css'), во всех файлах проекта.
19 | - Шаблоны создания типовых страниц и разделов сайта.
20 |
21 | Демо-видео
22 | Пожелания и сообщения об ошибках можете отправлять на почту или оставлять в Кабинете. Там же можете посмотреть планы по развитию.
23 | ]]>
24 |
25 | 0.1.9
27 | - Шаблоны создаваемых страниц и разделов Битрикс теперь могут быть изменены в настройках IDE: Editor / File and Code Templates
28 | - Убран крайне криво реализованный функционал для переопределения штатного поведения инспекций IDE. Решена проблема, описанная тут.
29 |
30 | 0.1.7
31 | - Исправление ошибок
32 |
33 | 0.1.6
34 | - Автокомплит следующим суперглобальным переменным в .parameters.php: $componentName, $templateProperties, $arCurrentValues, $arComponentParameters и $componentPath
35 | - Автокомплит следующим суперглобальным переменным в component.php: $componentName, $componentTemplate, $parentComponentName, $parentComponentPath и $parentComponentTemplate
36 |
37 | 0.1.5
38 | - Автокомплит компонента, его шаблона и переход к ним в вызове CBitrixComponent::includeComponentClass(...)
39 |
40 | 0.1.4
41 | - Несколько типовых шаблонов в диалоге создания страницы
42 |
43 | 0.1.3
44 | - Доступность переменных $arResult, $arParams, $componentPath и подобных им в файлах result_modifier.php
45 |
46 | 0.1.2
47 | - Создание типового раздела Битрикс сайта
48 |
49 | 0.1.1
53 | 0.1
54 | - Ошибка определения ссылок на файлы в строках с конкатенацией
55 | - Автокомплит шаблона компонента в процессе набора $APPLICATION->IncludeComponent("bitrix:component", ...)
56 |
57 | 0.0.9
58 | - Переход к коду компонента в class.php, если он есть и к component.php в противном случае.
59 | - Поддержка нестандартных расширений для шаблонов компонентов: template.twig, template.tpl
60 | - Исправлена ошибка: BxPathReference has unsatisfied dependency
61 |
62 | 0.0.8
66 | 0.0.7
67 | - Корректное определение файлов в строках с конкатенацией, например в 'ind'.'ex.c'.'ss' или $APPLICATION->SetAdditionalCSS($APPLICATION->GetCurDir().'/some.css')
68 | - Доступность переменных $arResult, $arParams и $componentPath в файлах component.php
69 | - Поддержка PhpStorm
70 |
71 | 0.0.6
72 | - Решена проблема с подсветкой bitrix в вызовах require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include.php");
73 | - Поддержка безопасного удаления файлов с предупреждением о их использованиях в вызовах, например $APPLICATION->SetAdditionalCSS('/some.css')
74 | - Поддержка переименования и перемещения файлов с автоматическим обновлением их вызовов, например $APPLICATION->SetAdditionalCSS('/some.css')
75 | - Поиск использований, например файла some.css, в вызовах $APPLICATION->SetAdditionalCSS('...some.css'), во всех файлах проекта.
76 | - Вышеперечисленную "магию" лучше посмотреть наглядно. В целом, тема интересная и есть куда развивать: автокомплит, например, создание отсутствующего файла и т.п.
77 |
78 | 0.0.5
79 | - Решена проблема с подсветкой bitrix в вызовах require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
80 | - Автокомплит переменных, доступных в шаблоне компонента. Это $arResult, $arParams, $componentPath и другие, описанные тут.
81 |
82 | 0.0.4
83 | - Автокомплит компонента в процессе набора $APPLICATION->IncludeComponent(...)
84 |
85 | 0.0.3
86 | - Переход на директории и файлы, найденные в строковых переменных.
87 |
88 | 0.0.2
91 | 0.0.1
92 | - Переход на шаблон компонента, расположенный внутри (bitrix|local)/templates/...
93 | - Переход на файл включаемой области при клике в вызове $APPLICATION->IncludeComponent('bitrix:main.include', ...);?> на значение ключа 'AREA_FILE_SUFFIX'.
94 | - Поддержка папок bitrix и local.
95 |
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 |
2 | require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
3 | \$APPLICATION->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 |
2 | \$sSectionName = "Новый раздел";
3 | \$arDirProperties = Array(
4 |
5 | );
6 | ?>
--------------------------------------------------------------------------------
/src/pro/opcode/bitrix/resources/fileTemplates/bxSimpleSectionIndex.php.ft:
--------------------------------------------------------------------------------
1 |
2 | require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
3 | \$APPLICATION->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 extends PhpNamedElement> 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 | }
--------------------------------------------------------------------------------