├── .gitignore ├── settings.gradle.kts ├── docs └── imgs │ ├── qr.png │ ├── debug.png │ ├── auto_suggestion.png │ ├── cases_execution.png │ ├── code_inspection.png │ ├── find_keyword_usages.png │ ├── keyword_navigation.png │ ├── syntax_highlighting.png │ └── file_structure_and_folding.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ ├── images │ │ ├── robot.png │ │ └── resource.png │ ├── messages │ │ ├── MyBundle.properties │ │ └── RobotBundle.properties │ └── META-INF │ │ └── pluginIcon.svg │ └── java │ └── com │ └── github │ └── jnhyperion │ └── hyperrobotframeworkplugin │ ├── psi │ ├── element │ │ ├── KeywordDefinitionId.java │ │ ├── VariableDefinitionId.java │ │ ├── Variable.java │ │ ├── Argument.java │ │ ├── Import.java │ │ ├── RobotStatement.java │ │ ├── VariableDefinition.java │ │ ├── KeywordInvokable.java │ │ ├── KeywordDefinitionIdImpl.java │ │ ├── VariableDefinitionIdImpl.java │ │ ├── DefinedKeyword.java │ │ ├── DefinedVariable.java │ │ ├── KeywordStatement.java │ │ ├── BracketSetting.java │ │ ├── Setting.java │ │ ├── ArgumentImpl.java │ │ ├── KeywordFile.java │ │ ├── BracketSettingImpl.java │ │ ├── SettingImpl.java │ │ ├── ImportImpl.java │ │ ├── KeywordDefinition.java │ │ ├── Heading.java │ │ ├── KeywordInvokableImpl.java │ │ ├── VariableImpl.java │ │ ├── RobotFile.java │ │ ├── RobotPsiElementBase.java │ │ ├── VariableDefinitionImpl.java │ │ ├── KeywordStatementImpl.java │ │ └── RobotFileImpl.java │ ├── RobotElementType.java │ ├── util │ │ ├── PerformanceEntity.java │ │ ├── RobotUtil.java │ │ ├── PerformanceCollector.java │ │ ├── PatternBuilder.java │ │ ├── PatternUtil.java │ │ └── ReservedVariable.java │ ├── RobotLanguage.java │ ├── RobotFileTypeHandler.java │ ├── RobotSyntaxHighlightingFactory.java │ ├── manip │ │ ├── ArgumentManipulator.java │ │ ├── VariableManipulator.java │ │ └── KeywordInvokableManipulator.java │ ├── dto │ │ ├── ImportType.java │ │ ├── KeywordDto.java │ │ └── VariableDto.java │ ├── RobotFeatureFileType.java │ ├── RobotResourceFileType.java │ ├── RecommendationWord.java │ ├── ref │ │ ├── RobotVariableReference.java │ │ ├── RobotKeywordReference.java │ │ ├── RobotArgumentReference.java │ │ ├── RobotPythonClass.java │ │ ├── RobotPythonFile.java │ │ └── RobotPythonWrapper.java │ ├── RobotTokenTypes.java │ ├── RobotKeywordTable.java │ ├── RobotParserDefinition.java │ └── RobotHighlighter.java │ ├── ide │ ├── inspections │ │ ├── SimpleInspection.java │ │ ├── SimpleInspectionVisitor.java │ │ ├── SimpleRobotInspection.java │ │ ├── complexity │ │ │ ├── RobotNestedVariable.java │ │ │ └── RobotNestedVariableDefinition.java │ │ ├── compilation │ │ │ ├── RobotKeywordNotFound.java │ │ │ ├── RobotImportNotFound.java │ │ │ └── RobotVariableNotFound.java │ │ ├── readability │ │ │ ├── RobotKeywordDefinitionStartingWithGherkin.java │ │ │ └── RobotGherkinInspection.java │ │ └── cleanup │ │ │ └── RobotImportNotUsed.java │ ├── icons │ │ └── RobotIcons.java │ ├── RobotCommenter.java │ ├── usage │ │ ├── RobotWordScanner.java │ │ ├── RobotKeywordGroupingRuleProvider.java │ │ └── RobotFindUsagesProvider.java │ ├── structure │ │ ├── RobotStructureViewFactory.java │ │ ├── RobotTypeFilter.java │ │ ├── RobotTypeSorter.java │ │ ├── RobotViewElementType.java │ │ ├── RobotStructureViewModel.java │ │ └── RobotStructureViewElement.java │ ├── execution │ │ ├── RobotRunLineMarkerProvider.java │ │ └── RobotRunConfigurationProducer.java │ ├── config │ │ ├── RobotOptionsProvider.java │ │ ├── RobotConfiguration.form │ │ ├── RobotConfiguration.java │ │ └── RobotColorsPage.java │ ├── RobotFoldingBuilder.java │ └── search │ │ └── RobotPythonReferenceSearch.java │ └── RobotBundle.java ├── detekt-config.yml ├── .run ├── Run Plugin Tests.run.xml ├── Run IDE with Plugin.run.xml └── Run Plugin Verification.run.xml ├── gradle.properties ├── README.md ├── .github └── workflows │ └── release.yml ├── gradlew.bat ├── CHANGELOG.md └── gradlew /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "HyperRobotFrameworkPlugin" 2 | -------------------------------------------------------------------------------- /docs/imgs/qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/qr.png -------------------------------------------------------------------------------- /docs/imgs/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/debug.png -------------------------------------------------------------------------------- /docs/imgs/auto_suggestion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/auto_suggestion.png -------------------------------------------------------------------------------- /docs/imgs/cases_execution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/cases_execution.png -------------------------------------------------------------------------------- /docs/imgs/code_inspection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/code_inspection.png -------------------------------------------------------------------------------- /docs/imgs/find_keyword_usages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/find_keyword_usages.png -------------------------------------------------------------------------------- /docs/imgs/keyword_navigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/keyword_navigation.png -------------------------------------------------------------------------------- /docs/imgs/syntax_highlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/syntax_highlighting.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/images/robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/src/main/resources/images/robot.png -------------------------------------------------------------------------------- /src/main/resources/images/resource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/src/main/resources/images/resource.png -------------------------------------------------------------------------------- /docs/imgs/file_structure_and_folding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/HEAD/docs/imgs/file_structure_and_folding.png -------------------------------------------------------------------------------- /src/main/resources/messages/MyBundle.properties: -------------------------------------------------------------------------------- 1 | name=My Plugin 2 | applicationService=Application service 3 | projectService=Project service: {0} 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /detekt-config.yml: -------------------------------------------------------------------------------- 1 | # Default detekt configuration: 2 | # https://github.com/detekt/detekt/blob/master/detekt-core/src/main/resources/default-detekt-config.yml 3 | 4 | formatting: 5 | Indentation: 6 | continuationIndentSize: 8 7 | ParameterListWrapping: 8 | indentSize: 8 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/KeywordDefinitionId.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | /** 4 | * @author mrubino 5 | * @since 2016-01-07 6 | */ 7 | public interface KeywordDefinitionId extends RobotStatement { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/VariableDefinitionId.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | /** 4 | * @author mrubino 5 | * @since 2016-04-01 6 | */ 7 | public interface VariableDefinitionId extends RobotStatement { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/Variable.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | /** 4 | * @author mrubino 5 | * @since 2015-07-21 6 | */ 7 | public interface Variable extends RobotStatement { 8 | 9 | boolean isNested(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/Argument.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiNamedElement; 4 | 5 | /** 6 | * @author Stephen Abrams 7 | */ 8 | public interface Argument extends RobotStatement, PsiNamedElement { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/Import.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | /** 4 | * @author mrubino 5 | */ 6 | public interface Import extends RobotStatement { 7 | 8 | boolean isResource(); 9 | 10 | boolean isLibrary(); 11 | 12 | boolean isVariables(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/RobotStatement.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * @author mrubino 8 | * @since 2015-07-23 9 | */ 10 | public interface RobotStatement extends PsiElement { 11 | 12 | @NotNull 13 | String getPresentableText(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/VariableDefinition.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiNamedElement; 4 | 5 | /** 6 | * @author mrubino 7 | */ 8 | public interface VariableDefinition extends RobotStatement, PsiNamedElement { 9 | 10 | // TODO: this should go away once we identify the nesting correctly 11 | boolean isNested(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotElementType.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.intellij.psi.tree.IElementType; 4 | import org.jetbrains.annotations.NonNls; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public class RobotElementType extends IElementType { 8 | public RobotElementType(@NotNull @NonNls String debugName) { 9 | super(debugName, RobotLanguage.INSTANCE); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/KeywordInvokable.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiNamedElement; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Collection; 7 | 8 | /** 9 | * @author Stephen Abrams 10 | */ 11 | public interface KeywordInvokable extends RobotStatement, PsiNamedElement { 12 | 13 | @NotNull 14 | Collection getArguments(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/KeywordDefinitionIdImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * @author mrubino 8 | * @since 2016-01-06 9 | */ 10 | public class KeywordDefinitionIdImpl extends RobotPsiElementBase implements KeywordDefinitionId { 11 | 12 | public KeywordDefinitionIdImpl(@NotNull ASTNode node) { 13 | super(node); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/util/PerformanceEntity.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.util; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * @author mrubino 8 | * @since 2014-06-27 9 | */ 10 | public interface PerformanceEntity { 11 | 12 | @NotNull 13 | String getDebugFileName(); 14 | 15 | @NotNull 16 | String getDebugText(); 17 | 18 | @NotNull 19 | Project getProject(); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/VariableDefinitionIdImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * @author mrubino 8 | * @since 2016-04-01 9 | */ 10 | public class VariableDefinitionIdImpl extends RobotPsiElementBase implements VariableDefinitionId { 11 | 12 | public VariableDefinitionIdImpl(@NotNull ASTNode node) { 13 | super(node); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/DefinedKeyword.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiElement; 4 | 5 | /** 6 | * @author mrubino 7 | * @since 2014-06-06 8 | */ 9 | public interface DefinedKeyword { 10 | 11 | String getKeywordName(); 12 | 13 | /** 14 | * @return true if this keyword definition has the [Arguments] setting. 15 | */ 16 | boolean hasArguments(); 17 | 18 | boolean matches(String text); 19 | 20 | PsiElement reference(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/DefinedVariable.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * @author mrubino 8 | * @since 2014-06-18 9 | */ 10 | public interface DefinedVariable { 11 | 12 | boolean matches(@Nullable String text); 13 | 14 | boolean isInScope(@Nullable PsiElement position); 15 | 16 | @Nullable 17 | PsiElement reference(); 18 | 19 | @Nullable 20 | String getLookup(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/KeywordStatement.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author mrubino 10 | */ 11 | public interface KeywordStatement extends RobotStatement { 12 | 13 | @Nullable 14 | KeywordInvokable getInvokable(); 15 | 16 | @NotNull 17 | List getArguments(); 18 | 19 | @Nullable 20 | DefinedVariable getGlobalVariable(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotLanguage.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.intellij.lang.Language; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * @author mrubino 8 | */ 9 | public class RobotLanguage extends Language { 10 | 11 | public static final RobotLanguage INSTANCE = new RobotLanguage(); 12 | 13 | private RobotLanguage() { 14 | super("Robot", ""); 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String getDisplayName() { 20 | return "Robot"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotFileTypeHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.intellij.openapi.fileTypes.FileTypeConsumer; 4 | import com.intellij.openapi.fileTypes.FileTypeFactory; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * @author mrubino 9 | */ 10 | public class RobotFileTypeHandler extends FileTypeFactory { 11 | 12 | @Override 13 | public void createFileTypes(@NotNull FileTypeConsumer consumer) { 14 | consumer.consume(RobotFeatureFileType.getInstance()); 15 | consumer.consume(RobotResourceFileType.getInstance()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/BracketSetting.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | /** 4 | * @author mrubino 5 | */ 6 | public interface BracketSetting extends RobotStatement { 7 | 8 | /** 9 | * Determines if the current element is an '[Arguments]' element. 10 | * 11 | * @return true if this is an argument element; false otherwise. 12 | */ 13 | boolean isArguments(); 14 | 15 | /** 16 | * Determines if the current element is a '[Teardown]' element. 17 | * 18 | * @return true if this is a teardown element; false otherwise. 19 | */ 20 | boolean isTeardown(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/Setting.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | /** 4 | * @author mrubino 5 | */ 6 | public interface Setting extends RobotStatement { 7 | 8 | /** 9 | * Determines if the current element is a 'Suite Teardown' element. 10 | * 11 | * @return true if this is a suite teardown element; false otherwise. 12 | */ 13 | boolean isSuiteTeardown(); 14 | 15 | /** 16 | * Determines if the current element is a 'Test Teardown' element. 17 | * 18 | * @return true if this is a test teardown element; false otherwise. 19 | */ 20 | boolean isTestTeardown(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/ArgumentImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref.RobotArgumentReference; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.psi.PsiReference; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * @author Stephen Abrams 10 | */ 11 | public class ArgumentImpl extends RobotPsiElementBase implements Argument { 12 | 13 | public ArgumentImpl(@NotNull final ASTNode node) { 14 | super(node); 15 | } 16 | 17 | @Override 18 | public PsiReference getReference() { 19 | return new RobotArgumentReference(this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/SimpleInspection.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections; 2 | 3 | import com.intellij.psi.PsiElement; 4 | 5 | /** 6 | * @author mrubino 7 | * @since 2014-06-07 8 | */ 9 | public interface SimpleInspection { 10 | 11 | /** 12 | * Determines if the element is valid for this inspection. 13 | * 14 | * @param element the element in question. 15 | * @return true if this element is valid; false if it is not. 16 | */ 17 | boolean skip(PsiElement element); 18 | 19 | /** 20 | * The inspection message to be show in this inspection matches. 21 | * 22 | * @return the inspection message. 23 | */ 24 | String getMessage(); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/KeywordFile.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.ImportType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Collection; 7 | 8 | /** 9 | * Created with IntelliJ IDEA. 10 | * User: mrubino 11 | * Date: 1/28/14 12 | * Time: 8:01 PM 13 | */ 14 | public interface KeywordFile { 15 | 16 | @NotNull 17 | Collection getDefinedKeywords(); 18 | 19 | @NotNull 20 | Collection getDefinedVariables(); 21 | 22 | @NotNull 23 | ImportType getImportType(); 24 | 25 | @NotNull 26 | Collection getImportedFiles(boolean includeTransitive); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotSyntaxHighlightingFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.intellij.openapi.fileTypes.SyntaxHighlighter; 4 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.vfs.VirtualFile; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | /** 11 | * @author mrubino 12 | */ 13 | public class RobotSyntaxHighlightingFactory extends SyntaxHighlighterFactory { 14 | 15 | @NotNull 16 | @Override 17 | public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) { 18 | return new RobotHighlighter(RobotKeywordProvider.getInstance()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/icons/RobotIcons.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.icons; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.util.IconLoader; 5 | 6 | import javax.swing.*; 7 | 8 | /** 9 | * @author mrubino 10 | * @since 2016-01-28 11 | */ 12 | public class RobotIcons { 13 | 14 | public static final Icon FILE = IconLoader.findIcon("/images/robot.png"); 15 | public static final Icon RESOURCE = IconLoader.findIcon("/images/resource.png"); 16 | public static final Icon HEADING = AllIcons.Nodes.Tag; 17 | public static final Icon KEYWORD_DEFINITION = AllIcons.Nodes.Method; 18 | public static final Icon TEST_CASE = AllIcons.RunConfigurations.Junit; 19 | public static final Icon VARIABLE_DEFINITION = AllIcons.Nodes.Variable; 20 | 21 | private RobotIcons() { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/BracketSettingImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * @author mrubino 8 | */ 9 | public class BracketSettingImpl extends RobotPsiElementBase implements BracketSetting { 10 | 11 | private static final String ARGUMENTS = "[Arguments]"; 12 | private static final String TEARDOWN = "[Teardown]"; 13 | 14 | public BracketSettingImpl(@NotNull final ASTNode node) { 15 | super(node); 16 | } 17 | 18 | @Override 19 | public boolean isArguments() { 20 | // TODO: better OO 21 | return ARGUMENTS.equalsIgnoreCase(getPresentableText()); 22 | } 23 | 24 | @Override 25 | public boolean isTeardown() { 26 | // TODO: better OO 27 | return TEARDOWN.equalsIgnoreCase(getPresentableText()); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/SettingImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * @author mrubino 8 | */ 9 | public class SettingImpl extends RobotPsiElementBase implements Setting { 10 | 11 | private static final String SUITE_TEARDOWN = "Suite Teardown"; 12 | private static final String TEST_TEARDOWN = "Test Teardown"; 13 | 14 | public SettingImpl(@NotNull final ASTNode node) { 15 | super(node); 16 | } 17 | 18 | @Override 19 | public boolean isSuiteTeardown() { 20 | // TODO: better OO 21 | return SUITE_TEARDOWN.equalsIgnoreCase(getPresentableText()); 22 | } 23 | 24 | @Override 25 | public boolean isTestTeardown() { 26 | // TODO: better OO 27 | return TEST_TEARDOWN.equalsIgnoreCase(getPresentableText()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/RobotCommenter.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide; 2 | 3 | import com.intellij.lang.Commenter; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * @author mrubino 8 | */ 9 | public class RobotCommenter implements Commenter { 10 | 11 | private static final String LINE_COMMENT_PREFIX = "#"; 12 | 13 | @Nullable 14 | public String getLineCommentPrefix() { 15 | return LINE_COMMENT_PREFIX; 16 | } 17 | 18 | @Nullable 19 | public String getBlockCommentPrefix() { 20 | return null; 21 | } 22 | 23 | @Nullable 24 | public String getBlockCommentSuffix() { 25 | return null; 26 | } 27 | 28 | @Nullable 29 | public String getCommentedBlockCommentPrefix() { 30 | return null; 31 | } 32 | 33 | @Nullable 34 | public String getCommentedBlockCommentSuffix() { 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/ImportImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * @author mrubino 8 | */ 9 | public class ImportImpl extends RobotPsiElementBase implements Import { 10 | 11 | public ImportImpl(@NotNull final ASTNode node) { 12 | super(node); 13 | } 14 | 15 | public boolean isResource() { 16 | // TODO: better OO 17 | String text = getPresentableText(); 18 | return text.equals("Resource"); 19 | } 20 | 21 | public boolean isVariables() { 22 | // TODO: better OO 23 | String text = getPresentableText(); 24 | return text.equals("Variables"); 25 | } 26 | 27 | public boolean isLibrary() { 28 | // TODO: better OO 29 | String text = getPresentableText(); 30 | return text.equals("Library"); 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/manip/ArgumentManipulator.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.manip; 2 | 3 | import com.intellij.openapi.util.TextRange; 4 | import com.intellij.psi.AbstractElementManipulator; 5 | import com.intellij.util.IncorrectOperationException; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Argument; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * we seem to need this but it is not really used at this time. it prevents NPEs for the jump to source. 11 | * we likely need it to do intelligent refactoring. 12 | * 13 | * @author Scott Albertine 14 | */ 15 | public class ArgumentManipulator extends AbstractElementManipulator { 16 | 17 | @Override 18 | public Argument handleContentChange(@NotNull Argument element, @NotNull TextRange range, 19 | String newContent) throws IncorrectOperationException { 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/SimpleInspectionVisitor.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections; 2 | 3 | import com.intellij.codeInspection.ProblemsHolder; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiElementVisitor; 6 | 7 | /** 8 | * @author mrubino 9 | * @since 2014-06-07 10 | */ 11 | public class SimpleInspectionVisitor extends PsiElementVisitor { 12 | 13 | private final ProblemsHolder holder; 14 | private final SimpleInspection context; 15 | 16 | public SimpleInspectionVisitor(ProblemsHolder holder, SimpleInspection context) { 17 | this.holder = holder; 18 | this.context = context; 19 | } 20 | 21 | @Override 22 | public void visitElement(PsiElement element) { 23 | if (this.context.skip(element)) { 24 | return; 25 | } 26 | 27 | // TODO: the refactor 28 | this.holder.registerProblem(element, this.context.getMessage()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/manip/VariableManipulator.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.manip; 2 | 3 | import com.intellij.openapi.util.TextRange; 4 | import com.intellij.psi.AbstractElementManipulator; 5 | import com.intellij.util.IncorrectOperationException; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Argument; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * we seem to need this but it is not really used at this time. it prevents NPEs for the jump to source. 11 | * we likely need it to do intelligent refactoring. 12 | * 13 | * @author mrubino 14 | * @since 2015-07-21 15 | */ 16 | public class VariableManipulator extends AbstractElementManipulator { 17 | 18 | @Override 19 | public Argument handleContentChange(@NotNull Argument element, @NotNull TextRange range, 20 | String newContent) throws IncorrectOperationException { 21 | return null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/manip/KeywordInvokableManipulator.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.manip; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordInvokable; 4 | import com.intellij.openapi.util.TextRange; 5 | import com.intellij.psi.AbstractElementManipulator; 6 | import com.intellij.util.IncorrectOperationException; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * we seem to need this but it is not really used at this time. it prevents NPEs for the jump to source. 11 | * we likely need it to do intelligent refactoring. 12 | * 13 | * @author mrubino 14 | */ 15 | public class KeywordInvokableManipulator extends AbstractElementManipulator { 16 | 17 | @Override 18 | public KeywordInvokable handleContentChange(@NotNull KeywordInvokable element, @NotNull TextRange range, 19 | String newContent) throws IncorrectOperationException { 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/KeywordDefinition.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiNamedElement; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Collection; 7 | import java.util.List; 8 | 9 | /** 10 | * @author Stephen Abrams 11 | */ 12 | public interface KeywordDefinition extends RobotStatement, PsiNamedElement { 13 | 14 | @NotNull 15 | List getInvokedKeywords(); 16 | 17 | /** 18 | * This does not include variables that are saved globally as a result of calling this keyword. 19 | * 20 | * @return a list of variables as defined in the arguments of this keyword 21 | */ 22 | @NotNull 23 | Collection getDeclaredVariables(); 24 | 25 | /** 26 | * Determines if this keyword definition has inline variables defined within its name. 27 | * 28 | * @return true if there are inline variables defined, false otherwise. 29 | */ 30 | boolean hasInlineVariables(); 31 | } 32 | -------------------------------------------------------------------------------- /.run/Run Plugin Tests.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /.run/Run IDE with Plugin.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # IntelliJ Platform Artifacts Repositories 2 | # -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html 3 | 4 | pluginGroup = com.github.jnhyperion.hyperrobotframeworkplugin 5 | pluginName = Hyper RobotFramework Support 6 | pluginVersion = 0.0.1.04081502 7 | pluginSinceBuild = 202.2 8 | pluginUntilBuild = 9 | # Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl 10 | # See https://jb.gg/intellij-platform-builds-list for available build versions 11 | pluginVerifierIdeVersions = PC-2020.2.2, PC-2020.2.4, PC-2020.3.2, PC-2021.1 12 | 13 | platformType = PC 14 | platformVersion = PC-2020.2 15 | platformDownloadSources = true 16 | # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html 17 | # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 18 | platformPlugins = PythonCore 19 | 20 | # Opt-out flag for bundling Kotlin standard library. 21 | # See https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library for details. 22 | kotlin.stdlib.default.dependency = false 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/dto/ImportType.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import java.util.Map; 7 | import java.util.TreeMap; 8 | 9 | /** 10 | * @author mrubino 11 | * @since 2014-06-19 12 | */ 13 | public enum ImportType { 14 | 15 | RESOURCE, 16 | LIBRARY, 17 | VARIABLES, 18 | UNKNOWN; 19 | 20 | private static final Map MAP; 21 | 22 | static { 23 | MAP = new TreeMap(String.CASE_INSENSITIVE_ORDER); 24 | MAP.put("resource", RESOURCE); 25 | MAP.put("resources", RESOURCE); 26 | MAP.put("library", LIBRARY); 27 | MAP.put("libraries", LIBRARY); 28 | MAP.put("variable", VARIABLES); 29 | MAP.put("variables", VARIABLES); 30 | } 31 | 32 | @NotNull 33 | public static ImportType getType(@Nullable String text) { 34 | ImportType result = MAP.get(text == null ? null : text.trim()); 35 | return result == null ? UNKNOWN : result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/util/RobotUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.util; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedKeyword; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Heading; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.RobotFileImpl; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiFile; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.util.Collection; 11 | import java.util.LinkedHashSet; 12 | 13 | public class RobotUtil { 14 | 15 | public static Collection getTestCasesFromElement(@NotNull PsiElement element) { 16 | PsiFile psiFile = element.getContainingFile(); 17 | if (psiFile instanceof RobotFileImpl) { 18 | for(Heading heading: ((RobotFileImpl) psiFile).getHeadings()) { 19 | if (heading.containsTestCases()) { 20 | return heading.getTestCases(); 21 | } 22 | } 23 | } 24 | return new LinkedHashSet<>(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/usage/RobotWordScanner.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.usage; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotKeywordProvider; 4 | import com.intellij.lang.cacheBuilder.DefaultWordsScanner; 5 | import com.intellij.psi.tree.TokenSet; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotLexer; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotTokenTypes; 8 | 9 | /** 10 | * @author mrubino 11 | * @since 2015-12-22 12 | */ 13 | public class RobotWordScanner extends DefaultWordsScanner { 14 | 15 | private static final TokenSet IDENTIFIERS = TokenSet.create(RobotTokenTypes.KEYWORD_DEFINITION, RobotTokenTypes.VARIABLE_DEFINITION); 16 | private static final TokenSet COMMENTS = TokenSet.create(RobotTokenTypes.COMMENT); 17 | private static final TokenSet LITERALS = TokenSet.create(RobotTokenTypes.ARGUMENT); 18 | 19 | public RobotWordScanner() { 20 | super(new RobotLexer(RobotKeywordProvider.getInstance()), IDENTIFIERS, COMMENTS, LITERALS); 21 | setMayHaveFileRefsInLiterals(true); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/structure/RobotStructureViewFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.structure; 2 | 3 | import com.intellij.ide.structureView.StructureViewBuilder; 4 | import com.intellij.ide.structureView.StructureViewModel; 5 | import com.intellij.ide.structureView.TreeBasedStructureViewBuilder; 6 | import com.intellij.lang.PsiStructureViewFactory; 7 | import com.intellij.openapi.editor.Editor; 8 | import com.intellij.psi.PsiFile; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | /** 13 | * @author mrubino 14 | * @since 2015-11-23 15 | */ 16 | public class RobotStructureViewFactory implements PsiStructureViewFactory { 17 | 18 | @Nullable 19 | @Override 20 | public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) { 21 | return new TreeBasedStructureViewBuilder() { 22 | @NotNull 23 | @Override 24 | public StructureViewModel createStructureViewModel(@Nullable Editor editor) { 25 | return new RobotStructureViewModel(psiFile, editor); 26 | } 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/Heading.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiFile; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Collection; 8 | 9 | /** 10 | * @author Stephen Abrams 11 | */ 12 | public interface Heading extends RobotStatement { 13 | 14 | boolean isSettings(); 15 | 16 | boolean containsTestCases(); 17 | 18 | boolean containsKeywordDefinitions(); 19 | 20 | @NotNull 21 | Collection getImportedFiles(); 22 | 23 | @NotNull 24 | Collection getDefinedKeywords(); 25 | 26 | @NotNull 27 | Collection getTestCases(); 28 | 29 | @NotNull 30 | Collection getFilesFromInvokedKeywordsAndVariables(); 31 | 32 | @NotNull 33 | Collection getDefinedVariables(); 34 | 35 | void importsChanged(); 36 | 37 | @NotNull 38 | Collection getInvokedKeywords(); 39 | 40 | @NotNull 41 | Collection getKeywordReferences(@Nullable KeywordDefinition definition); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/KeywordInvokableImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref.RobotKeywordReference; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiReference; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.Collection; 10 | import java.util.Collections; 11 | 12 | /** 13 | * @author Stephen Abrams 14 | */ 15 | public class KeywordInvokableImpl extends RobotPsiElementBase implements KeywordInvokable { 16 | 17 | public KeywordInvokableImpl(@NotNull final ASTNode node) { 18 | super(node); 19 | } 20 | 21 | @NotNull 22 | @Override 23 | public Collection getArguments() { 24 | PsiElement parent = getParent(); 25 | if (parent instanceof KeywordStatement) { 26 | return ((KeywordStatement) parent).getArguments(); 27 | } 28 | return Collections.emptySet(); 29 | } 30 | 31 | @Override 32 | public PsiReference getReference() { 33 | return new RobotKeywordReference(this); 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotFeatureFileType.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.icons.RobotIcons; 4 | import com.intellij.openapi.fileTypes.LanguageFileType; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import javax.swing.*; 9 | 10 | /** 11 | * @author mrubino 12 | */ 13 | public class RobotFeatureFileType extends LanguageFileType { 14 | 15 | private static final RobotFeatureFileType INSTANCE = new RobotFeatureFileType(); 16 | 17 | private RobotFeatureFileType() { 18 | super(RobotLanguage.INSTANCE); 19 | } 20 | 21 | public static RobotFeatureFileType getInstance() { 22 | return INSTANCE; 23 | } 24 | 25 | @NotNull 26 | public String getName() { 27 | return "Robot Feature"; 28 | } 29 | 30 | @NotNull 31 | public String getDescription() { 32 | return "Robot Feature Files"; 33 | } 34 | 35 | @NotNull 36 | public String getDefaultExtension() { 37 | return "robot"; 38 | } 39 | 40 | @Nullable 41 | public Icon getIcon() { 42 | return RobotIcons.FILE; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotResourceFileType.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.icons.RobotIcons; 4 | import com.intellij.openapi.fileTypes.LanguageFileType; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import javax.swing.*; 9 | 10 | /** 11 | * @author mrubino 12 | */ 13 | public class RobotResourceFileType extends LanguageFileType { 14 | 15 | private static final RobotResourceFileType INSTANCE = new RobotResourceFileType(); 16 | 17 | private RobotResourceFileType() { 18 | super(RobotLanguage.INSTANCE); 19 | } 20 | 21 | public static RobotResourceFileType getInstance() { 22 | return INSTANCE; 23 | } 24 | 25 | @NotNull 26 | public String getName() { 27 | return "Robot Resource"; 28 | } 29 | 30 | @NotNull 31 | public String getDescription() { 32 | return "Robot Resource Files"; 33 | } 34 | 35 | @NotNull 36 | public String getDefaultExtension() { 37 | return "resource"; 38 | } 39 | 40 | @Nullable 41 | public Icon getIcon() { 42 | return RobotIcons.RESOURCE; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/RobotBundle.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin; 2 | 3 | import com.intellij.CommonBundle; 4 | import com.intellij.reference.SoftReference; 5 | import org.jetbrains.annotations.NonNls; 6 | import org.jetbrains.annotations.PropertyKey; 7 | 8 | import java.lang.ref.Reference; 9 | import java.util.ResourceBundle; 10 | 11 | /** 12 | * @author mrubino 13 | */ 14 | public class RobotBundle { 15 | 16 | // based off python's 17 | 18 | @NonNls 19 | private static final String BUNDLE = "messages.RobotBundle"; 20 | 21 | private static Reference instance; 22 | 23 | private RobotBundle() { 24 | } 25 | 26 | public static String message(@NonNls @PropertyKey(resourceBundle = BUNDLE) String key, Object... params) { 27 | return CommonBundle.message(getBundle(), key, params); 28 | } 29 | 30 | // Cached loading 31 | private static ResourceBundle getBundle() { 32 | ResourceBundle bundle = SoftReference.dereference(instance); 33 | if (bundle == null) { 34 | bundle = ResourceBundle.getBundle(BUNDLE); 35 | instance = new SoftReference(bundle); 36 | } 37 | return bundle; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/VariableImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref.RobotVariableReference; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.openapi.util.text.StringUtil; 6 | import com.intellij.psi.PsiReference; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * @author mrubino 11 | * @since 2015-07-15 12 | */ 13 | public class VariableImpl extends RobotPsiElementBase implements Variable { 14 | 15 | public VariableImpl(@NotNull final ASTNode node) { 16 | super(node); 17 | } 18 | 19 | @Override 20 | public PsiReference getReference() { 21 | return new RobotVariableReference(this); 22 | } 23 | 24 | @Override 25 | public boolean isNested() { 26 | // TODO: this should become a check if the parent is a variable or a variable definition once we identify the nesting correctly 27 | String text = getPresentableText(); 28 | return StringUtil.getOccurrenceCount(text, "}") > 1 && 29 | (StringUtil.getOccurrenceCount(text, "${") + StringUtil.getOccurrenceCount(text, "@{") + StringUtil.getOccurrenceCount(text, "%{") > 1); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.run/Run Plugin Verification.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 25 | 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/RobotFile.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.intellij.psi.PsiFile; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Collection; 8 | 9 | /** 10 | * @author Stephen Abrams 11 | */ 12 | public interface RobotFile extends PsiFile { 13 | 14 | /** 15 | * @return locally defined keywords. 16 | */ 17 | @NotNull 18 | Collection getDefinedKeywords(); 19 | 20 | /** 21 | * @return all files that contain references to invoked keywords and used variables. 22 | */ 23 | @NotNull 24 | Collection getFilesFromInvokedKeywordsAndVariables(); 25 | 26 | /** 27 | * Gets all the imported keyword files that are considered in scope for this file. This 28 | * includes python libraries and robot resource files. 29 | * 30 | * @return a collection of keyword files that this files knows about. 31 | */ 32 | @NotNull 33 | Collection getImportedFiles(boolean includeTransitive); 34 | 35 | @NotNull 36 | Collection getDefinedVariables(); 37 | 38 | void importsChanged(); 39 | 40 | @NotNull 41 | Collection getKeywordReferences(@Nullable KeywordDefinition definition); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RecommendationWord.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * @author mrubino 7 | * @since 2014-02-16 8 | */ 9 | public class RecommendationWord { 10 | 11 | private final String presentation; 12 | private final String lookup; 13 | 14 | public RecommendationWord(@NotNull String presentation, @NotNull String lookup) { 15 | this.presentation = presentation; 16 | this.lookup = lookup; 17 | } 18 | 19 | @NotNull 20 | public String getPresentation() { 21 | return this.presentation; 22 | } 23 | 24 | @NotNull 25 | public String getLookup() { 26 | return this.lookup; 27 | } 28 | 29 | @Override 30 | public boolean equals(Object o) { 31 | if (this == o) return true; 32 | if (o == null || getClass() != o.getClass()) return false; 33 | 34 | RecommendationWord that = (RecommendationWord) o; 35 | 36 | if (!this.lookup.equals(that.lookup)) return false; 37 | //noinspection RedundantIfStatement 38 | if (!this.presentation.equals(that.presentation)) return false; 39 | 40 | return true; 41 | } 42 | 43 | @Override 44 | public int hashCode() { 45 | int result = this.presentation.hashCode(); 46 | result = 31 * result + this.lookup.hashCode(); 47 | return result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/ref/RobotVariableReference.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiFile; 5 | import com.intellij.psi.PsiReferenceBase; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.config.RobotOptionsProvider; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Variable; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * @author Scott Albertine 13 | */ 14 | public class RobotVariableReference extends PsiReferenceBase { 15 | 16 | public RobotVariableReference(@NotNull Variable element) { 17 | super(element, false); 18 | } 19 | 20 | @Nullable 21 | @Override 22 | public PsiElement resolve() { 23 | String text = getElement().getPresentableText(); 24 | PsiElement parent = getElement().getParent(); 25 | PsiElement results = ResolverUtils.resolveVariableFromStatement(text, parent, 26 | RobotOptionsProvider.getInstance(getElement().getProject()).allowGlobalVariables()); 27 | if (results != null) { 28 | return results; 29 | } 30 | PsiFile file = getElement().getContainingFile(); 31 | return ResolverUtils.resolveVariableFromFile(text, file); 32 | } 33 | 34 | @NotNull 35 | @Override 36 | public Object[] getVariants() { 37 | return EMPTY_ARRAY; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/ref/RobotKeywordReference.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiReferenceBase; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordInvokable; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceCollector; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceEntity; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * @author mrubino 13 | */ 14 | public class RobotKeywordReference extends PsiReferenceBase { 15 | 16 | public RobotKeywordReference(@NotNull KeywordInvokable element) { 17 | super(element, false); 18 | } 19 | 20 | @Nullable 21 | @Override 22 | public PsiElement resolve() { 23 | KeywordInvokable element = getElement(); 24 | String keyword = element.getPresentableText(); 25 | // all files we import are based off the file we are currently in 26 | // TODO: potentially unsafe cast 27 | PerformanceCollector debug = new PerformanceCollector((PerformanceEntity) element, "resolve"); 28 | PsiElement results = ResolverUtils.resolveKeywordFromFile(keyword, element.getContainingFile()); 29 | debug.complete(); 30 | return results; 31 | } 32 | 33 | @NotNull 34 | @Override 35 | public Object[] getVariants() { 36 | return EMPTY_ARRAY; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/SimpleRobotInspection.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections; 2 | 3 | import com.intellij.codeInspection.LocalInspectionTool; 4 | import com.intellij.codeInspection.LocalInspectionToolSession; 5 | import com.intellij.codeInspection.ProblemsHolder; 6 | import com.intellij.psi.PsiElementVisitor; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 8 | import org.jetbrains.annotations.Nls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * @author mrubino 13 | * @since 2014-06-07 14 | */ 15 | public abstract class SimpleRobotInspection extends LocalInspectionTool implements SimpleInspection { 16 | 17 | @Nls 18 | @NotNull 19 | @Override 20 | public String getGroupDisplayName() { 21 | return RobotBundle.message(getGroupNameKey()); 22 | } 23 | 24 | @NotNull 25 | protected abstract String getGroupNameKey(); 26 | 27 | @NotNull 28 | @Override 29 | public String getShortName() { 30 | return getClass().getSimpleName(); 31 | } 32 | 33 | @Override 34 | public boolean isEnabledByDefault() { 35 | return true; 36 | } 37 | 38 | @NotNull 39 | @Override 40 | public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, 41 | boolean isOnTheFly, 42 | @NotNull LocalInspectionToolSession session) { 43 | return new SimpleInspectionVisitor(holder, this); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/complexity/RobotNestedVariable.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.complexity; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleRobotInspection; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotTokenTypes; 6 | import com.intellij.psi.PsiElement; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Variable; 8 | import org.jetbrains.annotations.Nls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * @author mrubino 13 | * @since 2015-08-24 14 | */ 15 | public class RobotNestedVariable extends SimpleRobotInspection { 16 | 17 | @Nls 18 | @NotNull 19 | @Override 20 | public String getDisplayName() { 21 | return RobotBundle.message("INSP.NAME.variable.nested"); 22 | } 23 | 24 | @Override 25 | public boolean skip(PsiElement element) { 26 | if (element.getNode().getElementType() != RobotTokenTypes.VARIABLE) { 27 | return true; 28 | } 29 | PsiElement parent = element.getParent(); 30 | return !(parent instanceof Variable) || !((Variable) parent).isNested(); 31 | } 32 | 33 | @Override 34 | public String getMessage() { 35 | return RobotBundle.message("INSP.variable.nested"); 36 | } 37 | 38 | @NotNull 39 | @Override 40 | protected String getGroupNameKey() { 41 | return "INSP.GROUP.complexity"; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/util/PerformanceCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.util; 2 | 3 | import com.intellij.notification.*; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.config.RobotOptionsProvider; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * @author mrubino 9 | * @since 2014-06-26 10 | */ 11 | public class PerformanceCollector { 12 | 13 | private static final String MILLISECONDS = "ms"; 14 | private static final long MINIMUM = 500; 15 | 16 | private final String context; 17 | private final PerformanceEntity entity; 18 | private final long start; 19 | 20 | public PerformanceCollector(@NotNull PerformanceEntity entity, @NotNull String context) { 21 | this.entity = entity; 22 | this.context = context; 23 | this.start = System.currentTimeMillis(); 24 | NotificationsConfiguration.getNotificationsConfiguration().register( 25 | "intellibot.debug", NotificationDisplayType.NONE); 26 | } 27 | 28 | public void complete() { 29 | if (RobotOptionsProvider.getInstance(this.entity.getProject()).isDebug()) { 30 | long duration = System.currentTimeMillis() - this.start; 31 | if (duration > MINIMUM) { 32 | String message = String.format("[%s][%s][%s] %d%s", 33 | this.entity.getDebugFileName(), this.context, this.entity.getDebugText(), duration, MILLISECONDS); 34 | Notifications.Bus.notify(new Notification("intellibot.debug", "Debug", message, NotificationType.INFORMATION)); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotTokenTypes.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.intellij.psi.tree.IFileElementType; 4 | import com.intellij.psi.tree.IStubFileElementType; 5 | 6 | public interface RobotTokenTypes { 7 | 8 | IFileElementType FILE = new IStubFileElementType<>(RobotLanguage.INSTANCE); 9 | RobotElementType HEADING = new RobotElementType("HEADING"); 10 | RobotElementType SETTING = new RobotElementType("SETTING"); 11 | RobotElementType BRACKET_SETTING = new RobotElementType("BRACKET_SETTING"); 12 | RobotElementType IMPORT = new RobotElementType("IMPORT"); 13 | RobotElementType KEYWORD_DEFINITION = new RobotElementType("KEYWORD_DEFINITION"); 14 | RobotElementType KEYWORD_DEFINITION_ID = new RobotElementType("KEYWORD_DEFINITION_ID"); 15 | RobotElementType KEYWORD = new RobotElementType("KEYWORD"); 16 | RobotElementType ARGUMENT = new RobotElementType("ARGUMENT"); 17 | RobotElementType VARIABLE_DEFINITION = new RobotElementType("VARIABLE_DEFINITION"); 18 | RobotElementType VARIABLE_DEFINITION_ID = new RobotElementType("VARIABLE_DEFINITION_ID"); 19 | RobotElementType VARIABLE = new RobotElementType("VARIABLE"); 20 | RobotElementType COMMENT = new RobotElementType("COMMENT"); 21 | RobotElementType GHERKIN = new RobotElementType("GHERKIN"); 22 | RobotElementType SYNTAX_MARKER = new RobotElementType("SYNTAX_MARKER"); 23 | RobotElementType KEYWORD_STATEMENT = new RobotElementType("KEYWORD_STATEMENT"); 24 | 25 | RobotElementType ERROR = new RobotElementType("ERROR"); 26 | RobotElementType WHITESPACE = new RobotElementType("WHITESPACE"); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/compilation/RobotKeywordNotFound.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.compilation; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleRobotInspection; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordStatement; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiReference; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordInvokable; 9 | import org.jetbrains.annotations.Nls; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.Arrays; 13 | 14 | /** 15 | * @author mrubino 16 | * @since 2014-06-07 17 | */ 18 | public class RobotKeywordNotFound extends SimpleRobotInspection { 19 | 20 | @Nls 21 | @NotNull 22 | @Override 23 | public String getDisplayName() { 24 | return RobotBundle.message("INSP.NAME.keyword.undefined"); 25 | } 26 | 27 | @Override 28 | public boolean skip(PsiElement element) { 29 | if (element instanceof KeywordInvokable) { 30 | PsiReference reference = element.getReference(); 31 | if (reference != null && reference.resolve() != null) { 32 | return true; 33 | } 34 | } 35 | return true; 36 | } 37 | 38 | @Override 39 | public String getMessage() { 40 | return RobotBundle.message("INSP.keyword.undefined"); 41 | } 42 | 43 | @NotNull 44 | @Override 45 | protected String getGroupNameKey() { 46 | return "INSP.GROUP.compilation"; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/util/PatternBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.util; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | public class PatternBuilder { 9 | private static final Pattern PATTERN = Pattern.compile("(.*?)(\\$\\{.*?\\})(.*)"); 10 | private static final String ANY = ".*?"; 11 | private static final String DOT = "."; 12 | 13 | @NotNull 14 | static private String parseFunction(@NotNull String keyword) { 15 | Matcher matcher = PATTERN.matcher(keyword); 16 | String result = ""; 17 | if (matcher.matches()) { 18 | String start = matcher.group(1); 19 | String end = parseFunction(matcher.group(3)); 20 | 21 | if (start.length() > 0) { 22 | result = Pattern.quote(start); 23 | } 24 | result += ANY; 25 | if (end.length() > 0) { 26 | result += end; 27 | } 28 | } else { 29 | result = !keyword.isEmpty() ? Pattern.quote(keyword) : keyword; 30 | } 31 | return result; 32 | } 33 | 34 | @NotNull 35 | static private String parseNamespace(@NotNull String namespace) { 36 | String result = ""; 37 | if (!namespace.isEmpty()) { 38 | result = "(" + Pattern.quote(namespace + DOT) + ")?"; 39 | } 40 | return result; 41 | } 42 | 43 | 44 | @NotNull 45 | static public String parseNamespaceKeyword(@NotNull String namespace, @NotNull String keyword) { 46 | return parseNamespace(namespace) + parseFunction(keyword); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/complexity/RobotNestedVariableDefinition.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.complexity; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleRobotInspection; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotTokenTypes; 6 | import com.intellij.psi.PsiElement; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.VariableDefinition; 8 | import org.jetbrains.annotations.Nls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * @author mrubino 13 | * @since 2015-08-24 14 | * TODO: this should go away once we identify the nesting correctly 15 | */ 16 | public class RobotNestedVariableDefinition extends SimpleRobotInspection { 17 | 18 | @Nls 19 | @NotNull 20 | @Override 21 | public String getDisplayName() { 22 | return RobotBundle.message("INSP.NAME.variableDefinition.nested"); 23 | } 24 | 25 | @Override 26 | public boolean skip(PsiElement element) { 27 | if (element.getNode().getElementType() != RobotTokenTypes.VARIABLE_DEFINITION) { 28 | return true; 29 | } 30 | PsiElement parent = element.getParent(); 31 | return !(parent instanceof VariableDefinition) || !((VariableDefinition) parent).isNested(); 32 | } 33 | 34 | @Override 35 | public String getMessage() { 36 | return RobotBundle.message("INSP.variableDefinition.nested"); 37 | } 38 | 39 | @NotNull 40 | @Override 41 | protected String getGroupNameKey() { 42 | return "INSP.GROUP.complexity"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/structure/RobotTypeFilter.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.structure; 2 | 3 | import com.intellij.ide.util.treeView.smartTree.ActionPresentation; 4 | import com.intellij.ide.util.treeView.smartTree.ActionPresentationData; 5 | import com.intellij.ide.util.treeView.smartTree.Filter; 6 | import com.intellij.ide.util.treeView.smartTree.TreeElement; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * @author mrubino 11 | * @since 2015-12-15 12 | */ 13 | class RobotTypeFilter implements Filter { 14 | 15 | @NotNull 16 | private final String name; 17 | @NotNull 18 | private final RobotViewElementType type; 19 | 20 | RobotTypeFilter(@NotNull String name, @NotNull RobotViewElementType type) { 21 | this.name = name; 22 | this.type = type; 23 | } 24 | 25 | @Override 26 | public boolean isVisible(TreeElement treeElement) { 27 | if (treeElement instanceof RobotStructureViewElement) { 28 | RobotViewElementType type = ((RobotStructureViewElement) treeElement).getType(); 29 | return this.type != type; 30 | } 31 | return false; 32 | } 33 | 34 | @Override 35 | public boolean isReverted() { 36 | return true; 37 | } 38 | 39 | @NotNull 40 | @Override 41 | public ActionPresentation getPresentation() { 42 | return new ActionPresentationData( 43 | this.type.getMessage(), 44 | null, 45 | this.type.getIcon(null) 46 | ); 47 | } 48 | 49 | @NotNull 50 | @Override 51 | public String getName() { 52 | return this.name; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return this.getName(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/usage/RobotKeywordGroupingRuleProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.usage; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.util.PsiTreeUtil; 6 | import com.intellij.usages.PsiNamedElementUsageGroupBase; 7 | import com.intellij.usages.Usage; 8 | import com.intellij.usages.UsageGroup; 9 | import com.intellij.usages.impl.FileStructureGroupRuleProvider; 10 | import com.intellij.usages.rules.PsiElementUsage; 11 | import com.intellij.usages.rules.UsageGroupingRule; 12 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordDefinitionImpl; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | /** 17 | * @author mrubino 18 | * @since 2016-01-28 19 | */ 20 | public class RobotKeywordGroupingRuleProvider implements FileStructureGroupRuleProvider { 21 | 22 | @Nullable 23 | @Override 24 | public UsageGroupingRule getUsageGroupingRule(@NotNull Project project) { 25 | return new RobotKeywordGroupingRule(); 26 | } 27 | 28 | private static class RobotKeywordGroupingRule implements UsageGroupingRule { 29 | 30 | private RobotKeywordGroupingRule() { 31 | } 32 | 33 | public UsageGroup groupUsage(@NotNull Usage usage) { 34 | if (!(usage instanceof PsiElementUsage)) { 35 | return null; 36 | } else { 37 | PsiElement psiElement = ((PsiElementUsage) usage).getElement(); 38 | KeywordDefinitionImpl definition = PsiTreeUtil.getParentOfType(psiElement, KeywordDefinitionImpl.class, false); 39 | return definition == null ? null : new PsiNamedElementUsageGroupBase<>(definition); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HyperRobotFrameworkPlugin 2 | 3 | Robot Framework plugin for PyCharm. 4 | 5 | ❤️ If you like this plugin, please leave your [review](https://plugins.jetbrains.com/plugin/16382-hyper-robotframework-support/reviews/new) with five ⭐ stars, also, please ⭐ star my github [project](https://github.com/jnhyperion/HyperRobotFrameworkPlugin) 🙏. 6 | 7 | ## Features 8 | ### Syntax Highlighting 9 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/syntax_highlighting.png) 10 | ### Code Completion 11 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/auto_suggestion.png) 12 | ### Easy Test Execution 13 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/cases_execution.png) 14 | ### Debugging In Python Code 15 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/debug.png) 16 | ### Keyword Navigation 17 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/keyword_navigation.png) 18 | ### Find Keyword Usages 19 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/find_keyword_usages.png) 20 | ### Robot File Structure And Folding 21 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/file_structure_and_folding.png) 22 | ### Code Inspection 23 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/code_inspection.png) 24 | 25 | ## Prerequisites 26 | * Set your `Python` interpreter properly for your `PyCharm` 27 | 28 | ## Report Issues 29 | * https://github.com/jnhyperion/HyperRobotFrameworkPlugin/issues 30 | 31 | 32 | 33 | ## Buy Me A Coffee 34 | ![](https://raw.githubusercontent.com/jnhyperion/HyperRobotFrameworkPlugin/main/docs/imgs/qr.png) 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotKeywordTable.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.*; 6 | 7 | public class RobotKeywordTable { 8 | 9 | private final Map> syntaxByType = new HashMap>(); 10 | private final Map> recommendationsByType = new HashMap<>(); 11 | 12 | public void addSyntax(RobotElementType type, String keyword) { 13 | Set keywords = this.syntaxByType.get(type); 14 | if (keywords == null) { 15 | if (type == RobotTokenTypes.GHERKIN) { 16 | // this allows syntax for WHEN vs When vs when 17 | keywords = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); 18 | } else { 19 | keywords = new HashSet<>(); 20 | } 21 | this.syntaxByType.put(type, keywords); 22 | } 23 | keywords.add(keyword); 24 | } 25 | 26 | public void addRecommendation(@NotNull RobotElementType type, @NotNull String keyword, @NotNull String lookup) { 27 | Set keywords = this.recommendationsByType.get(type); 28 | if (keywords == null) { 29 | keywords = new HashSet<>(); 30 | this.recommendationsByType.put(type, keywords); 31 | } 32 | keywords.add(new RecommendationWord(keyword, lookup)); 33 | } 34 | 35 | @NotNull 36 | public Set getSyntaxOfType(RobotElementType type) { 37 | Set results = this.syntaxByType.get(type); 38 | return results == null ? Collections.emptySet() : results; 39 | } 40 | 41 | @NotNull 42 | public Set getRecommendationsForType(RobotElementType type) { 43 | Set results = this.recommendationsByType.get(type); 44 | return results == null ? Collections.emptySet() : results; 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/structure/RobotTypeSorter.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.structure; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.ide.util.treeView.smartTree.ActionPresentation; 5 | import com.intellij.ide.util.treeView.smartTree.ActionPresentationData; 6 | import com.intellij.ide.util.treeView.smartTree.Sorter; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.util.Comparator; 11 | 12 | /** 13 | * @author mrubino 14 | * @since 2015-12-15 15 | */ 16 | public class RobotTypeSorter implements Sorter { 17 | 18 | private static final RobotTypeSorter INSTANCE = new RobotTypeSorter(); 19 | 20 | public static Sorter getInstance() { 21 | return INSTANCE; 22 | } 23 | 24 | @Override 25 | public Comparator getComparator() { 26 | return new Comparator() { 27 | public int compare(Object o1, Object o2) { 28 | if (o1 instanceof RobotStructureViewElement && o2 instanceof RobotStructureViewElement) { 29 | return Integer.compare( 30 | ((RobotStructureViewElement) o1).getType().ordinal(), 31 | ((RobotStructureViewElement) o2).getType().ordinal() 32 | ); 33 | 34 | } 35 | return 0; 36 | } 37 | }; 38 | } 39 | 40 | @Override 41 | public boolean isVisible() { 42 | return true; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return this.getName(); 48 | } 49 | 50 | @NotNull 51 | @Override 52 | public ActionPresentation getPresentation() { 53 | return new ActionPresentationData(RobotBundle.message("action.structureView.sort.type"), 54 | null, AllIcons.ObjectBrowser.SortByType); 55 | } 56 | 57 | @NotNull 58 | @Override 59 | public String getName() { 60 | return "ROBOT_TYPE_COMPARATOR"; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/compilation/RobotImportNotFound.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.compilation; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleRobotInspection; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotTokenTypes; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiReference; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Import; 9 | import org.jetbrains.annotations.Nls; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | /** 13 | * @author mrubino 14 | * @since 2014-06-07 15 | */ 16 | public class RobotImportNotFound extends SimpleRobotInspection { 17 | 18 | @Nls 19 | @NotNull 20 | @Override 21 | public String getDisplayName() { 22 | return RobotBundle.message("INSP.NAME.import.undefined"); 23 | } 24 | 25 | @Override 26 | public boolean skip(PsiElement element) { 27 | if (element.getNode().getElementType() != RobotTokenTypes.ARGUMENT) { 28 | return true; 29 | } 30 | PsiElement parent = element.getParent(); 31 | if (parent instanceof Import) { 32 | PsiElement[] children = parent.getChildren(); 33 | // first child seems to be different than this 34 | if (children.length > 0 && children[0] == element) { 35 | PsiReference reference = element.getReference(); 36 | return reference != null && reference.resolve() != null; 37 | } else { 38 | return true; 39 | } 40 | 41 | } else { 42 | return true; 43 | } 44 | } 45 | 46 | @Override 47 | public String getMessage() { 48 | return RobotBundle.message("INSP.import.undefined"); 49 | } 50 | 51 | @NotNull 52 | @Override 53 | protected String getGroupNameKey() { 54 | return "INSP.GROUP.compilation"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/readability/RobotKeywordDefinitionStartingWithGherkin.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.readability; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleRobotInspection; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotKeywordProvider; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotTokenTypes; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordDefinition; 8 | import com.intellij.psi.PsiElement; 9 | import org.jetbrains.annotations.Nls; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.Collection; 13 | 14 | /** 15 | * @author mrubino 16 | * @since 2014-06-07 17 | */ 18 | public class RobotKeywordDefinitionStartingWithGherkin extends SimpleRobotInspection { 19 | 20 | @Nls 21 | @NotNull 22 | @Override 23 | public String getDisplayName() { 24 | return RobotBundle.message("INSP.NAME.define.keyword.gherkin.start"); 25 | } 26 | 27 | @Override 28 | public boolean skip(PsiElement element) { 29 | return !(element instanceof KeywordDefinition) || valid(((KeywordDefinition) element).getPresentableText()); 30 | } 31 | 32 | private boolean valid(String text) { 33 | Collection gherkin = RobotKeywordProvider.getInstance().getSyntaxOfType(RobotTokenTypes.GHERKIN); 34 | int firstSpace = text.indexOf(" "); 35 | 36 | String word; 37 | if (firstSpace < 0) { 38 | word = text; 39 | } else { 40 | word = text.substring(0, firstSpace); 41 | } 42 | return !gherkin.contains(word); 43 | } 44 | 45 | @Override 46 | public String getMessage() { 47 | return RobotBundle.message("INSP.define.keyword.gherkin.start"); 48 | } 49 | 50 | @NotNull 51 | @Override 52 | protected String getGroupNameKey() { 53 | return "INSP.GROUP.readability"; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for handling the release process based on the draft release prepared 2 | # with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided. 3 | 4 | name: Release 5 | on: 6 | release: 7 | types: [prereleased, released] 8 | 9 | jobs: 10 | 11 | # Prepare and publish the plugin to the Marketplace repository 12 | release: 13 | name: Publish Plugin 14 | runs-on: ubuntu-latest 15 | steps: 16 | 17 | # Setup Java 1.8 environment for the next steps 18 | - name: Setup Java 19 | uses: actions/setup-java@v1 20 | with: 21 | java-version: 1.8 22 | 23 | # Check out current repository 24 | - name: Fetch Sources 25 | uses: actions/checkout@v2 26 | with: 27 | ref: ${{ github.event.release.tag_name }} 28 | 29 | # Publish the plugin to the Marketplace 30 | - name: Publish Plugin 31 | env: 32 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 33 | run: ./gradlew publishPlugin 34 | 35 | # Patch changelog, commit and push to the current repository 36 | changelog: 37 | name: Update Changelog 38 | needs: release 39 | runs-on: ubuntu-latest 40 | steps: 41 | 42 | # Setup Java 1.8 environment for the next steps 43 | - name: Setup Java 44 | uses: actions/setup-java@v1 45 | with: 46 | java-version: 1.8 47 | 48 | # Check out current repository 49 | - name: Fetch Sources 50 | uses: actions/checkout@v2 51 | with: 52 | ref: ${{ github.event.release.tag_name }} 53 | 54 | # Update Unreleased section with the current version 55 | - name: Patch Changelog 56 | run: ./gradlew patchChangelog 57 | 58 | # Commit patched Changelog 59 | - name: Commit files 60 | run: | 61 | git config --local user.email "action@github.com" 62 | git config --local user.name "GitHub Action" 63 | git commit -m "Update changelog" -a 64 | 65 | # Push changes 66 | - name: Push changes 67 | uses: ad-m/github-push-action@master 68 | with: 69 | branch: main 70 | github_token: ${{ secrets.GITHUB_TOKEN }} 71 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/dto/KeywordDto.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedKeyword; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PatternBuilder; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PatternUtil; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.regex.Pattern; 10 | 11 | /** 12 | * This acts as a wrapper for python definitions. 13 | * 14 | * @author mrubino 15 | * @since 2014-06-06 16 | */ 17 | public class KeywordDto implements DefinedKeyword { 18 | 19 | 20 | 21 | private final PsiElement reference; 22 | private final String name; 23 | private final boolean args; 24 | private final Pattern namePattern; 25 | 26 | public KeywordDto(@NotNull PsiElement reference, @NotNull String namespace, @NotNull String name, boolean args) { 27 | this.reference = reference; 28 | this.name = PatternUtil.functionToKeyword(name).trim(); 29 | this.namePattern = Pattern.compile(PatternBuilder.parseNamespaceKeyword(namespace, this.name), Pattern.CASE_INSENSITIVE); 30 | this.args = args; 31 | } 32 | 33 | @Override 34 | public String getKeywordName() { 35 | return this.name; 36 | } 37 | 38 | @Override 39 | public boolean hasArguments() { 40 | return this.args; 41 | } 42 | 43 | @Override 44 | public boolean matches(String text) { 45 | return text != null && 46 | this.namePattern.matcher(PatternUtil.functionToKeyword(text).trim()).matches(); 47 | } 48 | 49 | @Override 50 | public PsiElement reference() { 51 | return this.reference; 52 | } 53 | 54 | @Override 55 | public boolean equals(Object o) { 56 | if (this == o) return true; 57 | if (o == null || getClass() != o.getClass()) return false; 58 | 59 | KeywordDto that = (KeywordDto) o; 60 | 61 | // I am not sure if we care about arguments in terms of uniqueness here 62 | return this.name.equals(that.name); 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return this.name.hashCode(); 68 | } 69 | 70 | @Override 71 | public String toString() { 72 | return this.name; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/RobotPsiElementBase.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PatternUtil; 4 | import com.intellij.extapi.psi.ASTWrapperPsiElement; 5 | import com.intellij.lang.ASTNode; 6 | import com.intellij.navigation.ItemPresentation; 7 | import com.intellij.openapi.util.Iconable; 8 | import com.intellij.psi.PsiElement; 9 | import com.intellij.util.IncorrectOperationException; 10 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceEntity; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import javax.swing.*; 14 | 15 | /** 16 | * @author Stephen Abrams 17 | */ 18 | public abstract class RobotPsiElementBase extends ASTWrapperPsiElement implements PerformanceEntity, RobotStatement { 19 | 20 | public RobotPsiElementBase(@NotNull final ASTNode node) { 21 | super(node); 22 | } 23 | 24 | @NotNull 25 | private static String toPresentableText(ASTNode node) { 26 | return PatternUtil.getPresentableText(node.getText()); 27 | } 28 | 29 | @Override 30 | public ItemPresentation getPresentation() { 31 | return new ItemPresentation() { 32 | public String getPresentableText() { 33 | return RobotPsiElementBase.this.getPresentableText(); 34 | } 35 | 36 | public String getLocationString() { 37 | return null; 38 | } 39 | 40 | public Icon getIcon(final boolean open) { 41 | return RobotPsiElementBase.this.getIcon(Iconable.ICON_FLAG_VISIBILITY); 42 | } 43 | }; 44 | } 45 | 46 | @NotNull 47 | @Override 48 | public String getPresentableText() { 49 | return toPresentableText(getNode()); 50 | } 51 | 52 | @NotNull 53 | @Override 54 | public String getDebugFileName() { 55 | return getContainingFile().getVirtualFile().getName(); 56 | } 57 | 58 | @NotNull 59 | @Override 60 | public String getDebugText() { 61 | return getPresentableText(); 62 | } 63 | 64 | @NotNull 65 | public String getName() { 66 | return getPresentableText(); 67 | } 68 | 69 | public PsiElement setName(@NotNull String var1) throws IncorrectOperationException { 70 | // TODO: for renaming an element 71 | return this; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/dto/VariableDto.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedVariable; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PatternUtil; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.ReservedVariableScope; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.regex.Pattern; 11 | 12 | /** 13 | * @author mrubino 14 | * @since 2014-06-18 15 | */ 16 | public class VariableDto implements DefinedVariable { 17 | 18 | private final PsiElement reference; 19 | private final String name; 20 | private final ReservedVariableScope scope; 21 | private Pattern pattern; 22 | 23 | public VariableDto(@NotNull PsiElement reference, @NotNull String name, @Nullable ReservedVariableScope scope) { 24 | this.reference = reference; 25 | this.name = name.trim(); 26 | this.scope = scope; 27 | } 28 | 29 | @Override 30 | public boolean matches(@Nullable String text) { 31 | if (text == null) { 32 | return false; 33 | } 34 | Pattern pattern = this.pattern; 35 | if (pattern == null) { 36 | pattern = Pattern.compile(PatternUtil.getVariablePattern(this.name), Pattern.CASE_INSENSITIVE); 37 | this.pattern = pattern; 38 | } 39 | return pattern.matcher(text).matches(); 40 | } 41 | 42 | @Override 43 | public boolean isInScope(@Nullable PsiElement position) { 44 | return this.scope == null || position == null || this.scope.isInScope(position); 45 | } 46 | 47 | @Nullable 48 | @Override 49 | public PsiElement reference() { 50 | return this.reference; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getLookup() { 56 | return this.scope == null ? this.reference.getText() : this.name; 57 | } 58 | 59 | @Override 60 | public boolean equals(Object o) { 61 | if (this == o) return true; 62 | if (o == null || getClass() != o.getClass()) return false; 63 | 64 | VariableDto that = (VariableDto) o; 65 | return this.name.equals(that.name); 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return this.name.hashCode(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/execution/RobotRunLineMarkerProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.execution; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotFeatureFileType; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedKeyword; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Heading; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordDefinitionImpl; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.RobotFileImpl; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.RobotUtil; 9 | import com.intellij.execution.lineMarker.ExecutorAction; 10 | import com.intellij.execution.lineMarker.RunLineMarkerContributor; 11 | import com.intellij.icons.AllIcons; 12 | import com.intellij.openapi.actionSystem.AnAction; 13 | import com.intellij.psi.PsiElement; 14 | import com.intellij.psi.PsiFile; 15 | import com.intellij.psi.impl.source.tree.LeafElement; 16 | import org.jetbrains.annotations.NotNull; 17 | import org.jetbrains.annotations.Nullable; 18 | 19 | import java.util.Collection; 20 | import java.util.LinkedHashSet; 21 | 22 | import static com.intellij.openapi.util.text.StringUtil.join; 23 | import static com.intellij.util.containers.ContainerUtil.mapNotNull; 24 | 25 | public class RobotRunLineMarkerProvider extends RunLineMarkerContributor { 26 | 27 | @Override 28 | public @Nullable Info getInfo(@NotNull PsiElement element) { 29 | if (element.getContainingFile().getVirtualFile().getFileType() instanceof RobotFeatureFileType) { 30 | PsiElement targetElement = element.getParent().getParent(); 31 | if (element instanceof LeafElement && 32 | targetElement instanceof KeywordDefinitionImpl) { 33 | Collection testCases = RobotUtil.getTestCasesFromElement(element); 34 | for (DefinedKeyword testCase: testCases) { 35 | if (testCase.getKeywordName().equals(element.getText())) { 36 | final AnAction[] actions = ExecutorAction.getActions(); 37 | return new Info(AllIcons.RunConfigurations.TestState.Run, actions, 38 | e -> join(mapNotNull(actions, action -> getText(action, e)), "\n")); 39 | } 40 | } 41 | } 42 | } 43 | return null; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/VariableDefinitionImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.icons.RobotIcons; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PatternUtil; 5 | import com.intellij.lang.ASTNode; 6 | import com.intellij.openapi.util.text.StringUtil; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiNameIdentifierOwner; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import javax.swing.*; 14 | import java.util.regex.Pattern; 15 | 16 | /** 17 | * @author mrubino 18 | */ 19 | public class VariableDefinitionImpl extends RobotPsiElementBase implements VariableDefinition, DefinedVariable, PsiNameIdentifierOwner { 20 | 21 | private Pattern pattern; 22 | 23 | public VariableDefinitionImpl(@NotNull final ASTNode node) { 24 | super(node); 25 | } 26 | 27 | @Override 28 | public void subtreeChanged() { 29 | super.subtreeChanged(); 30 | this.pattern = null; 31 | } 32 | 33 | @Override 34 | public boolean matches(String text) { 35 | if (text == null) { 36 | return false; 37 | } 38 | String myText = getPresentableText(); 39 | Pattern pattern = this.pattern; 40 | if (pattern == null) { 41 | pattern = Pattern.compile(PatternUtil.getVariablePattern(myText), Pattern.CASE_INSENSITIVE); 42 | this.pattern = pattern; 43 | } 44 | return pattern.matcher(text).matches(); 45 | } 46 | 47 | @Override 48 | public boolean isInScope(@Nullable PsiElement position) { 49 | return true; 50 | } 51 | 52 | @Nullable 53 | @Override 54 | public PsiElement reference() { 55 | return this; 56 | } 57 | 58 | @Nullable 59 | @Override 60 | public String getLookup() { 61 | return getText(); 62 | } 63 | 64 | @Override 65 | public boolean isNested() { 66 | String text = getPresentableText(); 67 | return StringUtil.getOccurrenceCount(text, "}") > 1 && 68 | (StringUtil.getOccurrenceCount(text, "${") + StringUtil.getOccurrenceCount(text, "@{") + StringUtil.getOccurrenceCount(text, "%{") > 1); 69 | } 70 | 71 | @Override 72 | @NotNull 73 | public Icon getIcon(int flags) { 74 | return RobotIcons.VARIABLE_DEFINITION; 75 | } 76 | 77 | @Nullable 78 | @Override 79 | public PsiElement getNameIdentifier() { 80 | return PsiTreeUtil.findChildOfType(this, VariableDefinitionId.class); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/resources/messages/RobotBundle.properties: -------------------------------------------------------------------------------- 1 | color.settings.argument=Argument 2 | color.settings.bracketSetting=Bracket Setting 3 | color.settings.comment=Comment 4 | color.settings.error=Error 5 | color.settings.gherkin=Gherkin 6 | color.settings.syntaxMarker=SyntaxMarker 7 | color.settings.heading=Heading 8 | color.settings.import=Import 9 | color.settings.keyword=Keyword 10 | color.settings.keywordDefinition=Keyword Definition 11 | color.settings.setting=Setting 12 | color.settings.variable=Variable 13 | color.settings.variableDefinition=Variable Definition 14 | 15 | # Python Support Warning 16 | plugin.python.missing=If you configure a python interpreter you will be able to get code completion around imported libraries in your robot files. 17 | plugin.python.missing.title=Intellibot: No Python Support for Robot 18 | 19 | # Structure 20 | action.structureView.show.files=Shows Files 21 | action.structureView.show.headings=Show Headings 22 | action.structureView.show.testCases=Show Test Cases 23 | action.structureView.show.keywords=Show Keywords 24 | action.structureView.show.variables=Show Variables 25 | action.structureView.sort.type=Sort by Type 26 | 27 | # Find Usages 28 | usage.declaration=Declaration 29 | usage.descriptive.argument=argument 30 | usage.descriptive.import=resource 31 | usage.descriptive.keyword=keyword 32 | usage.descriptive.variable=variable 33 | 34 | # Inspections 35 | # Inspection Groups 36 | INSP.GROUP.complexity=Complexity 37 | INSP.GROUP.readability=Readability 38 | INSP.GROUP.compilation=Compilation 39 | INSP.GROUP.cleanup=Clean Up 40 | # RobotGherkinInspection 41 | INSP.NAME.gherkin.format=Gherkin format 42 | INSP.gherkin.format=Incorrect gherkin format 43 | INSP.OPT.gherkin.format.upper=Allow all uppercase gherkin 44 | # RobotKeywordDefinitionStartingWithGherkin 45 | INSP.NAME.define.keyword.gherkin.start=Keyword starting with gherkin 46 | INSP.define.keyword.gherkin.start=Keyword starting with gherkin 47 | # RobotKeywordNotFound 48 | INSP.NAME.keyword.undefined=Undefined keyword 49 | INSP.keyword.undefined=Keyword definition not found 50 | # RobotVariableNotFound 51 | INSP.NAME.variable.undefined=Undefined variable 52 | INSP.variable.undefined=Variable definition not found 53 | # RobotImportNotFound 54 | INSP.NAME.import.undefined=Import not found 55 | INSP.import.undefined=Import file not found 56 | # RobotImportNotUsed 57 | INSP.NAME.import.unused=Import not used 58 | INSP.import.unused=Unused import statement 59 | # RobotNestedVariable 60 | INSP.NAME.variable.nested=Nested variable 61 | INSP.variable.nested=Usage of a nested variable 62 | # RobotNestedVariableDefinition 63 | INSP.NAME.variableDefinition.nested=Nested variable definition 64 | INSP.variableDefinition.nested=Usage of a nested variable definition -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/structure/RobotViewElementType.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.structure; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.icons.RobotIcons; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.*; 10 | 11 | /** 12 | * @author mrubino 13 | * @since 2015-12-15 14 | */ 15 | enum RobotViewElementType { 16 | File { 17 | @Nullable 18 | @Override 19 | protected Icon getIcon(@Nullable PsiElement element) { 20 | return element == null ? null : element.getIcon(0); 21 | } 22 | 23 | @NotNull 24 | @Override 25 | protected String getMessage() { 26 | return RobotBundle.message("action.structureView.show.files"); 27 | } 28 | }, 29 | Heading { 30 | @Nullable 31 | @Override 32 | protected Icon getIcon(@Nullable PsiElement element) { 33 | return RobotIcons.HEADING; 34 | } 35 | 36 | @NotNull 37 | @Override 38 | protected String getMessage() { 39 | return RobotBundle.message("action.structureView.show.headings"); 40 | } 41 | }, 42 | TestCase { 43 | @Nullable 44 | @Override 45 | protected Icon getIcon(@Nullable PsiElement element) { 46 | return RobotIcons.TEST_CASE; 47 | } 48 | 49 | @NotNull 50 | @Override 51 | protected String getMessage() { 52 | return RobotBundle.message("action.structureView.show.testCases"); 53 | } 54 | }, 55 | Keyword { 56 | @Nullable 57 | @Override 58 | protected Icon getIcon(@Nullable PsiElement element) { 59 | return RobotIcons.KEYWORD_DEFINITION; 60 | } 61 | 62 | @NotNull 63 | @Override 64 | protected String getMessage() { 65 | return RobotBundle.message("action.structureView.show.keywords"); 66 | } 67 | }, 68 | Variable { 69 | @Nullable 70 | @Override 71 | protected Icon getIcon(@Nullable PsiElement element) { 72 | return RobotIcons.VARIABLE_DEFINITION; 73 | } 74 | 75 | @NotNull 76 | @Override 77 | protected String getMessage() { 78 | return RobotBundle.message("action.structureView.show.variables"); 79 | } 80 | }; 81 | 82 | @Nullable 83 | protected abstract Icon getIcon(@Nullable PsiElement element); 84 | 85 | @NotNull 86 | protected abstract String getMessage(); 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/readability/RobotGherkinInspection.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.readability; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleInspection; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleRobotInspection; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotKeywordProvider; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotTokenTypes; 8 | import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; 9 | import com.intellij.psi.PsiElement; 10 | import org.jetbrains.annotations.Nls; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import javax.swing.*; 14 | import java.util.Collection; 15 | import java.util.HashSet; 16 | 17 | /** 18 | * @author mrubino 19 | * @since 2014-06-07 20 | */ 21 | public class RobotGherkinInspection extends SimpleRobotInspection implements SimpleInspection { 22 | 23 | private static final Collection NORMAL; 24 | private static final Collection UPPER; 25 | 26 | static { 27 | NORMAL = new HashSet(); 28 | UPPER = new HashSet(); 29 | for (String gherkin : RobotKeywordProvider.getInstance().getSyntaxOfType(RobotTokenTypes.GHERKIN)) { 30 | NORMAL.add(gherkin); 31 | UPPER.add(gherkin.toUpperCase()); 32 | } 33 | } 34 | 35 | public boolean allowUppercase = false; 36 | 37 | @Nls 38 | @NotNull 39 | @Override 40 | public String getDisplayName() { 41 | return RobotBundle.message("INSP.NAME.gherkin.format"); 42 | } 43 | 44 | @Override 45 | public JComponent createOptionsPanel() { 46 | MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); 47 | panel.addCheckbox(RobotBundle.message("INSP.OPT.gherkin.format.upper"), "allowUppercase"); 48 | return panel; 49 | } 50 | 51 | @Override 52 | public boolean skip(PsiElement element) { 53 | // this should be getPresentableText if we ever formalize the Gherkin type 54 | return element.getNode().getElementType() != RobotTokenTypes.GHERKIN || 55 | valid(element.getText()); 56 | } 57 | 58 | @Override 59 | public String getMessage() { 60 | return RobotBundle.message("INSP.gherkin.format"); 61 | } 62 | 63 | private boolean valid(String text) { 64 | return NORMAL.contains(text) || (this.allowUppercase && UPPER.contains(text)); 65 | } 66 | 67 | @NotNull 68 | @Override 69 | protected String getGroupNameKey() { 70 | return "INSP.GROUP.readability"; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/config/RobotOptionsProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.config; 2 | 3 | import com.intellij.openapi.components.*; 4 | import com.intellij.openapi.project.Project; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | /** 8 | * @author mrubino 9 | * @since 2014-06-26 10 | */ 11 | @State( 12 | name = "RobotOptionsProvider", 13 | storages = { 14 | @Storage(value = StoragePathMacros.WORKSPACE_FILE) 15 | } 16 | ) 17 | public class RobotOptionsProvider implements PersistentStateComponent { 18 | 19 | public static class State { 20 | public boolean transitiveImports = true; 21 | public boolean globalVariables = true; 22 | public boolean debug = false; 23 | public boolean capitalizeKeywords = true; 24 | public boolean inlineVariableSearch = false; 25 | } 26 | 27 | private final State state = new State(); 28 | 29 | public static RobotOptionsProvider getInstance(Project project) { 30 | return ServiceManager.getService(project, RobotOptionsProvider.class); 31 | } 32 | 33 | @Nullable 34 | @Override 35 | public State getState() { 36 | return this.state; 37 | } 38 | 39 | @Override 40 | public void loadState(State state) { 41 | this.state.debug = state.debug; 42 | this.state.transitiveImports = state.transitiveImports; 43 | this.state.globalVariables = state.globalVariables; 44 | this.state.capitalizeKeywords = state.capitalizeKeywords; 45 | this.state.inlineVariableSearch = state.inlineVariableSearch; 46 | } 47 | 48 | public boolean isDebug() { 49 | return this.state.debug; 50 | } 51 | 52 | public void setDebug(boolean debug) { 53 | this.state.debug = debug; 54 | } 55 | 56 | public boolean allowTransitiveImports() { 57 | return this.state.transitiveImports; 58 | } 59 | 60 | public void setTransitiveImports(boolean transitiveImports) { 61 | this.state.transitiveImports = transitiveImports; 62 | } 63 | 64 | public boolean allowGlobalVariables() { 65 | return this.state.globalVariables; 66 | } 67 | 68 | public void setGlobalVariables(boolean globalVariables) { 69 | this.state.globalVariables = globalVariables; 70 | } 71 | 72 | public boolean capitalizeKeywords() { 73 | return this.state.capitalizeKeywords; 74 | } 75 | 76 | public void setCapitalizeKeywords(boolean capitalizeKeywords) { 77 | this.state.capitalizeKeywords = capitalizeKeywords; 78 | } 79 | 80 | public boolean inlineVariableSearch() { 81 | return this.state.inlineVariableSearch; 82 | } 83 | 84 | public void setInlineVariableSearch(boolean inlineVariableSearch) { 85 | this.state.inlineVariableSearch = inlineVariableSearch; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/usage/RobotFindUsagesProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.usage; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.*; 4 | import com.intellij.lang.cacheBuilder.WordsScanner; 5 | import com.intellij.lang.findUsages.FindUsagesProvider; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiNamedElement; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 9 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.*; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | /** 14 | * @author Stephen Abrams 15 | */ 16 | public class RobotFindUsagesProvider implements FindUsagesProvider { 17 | 18 | @Nullable 19 | @Override 20 | public WordsScanner getWordsScanner() { 21 | return new RobotWordScanner(); 22 | } 23 | 24 | @Override 25 | public boolean canFindUsagesFor(@NotNull PsiElement element) { 26 | if (element instanceof Argument && element.getParent() instanceof Import) { 27 | // if the Argument is the first child of Import, then it is the file reference 28 | // everything else will be covered by Variables 29 | return element == element.getParent().getFirstChild(); 30 | } 31 | return element instanceof PsiNamedElement; 32 | } 33 | 34 | @Nullable 35 | @Override 36 | public String getHelpId(@NotNull PsiElement element) { 37 | return null; 38 | } 39 | 40 | @NotNull 41 | @Override 42 | public String getType(@NotNull PsiElement element) { 43 | return RobotBundle.message("usage.declaration"); 44 | } 45 | 46 | @NotNull 47 | @Override 48 | public String getDescriptiveName(@NotNull PsiElement element) { 49 | // this is what appears in the find usages dialog 50 | if (element instanceof KeywordDefinition) { 51 | return RobotBundle.message("usage.descriptive.keyword"); 52 | } else if (element instanceof VariableDefinition) { 53 | return RobotBundle.message("usage.descriptive.variable"); 54 | } else if (element instanceof RobotFile) { 55 | return RobotBundle.message("usage.descriptive.import"); 56 | } else if (element instanceof Argument) { 57 | return RobotBundle.message("usage.descriptive.argument"); 58 | } 59 | return ""; 60 | } 61 | 62 | @NotNull 63 | @Override 64 | public String getNodeText(@NotNull PsiElement element, boolean useFullName) { 65 | // TODO: if variable definition get value set to variable 66 | return ""; 67 | // if (element instanceof SimpleProperty) { 68 | // return ((SimpleProperty) element).getKey() + ":" + ((SimpleProperty) element).getValue(); 69 | // } else { 70 | // return ""; 71 | // } 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/RobotFoldingBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.lang.folding.FoldingBuilder; 5 | import com.intellij.lang.folding.FoldingDescriptor; 6 | import com.intellij.navigation.ItemPresentation; 7 | import com.intellij.navigation.NavigationItem; 8 | import com.intellij.openapi.editor.Document; 9 | import com.intellij.openapi.project.DumbAware; 10 | import com.intellij.psi.tree.TokenSet; 11 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotTokenTypes; 12 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Heading; 13 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordDefinition; 14 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.RobotStatement; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | 21 | /** 22 | * @author mrubino 23 | */ 24 | public class RobotFoldingBuilder implements FoldingBuilder, DumbAware { 25 | 26 | private static final String ELLIPSIS = "..."; 27 | 28 | private static final TokenSet BLOCKS_TO_FOLD = TokenSet.create(RobotTokenTypes.KEYWORD_DEFINITION, RobotTokenTypes.HEADING); 29 | 30 | @NotNull 31 | public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode node, @NotNull Document document) { 32 | Collection descriptors = new ArrayList(); 33 | appendDescriptors(node, descriptors); 34 | return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); 35 | } 36 | 37 | private void appendDescriptors(ASTNode node, Collection descriptors) { 38 | if (BLOCKS_TO_FOLD.contains(node.getElementType()) && 39 | node.getTextRange().getLength() >= 2 && 40 | node.getPsi() instanceof RobotStatement) { 41 | descriptors.add(new FoldingDescriptor(node, node.getTextRange())); 42 | } 43 | ASTNode child = node.getFirstChildNode(); 44 | while (child != null) { 45 | appendDescriptors(child, descriptors); 46 | child = child.getTreeNext(); 47 | } 48 | } 49 | 50 | @Nullable 51 | public String getPlaceholderText(@NotNull ASTNode node) { 52 | if (node.getPsi() instanceof Heading || 53 | node.getPsi() instanceof KeywordDefinition) { 54 | ItemPresentation presentation = ((NavigationItem) node.getPsi()).getPresentation(); 55 | if (presentation != null) { 56 | return presentation.getPresentableText(); 57 | } 58 | } 59 | return ELLIPSIS; 60 | } 61 | 62 | public boolean isCollapsedByDefault(@NotNull ASTNode node) { 63 | return node.getPsi() instanceof Heading && ((Heading) node.getPsi()).isSettings(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/structure/RobotStructureViewModel.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.structure; 2 | 3 | import com.intellij.ide.structureView.StructureViewModel; 4 | import com.intellij.ide.structureView.StructureViewModelBase; 5 | import com.intellij.ide.structureView.StructureViewTreeElement; 6 | import com.intellij.ide.util.treeView.smartTree.Filter; 7 | import com.intellij.ide.util.treeView.smartTree.Sorter; 8 | import com.intellij.openapi.editor.Editor; 9 | import com.intellij.psi.PsiFile; 10 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordDefinition; 11 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.RobotFile; 12 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.VariableDefinition; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | /** 17 | * @author mrubino 18 | * @since 2015-11-23 19 | */ 20 | public class RobotStructureViewModel extends StructureViewModelBase implements StructureViewModel.ElementInfoProvider, StructureViewModel.ExpandInfoProvider { 21 | 22 | private static final Filter[] FILTERS = new Filter[]{ 23 | new RobotTypeFilter("SHOW_TEST_CASES", RobotViewElementType.TestCase), 24 | new RobotTypeFilter("SHOW_KEYWORDS", RobotViewElementType.Keyword), 25 | new RobotTypeFilter("SHOW_VARIABLES", RobotViewElementType.Variable), 26 | new RobotTypeFilter("SHOW_HEADINGS", RobotViewElementType.Heading) 27 | }; 28 | 29 | public RobotStructureViewModel(@NotNull PsiFile psiFile, @Nullable Editor editor) { 30 | this(psiFile, editor, new RobotStructureViewElement(psiFile)); 31 | withSorters( 32 | Sorter.ALPHA_SORTER, 33 | RobotTypeSorter.getInstance() 34 | ); 35 | } 36 | 37 | public RobotStructureViewModel(@NotNull PsiFile psiFile, @Nullable Editor editor, @NotNull StructureViewTreeElement element) { 38 | super(psiFile, editor, element); 39 | } 40 | 41 | 42 | @Override 43 | public boolean isAlwaysShowsPlus(StructureViewTreeElement element) { 44 | return element.getValue() instanceof RobotFile; 45 | } 46 | 47 | @Override 48 | public boolean isAlwaysLeaf(StructureViewTreeElement element) { 49 | final Object value = element.getValue(); 50 | return value instanceof KeywordDefinition || value instanceof VariableDefinition; 51 | } 52 | 53 | @Override 54 | public boolean shouldEnterElement(Object element) { 55 | return false; 56 | } 57 | 58 | @NotNull 59 | @Override 60 | public Filter[] getFilters() { 61 | return FILTERS; 62 | } 63 | 64 | @Override 65 | public boolean isAutoExpand(@NotNull StructureViewTreeElement element) { 66 | return element.getValue() instanceof RobotFile; 67 | } 68 | 69 | @Override 70 | public boolean isSmartExpand() { 71 | return false; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/compilation/RobotVariableNotFound.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.compilation; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleRobotInspection; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiReference; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Argument; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordInvokable; 9 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordStatement; 10 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Variable; 11 | import org.jetbrains.annotations.Nls; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | /** 18 | * @author mrubino 19 | * @since 2014-06-18 20 | */ 21 | public class RobotVariableNotFound extends SimpleRobotInspection { 22 | 23 | @Nls 24 | @NotNull 25 | @Override 26 | public String getDisplayName() { 27 | return RobotBundle.message("INSP.NAME.variable.undefined"); 28 | } 29 | 30 | @Override 31 | public boolean skip(PsiElement element) { 32 | if (element instanceof Variable) { 33 | PsiReference reference = element.getReference(); 34 | if (reference != null && reference.resolve() != null) { 35 | return true; 36 | } 37 | if (((Variable) element).isNested()) { 38 | // TODO: nested variables 39 | return true; 40 | } 41 | 42 | // TODO: what is needed below this point... 43 | PsiElement container = element.getParent(); 44 | element = container; 45 | if (container instanceof Argument) { 46 | container = container.getParent(); 47 | } 48 | if (container instanceof KeywordStatement) { 49 | // this is the case where we have a 'set test variable' call with more than one arg 50 | // the first is the variable name, the second is the value 51 | // if there is only one argument then we might want to see where it was created 52 | if (((KeywordStatement) container).getGlobalVariable() != null) { 53 | List arguments = ((KeywordStatement) container).getArguments(); 54 | if (arguments.size() > 1 && element == arguments.get(0)) { 55 | return true; 56 | } 57 | } 58 | } 59 | return false; 60 | } else { 61 | return true; 62 | } 63 | } 64 | 65 | @Override 66 | public String getMessage() { 67 | return RobotBundle.message("INSP.variable.undefined"); 68 | } 69 | 70 | @NotNull 71 | @Override 72 | protected String getGroupNameKey() { 73 | return "INSP.GROUP.compilation"; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/inspections/cleanup/RobotImportNotUsed.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.cleanup; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.inspections.SimpleRobotInspection; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotTokenTypes; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiFile; 8 | import com.intellij.psi.PsiReference; 9 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Argument; 10 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Import; 11 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.RobotFile; 12 | import org.jetbrains.annotations.Nls; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.Collection; 16 | 17 | /** 18 | * @author mrubino 19 | * @since 2014-06-07 20 | */ 21 | public class RobotImportNotUsed extends SimpleRobotInspection { 22 | 23 | @Nls 24 | @NotNull 25 | @Override 26 | public String getDisplayName() { 27 | return RobotBundle.message("INSP.NAME.import.unused"); 28 | } 29 | 30 | @Override 31 | public boolean skip(PsiElement element) { 32 | if (element.getNode().getElementType() != RobotTokenTypes.ARGUMENT) { 33 | return true; 34 | } else if (!(element instanceof Argument)) { 35 | return true; 36 | } 37 | PsiFile file = element.getContainingFile(); 38 | if (!(file instanceof RobotFile)) { 39 | return true; 40 | } 41 | 42 | PsiElement parent = element.getParent(); 43 | 44 | if (parent instanceof Import) { 45 | if (!((Import) parent).isResource()) { 46 | // TODO: python libraries 47 | // TODO: variables 48 | return true; 49 | } 50 | PsiElement[] children = parent.getChildren(); 51 | // first child seems to be different than this 52 | if (children.length > 0 && children[0] == element) { 53 | PsiReference reference = element.getReference(); 54 | if (reference == null) { 55 | return true; 56 | } 57 | PsiElement importFile = reference.resolve(); 58 | if (importFile == null) { 59 | return true; // we cannot find the file thus we do not know if we use it 60 | } 61 | 62 | Collection referenced = ((RobotFile) file).getFilesFromInvokedKeywordsAndVariables(); 63 | return referenced.contains(importFile.getContainingFile()); 64 | } else { 65 | return true; 66 | } 67 | } else { 68 | return true; 69 | } 70 | } 71 | 72 | @Override 73 | public String getMessage() { 74 | return RobotBundle.message("INSP.import.unused"); 75 | } 76 | 77 | @NotNull 78 | @Override 79 | protected String getGroupNameKey() { 80 | return "INSP.GROUP.cleanup"; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/ref/RobotArgumentReference.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiReferenceBase; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Argument; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.Import; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordStatement; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceCollector; 9 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceEntity; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | /** 14 | * @author Scott Albertine 15 | */ 16 | public class RobotArgumentReference extends PsiReferenceBase { 17 | 18 | public RobotArgumentReference(@NotNull Argument element) { 19 | super(element, false); 20 | } 21 | 22 | @Nullable 23 | @Override 24 | public PsiElement resolve() { 25 | PsiElement parent = getElement().getParent(); 26 | // TODO: potentially unsafe cast 27 | PerformanceCollector debug = new PerformanceCollector((PerformanceEntity) getElement(), "resolve"); 28 | PsiElement result = null; 29 | // we only want to attempt to resolve a resource/library for the first argument 30 | if (parent instanceof Import) { 31 | PsiElement secondChild = getSecondChild(parent); 32 | if (secondChild == getElement()) { 33 | Import importElement = (Import) parent; 34 | if (importElement.isResource()) { 35 | result = resolveResource(); 36 | } else if (importElement.isLibrary() || importElement.isVariables()) { 37 | result = resolveLibrary(); 38 | } 39 | } 40 | } else if (parent instanceof KeywordStatement) { 41 | result = resolveKeyword(); 42 | } 43 | debug.complete(); 44 | return result; 45 | } 46 | 47 | private static PsiElement getSecondChild(PsiElement element) { 48 | if (element == null) { 49 | return null; 50 | } 51 | PsiElement[] children = element.getChildren(); 52 | return children.length > 0 ? children[0] : null; 53 | } 54 | 55 | private PsiElement resolveKeyword() { 56 | Argument element = getElement(); 57 | String keyword = element.getPresentableText(); 58 | // all files we import are based off the file we are currently in 59 | return ResolverUtils.resolveKeywordFromFile(keyword, element.getContainingFile()); 60 | } 61 | 62 | @Nullable 63 | private PsiElement resolveLibrary() { 64 | return RobotFileManager.findPython(getElement().getPresentableText(), 65 | getElement().getProject(), getElement()); 66 | } 67 | 68 | private PsiElement resolveResource() { 69 | return RobotFileManager.findRobot(getElement().getPresentableText(), 70 | getElement().getProject(), getElement()); 71 | } 72 | 73 | @NotNull 74 | @Override 75 | public Object[] getVariants() { 76 | return EMPTY_ARRAY; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # HyperRobotFrameworkPlugin Changelog 4 | ## [0.1.0] 5 | ### Added 6 | - Better file structure view 7 | - Folding function for multi line statements 8 | 9 | ### Fixed 10 | - No word completion for `tasks` 11 | 12 | ## [0.0.9] 13 | ### Changed 14 | - `RETURN` is changed from keyword to robot syntax marker 15 | 16 | ### Fixed 17 | - Variable cannot be resolved after multi line statements 18 | - Incorrect paring after robot syntax markers 19 | - Other minor bugs 20 | 21 | ## [0.0.8] 22 | ### Fixed 23 | - Reference link is incorrect sometimes when refactoring projects 24 | - Incorrect inspection warning when `resource` file is not directly used in transitive import 25 | - Cannot parse variable properly in syntax maker statement block 26 | 27 | ## [0.0.7] 28 | ### Added 29 | - When plugin cannot find resource/library/variable file by the exact given path, it will try to search the entire project for the most possible files. (Will be useful when your file path is dynamic during the runtime.) 30 | - If plugin find more than one results during the fuzzy search, this file is still marked as unrecognized, you can find the multi results by clicking the references. 31 | - Note, this feature may ignore your potential runtime importing errors. 32 | 33 | ### Fixed 34 | - Some potential IDE errors 35 | - Robot builtin variable cannot be recognized sometimes 36 | - Some defined variables are missing in word completion list 37 | - Some defined variables' formats are incorrect in word completion list 38 | 39 | ## [0.0.6] 40 | ### Added 41 | - Variables dynamically set in settings `Test Setup` & `Suite Setup` now can be resolved 42 | - Variables dynamically set in `__init__.robot` now can be resolved 43 | 44 | ### Fixed 45 | - Incorrect import reference when there are multi python/resource files with the same name 46 | 47 | ## [0.0.5] 48 | ### Fixed 49 | - Some plugin errors when updating project structure 50 | - Some plugin errors when updating project python interpreter 51 | 52 | ## [0.0.4] 53 | ### Added 54 | - Support `WHILE` `CONTINUE` `BREAK` syntax 55 | - Support defined variable word completion in keyword and test 56 | ### Fixed 57 | - Some builtin variables are incorrect in recommendation word completion 58 | - Some library keywords completion contains string `'` 59 | - Dict variables are not considered as variables 60 | - Number variable such as `${1}` will be recognized as undefined variable 61 | - Variable definition is not recognized after `FOR` statement 62 | 63 | 64 | ## [0.0.3] 65 | ### Fixed 66 | - Fix some plugin errors 67 | ### Added 68 | - Support more Pycharm Editions 69 | - Support `TRY` `EXCEPT` syntax 70 | - Support `*** Tasks ***` syntax 71 | - Support data drive style tests 72 | ### Changed 73 | - Keyword with arguments tail is changed from 2 blanks to 4 74 | - Optimize recommendation word completion 75 | - Optimize syntax highlight color 76 | 77 | 78 | ## 0.0.2 79 | ### Changed 80 | - Optimize recommendation word completion 81 | - Optimize syntax highlight color 82 | - Support `TRY` `EXCEPT` syntax 83 | - Support `*** Tasks ***` syntax 84 | - Support data drive style tests 85 | - Fix some plugin errors 86 | 87 | ## 0.0.1 88 | - Initial scaffold created from [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template) 89 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/ref/RobotPythonClass.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.ImportType; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceCollector; 5 | import com.intellij.openapi.project.Project; 6 | import com.jetbrains.python.psi.PyClass; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedKeyword; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedVariable; 9 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordFile; 10 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceEntity; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Collection; 14 | import java.util.Collections; 15 | import java.util.HashSet; 16 | 17 | /** 18 | * @author mrubino 19 | */ 20 | public class RobotPythonClass extends RobotPythonWrapper implements KeywordFile, PerformanceEntity { 21 | 22 | private final String library; 23 | private final PyClass pythonClass; 24 | private final ImportType importType; 25 | 26 | public RobotPythonClass(@NotNull String library, @NotNull PyClass pythonClass, @NotNull ImportType importType) { 27 | this.library = library; 28 | this.pythonClass = pythonClass; 29 | this.importType = importType; 30 | } 31 | 32 | @NotNull 33 | @Override 34 | public Collection getDefinedKeywords() { 35 | final Collection results = new HashSet<>(); 36 | PerformanceCollector debug = new PerformanceCollector(this, "get defined keywords"); 37 | addDefinedKeywords(this.pythonClass, this.library, results); 38 | debug.complete(); 39 | return results; 40 | } 41 | 42 | @NotNull 43 | @Override 44 | public Collection getDefinedVariables() { 45 | final Collection results = new HashSet(); 46 | PerformanceCollector debug = new PerformanceCollector(this, "get defined variables"); 47 | addDefinedVariables(this.pythonClass, results); 48 | debug.complete(); 49 | return results; 50 | } 51 | 52 | @NotNull 53 | @Override 54 | public ImportType getImportType() { 55 | return this.importType; 56 | } 57 | 58 | @NotNull 59 | @Override 60 | public Collection getImportedFiles(boolean includeTransitive) { 61 | return Collections.emptyList(); 62 | } 63 | 64 | @Override 65 | public boolean equals(Object o) { 66 | if (this == o) return true; 67 | if (o == null || getClass() != o.getClass()) return false; 68 | 69 | RobotPythonClass that = (RobotPythonClass) o; 70 | return this.library.equals(that.library) && this.pythonClass.equals(that.pythonClass); 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | int result = this.library.hashCode(); 76 | result = 31 * result + this.pythonClass.hashCode(); 77 | return result; 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | return this.library; 83 | } 84 | 85 | @NotNull 86 | @Override 87 | public String getDebugFileName() { 88 | return this.library; 89 | } 90 | 91 | @NotNull 92 | @Override 93 | public String getDebugText() { 94 | return this.pythonClass.getContainingFile().getVirtualFile().getName(); 95 | } 96 | 97 | @NotNull 98 | @Override 99 | public Project getProject() { 100 | return this.pythonClass.getProject(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotParserDefinition.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.*; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.lang.ParserDefinition; 6 | import com.intellij.lang.PsiParser; 7 | import com.intellij.lexer.Lexer; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.psi.FileViewProvider; 10 | import com.intellij.psi.PsiElement; 11 | import com.intellij.psi.PsiFile; 12 | import com.intellij.psi.tree.IFileElementType; 13 | import com.intellij.psi.tree.TokenSet; 14 | import com.intellij.psi.util.PsiUtilCore; 15 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.*; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | /** 19 | * @author Stephen Abrams 20 | */ 21 | public class RobotParserDefinition implements ParserDefinition { 22 | 23 | private static final TokenSet WHITESPACE_SET = TokenSet.create(RobotTokenTypes.WHITESPACE); 24 | private static final TokenSet COMMENTS_SET = TokenSet.create(RobotTokenTypes.COMMENT); 25 | private static final TokenSet STRING_SET = TokenSet.create(RobotTokenTypes.GHERKIN, 26 | RobotTokenTypes.SYNTAX_MARKER); 27 | 28 | @NotNull 29 | @Override 30 | public Lexer createLexer(Project project) { 31 | return new RobotLexer(RobotKeywordProvider.getInstance()); 32 | } 33 | 34 | @Override 35 | public PsiParser createParser(Project project) { 36 | return new RobotParser(); 37 | } 38 | 39 | @Override 40 | public IFileElementType getFileNodeType() { 41 | return RobotTokenTypes.FILE; 42 | } 43 | 44 | @NotNull 45 | @Override 46 | public TokenSet getWhitespaceTokens() { 47 | return WHITESPACE_SET; 48 | } 49 | 50 | @NotNull 51 | @Override 52 | public TokenSet getCommentTokens() { 53 | return COMMENTS_SET; 54 | } 55 | 56 | @NotNull 57 | @Override 58 | public TokenSet getStringLiteralElements() { 59 | return STRING_SET; 60 | } 61 | 62 | @NotNull 63 | @Override 64 | public PsiElement createElement(ASTNode node) { 65 | if (node.getElementType() == RobotTokenTypes.KEYWORD_DEFINITION) return new KeywordDefinitionImpl(node); 66 | if (node.getElementType() == RobotTokenTypes.KEYWORD_DEFINITION_ID) return new KeywordDefinitionIdImpl(node); 67 | if (node.getElementType() == RobotTokenTypes.KEYWORD_STATEMENT) return new KeywordStatementImpl(node); 68 | if (node.getElementType() == RobotTokenTypes.KEYWORD) return new KeywordInvokableImpl(node); 69 | if (node.getElementType() == RobotTokenTypes.VARIABLE_DEFINITION) return new VariableDefinitionImpl(node); 70 | if (node.getElementType() == RobotTokenTypes.VARIABLE_DEFINITION_ID) return new VariableDefinitionIdImpl(node); 71 | if (node.getElementType() == RobotTokenTypes.HEADING) return new HeadingImpl(node); 72 | if (node.getElementType() == RobotTokenTypes.ARGUMENT) return new ArgumentImpl(node); 73 | if (node.getElementType() == RobotTokenTypes.VARIABLE) return new VariableImpl(node); 74 | if (node.getElementType() == RobotTokenTypes.IMPORT) return new ImportImpl(node); 75 | if (node.getElementType() == RobotTokenTypes.SETTING) return new SettingImpl(node); 76 | if (node.getElementType() == RobotTokenTypes.BRACKET_SETTING) return new BracketSettingImpl(node); 77 | 78 | return PsiUtilCore.NULL_PSI_ELEMENT; 79 | 80 | } 81 | 82 | @Override 83 | public PsiFile createFile(FileViewProvider viewProvider) { 84 | return new RobotFileImpl(viewProvider); 85 | } 86 | 87 | @Override 88 | public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) { 89 | // TODO: guessing this is for code cleanup 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/config/RobotConfiguration.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/config/RobotConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.config; 2 | 3 | import com.intellij.openapi.options.Configurable; 4 | import com.intellij.openapi.options.ConfigurationException; 5 | import com.intellij.openapi.options.SearchableConfigurable; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.project.ProjectManager; 8 | import org.jetbrains.annotations.Nls; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import javax.swing.*; 13 | 14 | /** 15 | * @author mrubino 16 | * @since 2014-06-26 17 | */ 18 | public class RobotConfiguration implements SearchableConfigurable, Configurable.NoScroll { 19 | 20 | private JPanel panel; 21 | private JCheckBox enableDebug; 22 | private JCheckBox allowTransitiveImports; 23 | private JCheckBox allowGlobalVariables; 24 | private JCheckBox capitalizeKeywords; 25 | private JCheckBox inlineVariableSearch; 26 | 27 | @Nullable 28 | private RobotOptionsProvider getOptionProvider() { 29 | Project[] projects = ProjectManager.getInstance().getOpenProjects(); 30 | if (projects.length > 0) { 31 | return RobotOptionsProvider.getInstance(projects[0]); 32 | } else { 33 | return null; 34 | } 35 | } 36 | 37 | @NotNull 38 | @Override 39 | public String getId() { 40 | return getHelpTopic(); 41 | } 42 | 43 | @Nullable 44 | @Override 45 | public Runnable enableSearch(String s) { 46 | return null; 47 | } 48 | 49 | @Nls 50 | @Override 51 | public String getDisplayName() { 52 | return "Robot Options"; 53 | } 54 | 55 | @NotNull 56 | @Override 57 | public String getHelpTopic() { 58 | return "reference.idesettings.robot"; 59 | } 60 | 61 | @Nullable 62 | @Override 63 | public JComponent createComponent() { 64 | return this.panel; 65 | } 66 | 67 | @Override 68 | public boolean isModified() { 69 | RobotOptionsProvider provider = getOptionProvider(); 70 | if (provider != null) { 71 | return provider.isDebug() != this.enableDebug.isSelected() || 72 | provider.allowTransitiveImports() != this.allowTransitiveImports.isSelected() || 73 | provider.allowGlobalVariables() != this.allowGlobalVariables.isSelected() || 74 | provider.capitalizeKeywords() != this.capitalizeKeywords.isSelected() || 75 | provider.inlineVariableSearch() != this.inlineVariableSearch.isSelected(); 76 | } else { 77 | return false; 78 | } 79 | } 80 | 81 | @Override 82 | public void apply() throws ConfigurationException { 83 | RobotOptionsProvider provider = getOptionProvider(); 84 | if (provider != null) { 85 | provider.setDebug(this.enableDebug.isSelected()); 86 | provider.setTransitiveImports(this.allowTransitiveImports.isSelected()); 87 | provider.setGlobalVariables(this.allowGlobalVariables.isSelected()); 88 | provider.setCapitalizeKeywords(this.capitalizeKeywords.isSelected()); 89 | provider.setInlineVariableSearch(this.inlineVariableSearch.isSelected()); 90 | } 91 | } 92 | 93 | @Override 94 | public void reset() { 95 | RobotOptionsProvider provider = getOptionProvider(); 96 | if (provider != null) { 97 | this.enableDebug.setSelected(provider.isDebug()); 98 | this.allowTransitiveImports.setSelected(provider.allowTransitiveImports()); 99 | this.allowGlobalVariables.setSelected(provider.allowGlobalVariables()); 100 | this.capitalizeKeywords.setSelected(provider.capitalizeKeywords()); 101 | this.inlineVariableSearch.setSelected(provider.inlineVariableSearch()); 102 | } 103 | } 104 | 105 | @Override 106 | public void disposeUIResources() { 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/util/PatternUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.util; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import java.util.Collection; 7 | import java.util.TreeSet; 8 | import java.util.regex.Pattern; 9 | 10 | /** 11 | * @author mrubino 12 | * @since 2014-06-19 13 | */ 14 | public class PatternUtil { 15 | 16 | private static final Collection VARIABLE_SETTERS; 17 | private static final String EMPTY = ""; 18 | private static final String SPACE = " "; 19 | private static final String SUPER_SPACE = " "; 20 | private static final String TAB = "\t"; 21 | private static final String NEWLINE = "\n"; 22 | private static final String UNDERSCORE = "_"; 23 | private static final String EQUAL = "="; 24 | private static final String SCALAR_START = "${"; 25 | private static final String LIST_START = "@{"; 26 | private static final String ENVIRONMENT_START = "%{"; 27 | private static final String DICTIONARY_START = "&{"; 28 | private static final String VARIABLE_CLOSE = "}"; 29 | private static final String VARIABLE_START_PATTERN = "[\\$\\@\\%\\&]\\{"; 30 | private static final String VARIABLE_END_PATTERN = "((\\..*?)*?(\\[.*?\\])*?)*?\\}(\\[\\d+\\])?"; 31 | private static final String VARIABLE_SEPARATOR = "[ _]*?"; 32 | 33 | static { 34 | VARIABLE_SETTERS = new TreeSet(String.CASE_INSENSITIVE_ORDER); 35 | VARIABLE_SETTERS.add("set test variable"); 36 | VARIABLE_SETTERS.add("set suite variable"); 37 | VARIABLE_SETTERS.add("set global variable"); 38 | } 39 | 40 | private PatternUtil() { 41 | } 42 | 43 | @NotNull 44 | public static String getVariablePattern(@NotNull String original) { 45 | String text = original.trim(); 46 | if (text.length() == 0) { 47 | return text; 48 | } 49 | // strip any equals 50 | if (text.endsWith(EQUAL)) { 51 | text = text.substring(0, text.length() - 1); 52 | } 53 | text = text.trim(); 54 | // strip the starting marker 55 | if (text.startsWith(SCALAR_START) || text.startsWith(LIST_START) || 56 | text.startsWith(DICTIONARY_START) || text.startsWith(ENVIRONMENT_START)) { 57 | text = text.substring(2); 58 | } 59 | // strip the ending marker 60 | if (text.endsWith(VARIABLE_CLOSE)) { 61 | text = text.substring(0, text.length() - 1); 62 | } 63 | if (text.isEmpty()) { 64 | return original; 65 | } 66 | // put it all back together allowing for ' ' or '_' optionally anywhere 67 | StringBuilder pattern = new StringBuilder(); 68 | pattern.append(VARIABLE_START_PATTERN); 69 | for (char c : text.toCharArray()) { 70 | if (c == '_' || c == ' ') { 71 | continue; 72 | } 73 | pattern.append(VARIABLE_SEPARATOR); 74 | pattern.append(Pattern.quote(Character.toString(c))); 75 | } 76 | pattern.append(VARIABLE_SEPARATOR); 77 | pattern.append(VARIABLE_END_PATTERN); 78 | 79 | return pattern.toString(); 80 | } 81 | 82 | public static boolean isVariableSettingKeyword(String keyword) { 83 | return VARIABLE_SETTERS.contains(functionToKeyword(keyword)); 84 | } 85 | 86 | @Nullable 87 | public static String functionToKeyword(@Nullable String function) { 88 | return function == null ? null : function.replaceAll(UNDERSCORE, SPACE).trim(); 89 | } 90 | 91 | @NotNull 92 | public static String getPresentableText(@Nullable String text) { 93 | if (text == null) { 94 | return EMPTY; 95 | } 96 | int newLine = indexOf(text, NEWLINE); 97 | int tab = indexOf(text, TAB); 98 | int superSpace = indexOf(text, SUPER_SPACE); 99 | 100 | int index = Math.min(newLine, tab); 101 | index = Math.min(index, superSpace); 102 | 103 | return text.substring(0, index).trim(); 104 | } 105 | 106 | private static int indexOf(@NotNull String text, @NotNull String string) { 107 | int index = text.indexOf(string); 108 | return index < 0 ? text.length() : index; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/KeywordStatementImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.VariableDto; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PatternUtil; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceCollector; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceEntity; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * @author mrubino 17 | */ 18 | public class KeywordStatementImpl extends RobotPsiElementBase implements KeywordStatement, PerformanceEntity { 19 | 20 | private List arguments; 21 | private DefinedVariable variable; 22 | private KeywordInvokable invokable; 23 | 24 | public KeywordStatementImpl(@NotNull ASTNode node) { 25 | super(node); 26 | } 27 | 28 | @Nullable 29 | @Override 30 | public KeywordInvokable getInvokable() { 31 | KeywordInvokable result = this.invokable; 32 | if (result == null) { 33 | PerformanceCollector debug = new PerformanceCollector(this, "invokable"); 34 | result = collectInvokable(); 35 | this.invokable = result; 36 | debug.complete(); 37 | } 38 | return result; 39 | } 40 | 41 | @Nullable 42 | private KeywordInvokable collectInvokable() { 43 | for (PsiElement child : getChildren()) { 44 | if (child instanceof KeywordInvokable) { 45 | return (KeywordInvokable) child; 46 | } 47 | } 48 | return null; 49 | } 50 | 51 | @NotNull 52 | @Override 53 | public List getArguments() { 54 | List results = this.arguments; 55 | if (results == null) { 56 | PerformanceCollector debug = new PerformanceCollector(this, "arguments"); 57 | results = collectArguments(); 58 | this.arguments = results; 59 | debug.complete(); 60 | } 61 | return results; 62 | } 63 | 64 | @NotNull 65 | private List collectArguments() { 66 | List results = new ArrayList(); 67 | for (PsiElement element : getChildren()) { 68 | if (element instanceof Argument) { 69 | results.add((Argument) element); 70 | } 71 | } 72 | return results; 73 | } 74 | 75 | @Nullable 76 | @Override 77 | public DefinedVariable getGlobalVariable() { 78 | DefinedVariable result = this.variable; 79 | if (result == null) { 80 | PerformanceCollector debug = new PerformanceCollector(this, "global variable"); 81 | result = collectGlobalVariable(); 82 | this.variable = result; 83 | debug.complete(); 84 | } 85 | return result; 86 | } 87 | 88 | @Nullable 89 | private DefinedVariable collectGlobalVariable() { 90 | KeywordInvokable invokable = getInvokable(); 91 | if (invokable != null) { 92 | String text = invokable.getPresentableText(); 93 | if (PatternUtil.isVariableSettingKeyword(text)) { 94 | List arguments = getArguments(); 95 | if (arguments.size() > 0) { 96 | Argument variable = arguments.get(0); 97 | // already formatted ${X} 98 | return new VariableDto(variable, variable.getPresentableText(), null); 99 | } 100 | } 101 | } 102 | return null; 103 | } 104 | 105 | @Override 106 | public void subtreeChanged() { 107 | super.subtreeChanged(); 108 | this.arguments = null; 109 | this.invokable = null; 110 | this.variable = null; 111 | } 112 | 113 | @NotNull 114 | @Override 115 | public String getDebugText() { 116 | KeywordInvokable invokable = getInvokable(); 117 | String text = invokable == null ? null : getInvokable().getPresentableText(); 118 | return text == null ? "EMPTY" : text; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/config/RobotColorsPage.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.config; 2 | 3 | import com.intellij.openapi.editor.colors.TextAttributesKey; 4 | import com.intellij.openapi.fileTypes.SyntaxHighlighter; 5 | import com.intellij.openapi.options.colors.AttributesDescriptor; 6 | import com.intellij.openapi.options.colors.ColorDescriptor; 7 | import com.intellij.openapi.options.colors.ColorSettingsPage; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.RobotBundle; 9 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotFeatureFileType; 10 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotHighlighter; 11 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotKeywordProvider; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import javax.swing.*; 16 | import java.util.Map; 17 | 18 | /** 19 | * @author mrubino 20 | */ 21 | public class RobotColorsPage implements ColorSettingsPage { 22 | 23 | private static final String DEMO_TEXT = "invalid\n" + 24 | "*** Settings ***\n" + 25 | "Documentation This is some demo text\n" + 26 | "Library CalculatorLibrary\n" + 27 | "\n" + 28 | "*** Variables ***\n" + 29 | "${var1} 12345\n" + 30 | "${var2} another variable\n" + 31 | "\n" + 32 | "*** Test Cases ***\n" + 33 | "Addition\n" + 34 | " [Tags] Calculator\n" + 35 | " Given calculator has been cleared\n" + 36 | " When user types \"1 + 1\"\n" + 37 | " And user pushes equals\n" + 38 | " Then result is \"2\"\n" + 39 | "\n" + 40 | "#Subtraction\n" + 41 | "# [Tags] Calculator\n" + 42 | "# TODO: implement me\n" + 43 | "\n" + 44 | "*** Keywords ***\n" + 45 | "Calculator has been cleared\n" + 46 | " Push button C\n" + 47 | "\n" + 48 | "User types \"${expression}\"\n" + 49 | " Push buttons ${expression}\n" + 50 | "\n" + 51 | "User pushes equals\n" + 52 | " Push button =\n" + 53 | "\n" + 54 | "Result is \"${result}\"\n" + 55 | " Result should be ${result}"; 56 | 57 | private static final String NAME = "Robot"; 58 | private static final ColorDescriptor[] COLORS = new ColorDescriptor[0]; 59 | 60 | private static final AttributesDescriptor[] ATTRIBUTES = new AttributesDescriptor[]{ 61 | new AttributesDescriptor(RobotBundle.message("color.settings.heading"), RobotHighlighter.HEADING), 62 | new AttributesDescriptor(RobotBundle.message("color.settings.comment"), RobotHighlighter.COMMENT), 63 | new AttributesDescriptor(RobotBundle.message("color.settings.argument"), RobotHighlighter.ARGUMENT), 64 | new AttributesDescriptor(RobotBundle.message("color.settings.error"), RobotHighlighter.ERROR), 65 | new AttributesDescriptor(RobotBundle.message("color.settings.gherkin"), RobotHighlighter.GHERKIN), 66 | new AttributesDescriptor(RobotBundle.message("color.settings.syntaxMarker"), RobotHighlighter.SYNTAX_MARKER), 67 | new AttributesDescriptor(RobotBundle.message("color.settings.variable"), RobotHighlighter.VARIABLE), 68 | new AttributesDescriptor(RobotBundle.message("color.settings.variableDefinition"), RobotHighlighter.VARIABLE_DEFINITION), 69 | new AttributesDescriptor(RobotBundle.message("color.settings.keyword"), RobotHighlighter.KEYWORD), 70 | new AttributesDescriptor(RobotBundle.message("color.settings.keywordDefinition"), RobotHighlighter.KEYWORD_DEFINITION), 71 | new AttributesDescriptor(RobotBundle.message("color.settings.bracketSetting"), RobotHighlighter.BRACKET_SETTING), 72 | new AttributesDescriptor(RobotBundle.message("color.settings.setting"), RobotHighlighter.SETTING), 73 | new AttributesDescriptor(RobotBundle.message("color.settings.import"), RobotHighlighter.IMPORT) 74 | }; 75 | 76 | @Nullable 77 | @Override 78 | public Icon getIcon() { 79 | return RobotFeatureFileType.getInstance().getIcon(); 80 | } 81 | 82 | @NotNull 83 | @Override 84 | public SyntaxHighlighter getHighlighter() { 85 | return new RobotHighlighter(RobotKeywordProvider.getInstance()); 86 | } 87 | 88 | @NotNull 89 | @Override 90 | public String getDemoText() { 91 | return DEMO_TEXT; 92 | } 93 | 94 | @Nullable 95 | @Override 96 | public Map getAdditionalHighlightingTagToDescriptorMap() { 97 | return null; 98 | } 99 | 100 | @NotNull 101 | @Override 102 | public AttributesDescriptor[] getAttributeDescriptors() { 103 | return ATTRIBUTES; 104 | } 105 | 106 | @NotNull 107 | @Override 108 | public ColorDescriptor[] getColorDescriptors() { 109 | return COLORS; 110 | } 111 | 112 | @NotNull 113 | @Override 114 | public String getDisplayName() { 115 | return NAME; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/RobotHighlighter.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; 5 | import com.intellij.openapi.editor.colors.TextAttributesKey; 6 | import com.intellij.openapi.fileTypes.SyntaxHighlighterBase; 7 | import com.intellij.psi.tree.IElementType; 8 | import gnu.trove.THashMap; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * @author Stephen Abrams 15 | */ 16 | public class RobotHighlighter extends SyntaxHighlighterBase { 17 | private static final Map keys1; 18 | private static final Map keys2; 19 | 20 | private final RobotKeywordProvider myKeywordProvider; 21 | 22 | public RobotHighlighter(RobotKeywordProvider keywordProvider) { 23 | this.myKeywordProvider = keywordProvider; 24 | } 25 | 26 | @NotNull 27 | public Lexer getHighlightingLexer() { 28 | return new RobotLexer(this.myKeywordProvider); 29 | } 30 | 31 | public static final TextAttributesKey HEADING = TextAttributesKey.createTextAttributesKey( 32 | RobotTokenTypes.HEADING.toString(), 33 | DefaultLanguageHighlighterColors.STRING 34 | ); 35 | 36 | public static final TextAttributesKey SETTING = TextAttributesKey.createTextAttributesKey( 37 | RobotTokenTypes.SETTING.toString(), 38 | DefaultLanguageHighlighterColors.KEYWORD 39 | ); 40 | 41 | public static final TextAttributesKey BRACKET_SETTING = TextAttributesKey.createTextAttributesKey( 42 | RobotTokenTypes.BRACKET_SETTING.toString(), 43 | DefaultLanguageHighlighterColors.DOC_COMMENT_TAG 44 | ); 45 | 46 | public static final TextAttributesKey IMPORT = TextAttributesKey.createTextAttributesKey( 47 | RobotTokenTypes.IMPORT.toString(), 48 | DefaultLanguageHighlighterColors.DOC_COMMENT_TAG_VALUE 49 | ); 50 | 51 | public static final TextAttributesKey KEYWORD_DEFINITION = TextAttributesKey.createTextAttributesKey( 52 | RobotTokenTypes.KEYWORD_DEFINITION.toString(), 53 | DefaultLanguageHighlighterColors.KEYWORD 54 | ); 55 | 56 | public static final TextAttributesKey KEYWORD = TextAttributesKey.createTextAttributesKey( 57 | RobotTokenTypes.KEYWORD.toString(), 58 | DefaultLanguageHighlighterColors.FUNCTION_DECLARATION 59 | ); 60 | 61 | public static final TextAttributesKey ARGUMENT = TextAttributesKey.createTextAttributesKey( 62 | RobotTokenTypes.ARGUMENT.toString(), 63 | DefaultLanguageHighlighterColors.STATIC_FIELD 64 | ); 65 | 66 | public static final TextAttributesKey VARIABLE_DEFINITION = TextAttributesKey.createTextAttributesKey( 67 | RobotTokenTypes.VARIABLE_DEFINITION.toString(), 68 | DefaultLanguageHighlighterColors.MARKUP_ATTRIBUTE 69 | ); 70 | 71 | public static final TextAttributesKey VARIABLE = TextAttributesKey.createTextAttributesKey( 72 | RobotTokenTypes.VARIABLE.toString(), 73 | DefaultLanguageHighlighterColors.DOC_COMMENT_MARKUP 74 | ); 75 | 76 | public static final TextAttributesKey COMMENT = TextAttributesKey.createTextAttributesKey( 77 | RobotTokenTypes.COMMENT.toString(), 78 | DefaultLanguageHighlighterColors.LINE_COMMENT 79 | ); 80 | 81 | public static final TextAttributesKey GHERKIN = TextAttributesKey.createTextAttributesKey( 82 | RobotTokenTypes.GHERKIN.toString(), 83 | DefaultLanguageHighlighterColors.METADATA 84 | ); 85 | 86 | public static final TextAttributesKey SYNTAX_MARKER = TextAttributesKey.createTextAttributesKey( 87 | RobotTokenTypes.SYNTAX_MARKER.toString(), 88 | DefaultLanguageHighlighterColors.METADATA 89 | ); 90 | 91 | public static final TextAttributesKey ERROR = TextAttributesKey.createTextAttributesKey( 92 | RobotTokenTypes.ERROR.toString(), 93 | DefaultLanguageHighlighterColors.INVALID_STRING_ESCAPE 94 | ); 95 | 96 | static { 97 | keys1 = new THashMap<>(); 98 | keys2 = new THashMap<>(); 99 | 100 | keys1.put(RobotTokenTypes.HEADING, HEADING); 101 | keys1.put(RobotTokenTypes.COMMENT, COMMENT); 102 | keys1.put(RobotTokenTypes.ARGUMENT, ARGUMENT); 103 | keys1.put(RobotTokenTypes.ERROR, ERROR); 104 | keys1.put(RobotTokenTypes.GHERKIN, GHERKIN); 105 | keys1.put(RobotTokenTypes.SYNTAX_MARKER, SYNTAX_MARKER); 106 | keys1.put(RobotTokenTypes.VARIABLE, VARIABLE); 107 | keys1.put(RobotTokenTypes.VARIABLE_DEFINITION, VARIABLE_DEFINITION); 108 | keys1.put(RobotTokenTypes.KEYWORD, KEYWORD); 109 | keys1.put(RobotTokenTypes.KEYWORD_DEFINITION, KEYWORD_DEFINITION); 110 | keys1.put(RobotTokenTypes.BRACKET_SETTING, BRACKET_SETTING); 111 | keys1.put(RobotTokenTypes.SETTING, SETTING); 112 | keys1.put(RobotTokenTypes.IMPORT, IMPORT); 113 | } 114 | 115 | @NotNull 116 | public TextAttributesKey[] getTokenHighlights(IElementType tokenType) { 117 | return pack(keys1.get(tokenType), keys2.get(tokenType)); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 66 | 67 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/element/RobotFileImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.element; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotFeatureFileType; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotLanguage; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.ImportType; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceCollector; 7 | import com.intellij.extapi.psi.PsiFileBase; 8 | import com.intellij.openapi.fileTypes.FileType; 9 | import com.intellij.psi.FileViewProvider; 10 | import com.intellij.psi.PsiElement; 11 | import com.intellij.psi.PsiFile; 12 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceEntity; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.Collection; 17 | import java.util.HashSet; 18 | import java.util.LinkedHashSet; 19 | 20 | /** 21 | * @author Stephen Abrams 22 | */ 23 | public class RobotFileImpl extends PsiFileBase implements RobotFile, KeywordFile, PerformanceEntity { 24 | 25 | private Collection headings; 26 | 27 | public RobotFileImpl(FileViewProvider viewProvider) { 28 | super(viewProvider, RobotLanguage.INSTANCE); 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public FileType getFileType() { 34 | return RobotFeatureFileType.getInstance(); 35 | } 36 | 37 | @Override 38 | public void subtreeChanged() { 39 | super.subtreeChanged(); 40 | this.headings = null; 41 | } 42 | 43 | @NotNull 44 | @Override 45 | public Collection getDefinedVariables() { 46 | Collection results = new LinkedHashSet(); 47 | for (Heading heading : getHeadings()) { 48 | results.addAll(heading.getDefinedVariables()); 49 | } 50 | return results; 51 | } 52 | 53 | @NotNull 54 | @Override 55 | public ImportType getImportType() { 56 | return ImportType.RESOURCE; 57 | } 58 | 59 | @NotNull 60 | @Override 61 | public Collection getDefinedKeywords() { 62 | Collection results = new LinkedHashSet(); 63 | for (Heading heading : getHeadings()) { 64 | results.addAll(heading.getDefinedKeywords()); 65 | } 66 | return results; 67 | } 68 | 69 | @NotNull 70 | @Override 71 | public Collection getFilesFromInvokedKeywordsAndVariables() { 72 | Collection results = new HashSet(); 73 | for (Heading heading : getHeadings()) { 74 | results.addAll(heading.getFilesFromInvokedKeywordsAndVariables()); 75 | } 76 | return results; 77 | } 78 | 79 | @NotNull 80 | @Override 81 | public Collection getImportedFiles(boolean includeTransitive) { 82 | Collection results = new LinkedHashSet(); 83 | for (Heading heading : getHeadings()) { 84 | for (KeywordFile file : heading.getImportedFiles()) { 85 | addKeywordFiles(results, file, includeTransitive); 86 | } 87 | } 88 | return results; 89 | } 90 | 91 | private void addKeywordFiles(Collection files, KeywordFile current, boolean includeTransitive) { 92 | if (files.add(current)) { 93 | if (includeTransitive) { 94 | for (KeywordFile file : current.getImportedFiles(false)) { 95 | addKeywordFiles(files, file, true); 96 | } 97 | } 98 | } 99 | } 100 | 101 | @Override 102 | public void importsChanged() { 103 | for (Heading heading : getHeadings()) { 104 | heading.importsChanged(); 105 | } 106 | } 107 | 108 | @NotNull 109 | @Override 110 | public Collection getKeywordReferences(@Nullable KeywordDefinition definition) { 111 | Collection results = new LinkedHashSet(); 112 | for (Heading heading : getHeadings()) { 113 | results.addAll(heading.getKeywordReferences(definition)); 114 | } 115 | return results; 116 | } 117 | 118 | @NotNull 119 | public Collection getHeadings() { 120 | Collection results = this.headings; 121 | if (results == null) { 122 | PerformanceCollector debug = new PerformanceCollector(this, "headings"); 123 | results = collectHeadings(); 124 | this.headings = results; 125 | debug.complete(); 126 | } 127 | return results; 128 | } 129 | 130 | @NotNull 131 | private Collection collectHeadings() { 132 | Collection results = new LinkedHashSet(); 133 | for (PsiElement child : getChildren()) { 134 | if (child instanceof Heading) { 135 | results.add((Heading) child); 136 | } 137 | } 138 | return results; 139 | } 140 | 141 | @NotNull 142 | @Override 143 | public String getDebugFileName() { 144 | return getVirtualFile().getName(); 145 | } 146 | 147 | @NotNull 148 | @Override 149 | public String getDebugText() { 150 | return "."; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/ref/RobotPythonFile.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.ImportType; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.KeywordDto; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.VariableDto; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceCollector; 7 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.ReservedVariableScope; 8 | import com.intellij.openapi.project.Project; 9 | import com.jetbrains.python.psi.PyClass; 10 | import com.jetbrains.python.psi.PyFile; 11 | import com.jetbrains.python.psi.PyFunction; 12 | import com.jetbrains.python.psi.PyTargetExpression; 13 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedKeyword; 14 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedVariable; 15 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordFile; 16 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceEntity; 17 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.ReservedVariable; 18 | import org.jetbrains.annotations.NotNull; 19 | 20 | import java.util.Collection; 21 | import java.util.Collections; 22 | import java.util.HashSet; 23 | 24 | /** 25 | * @author mrubino 26 | * @since 2014-06-17 27 | */ 28 | public class RobotPythonFile extends RobotPythonWrapper implements KeywordFile, PerformanceEntity { 29 | 30 | private static final String EMPTY = ""; 31 | 32 | private final String library; 33 | private final PyFile pythonFile; 34 | private final ImportType importType; 35 | 36 | public RobotPythonFile(@NotNull String library, @NotNull PyFile pythonFile, @NotNull ImportType importType) { 37 | this.library = library; 38 | this.pythonFile = pythonFile; 39 | this.importType = importType; 40 | } 41 | 42 | @NotNull 43 | @Override 44 | public Collection getDefinedKeywords() { 45 | PerformanceCollector debug = new PerformanceCollector(this, "get defined keywords"); 46 | Collection results = new HashSet(); 47 | for (PyFunction function : this.pythonFile.getTopLevelFunctions()) { 48 | String keyword = functionToKeyword(function.getName()); 49 | if (keyword != null) { 50 | results.add(new KeywordDto(function, this.library, keyword, hasArguments(function.getParameterList().getParameters()))); 51 | } 52 | } 53 | for (PyTargetExpression expression : this.pythonFile.getTopLevelAttributes()) { 54 | String keyword = functionToKeyword(expression.getName()); 55 | if (keyword != null) { 56 | results.add(new KeywordDto(expression, this.library, keyword, false)); 57 | } 58 | } 59 | for (PyClass subClass : this.pythonFile.getTopLevelClasses()) { 60 | String namespace = subClass.getQualifiedName() == null ? EMPTY : subClass.getQualifiedName(); 61 | addDefinedKeywords(subClass, namespace, results); 62 | } 63 | debug.complete(); 64 | return results; 65 | } 66 | 67 | @NotNull 68 | @Override 69 | public Collection getDefinedVariables() { 70 | PerformanceCollector debug = new PerformanceCollector(this, "get defined variables"); 71 | final Collection results = new HashSet(); 72 | for (PyTargetExpression expression : this.pythonFile.getTopLevelAttributes()) { 73 | String keyword = expression.getName(); 74 | if (keyword != null) { 75 | // not formatted ${X}, assume scalar 76 | results.add(new VariableDto(expression, ReservedVariable.wrapToScalar(keyword), 77 | ReservedVariableScope.TestCase)); 78 | } 79 | } 80 | for (PyClass subClass : this.pythonFile.getTopLevelClasses()) { 81 | addDefinedVariables(subClass, results); 82 | } 83 | debug.complete(); 84 | return results; 85 | } 86 | 87 | @NotNull 88 | @Override 89 | public ImportType getImportType() { 90 | return this.importType; 91 | } 92 | 93 | @NotNull 94 | @Override 95 | public Collection getImportedFiles(boolean includeTransitive) { 96 | return Collections.emptyList(); 97 | } 98 | 99 | @Override 100 | public boolean equals(Object o) { 101 | if (this == o) return true; 102 | if (o == null || getClass() != o.getClass()) return false; 103 | 104 | RobotPythonFile that = (RobotPythonFile) o; 105 | return this.library.equals(that.library) && this.pythonFile.equals(that.pythonFile); 106 | } 107 | 108 | @Override 109 | public int hashCode() { 110 | int result = this.library.hashCode(); 111 | result = 31 * result + this.pythonFile.hashCode(); 112 | return result; 113 | } 114 | 115 | @Override 116 | public String toString() { 117 | return this.library; 118 | } 119 | 120 | @NotNull 121 | @Override 122 | public String getDebugFileName() { 123 | return toString(); 124 | } 125 | 126 | @NotNull 127 | @Override 128 | public String getDebugText() { 129 | return this.pythonFile.getContainingFile().getVirtualFile().getName(); 130 | } 131 | 132 | @NotNull 133 | @Override 134 | public Project getProject() { 135 | return this.pythonFile.getProject(); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/ref/RobotPythonWrapper.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.ref; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.KeywordDto; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.dto.VariableDto; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.ReservedVariableScope; 6 | import com.intellij.util.Processor; 7 | import com.jetbrains.python.psi.*; 8 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedKeyword; 9 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedVariable; 10 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.ReservedVariable; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import java.util.Collection; 15 | 16 | /** 17 | * @author mrubino 18 | * @since 2014-06-17 19 | */ 20 | public abstract class RobotPythonWrapper { 21 | 22 | private static final String UNDERSCORE = "_"; 23 | private static final String SELF = "self"; 24 | 25 | protected static boolean hasArguments(@Nullable PyParameter[] parameters) { 26 | if (parameters == null || parameters.length == 0) { 27 | return false; 28 | } 29 | 30 | for (PyParameter parameter : parameters) { 31 | String name = parameter.getName(); 32 | if (name != null && !SELF.equalsIgnoreCase(name)) { 33 | return true; 34 | } 35 | } 36 | return false; 37 | } 38 | 39 | protected static String functionToKeyword(@Nullable String function) { 40 | if (function == null || isPrivate(function)) { 41 | return null; 42 | } else { 43 | return function; 44 | } 45 | } 46 | 47 | protected static void addDefinedVariables(@NotNull PyClass pythonClass, @NotNull final Collection results) { 48 | pythonClass.visitClassAttributes( 49 | new Processor() { 50 | @Override 51 | public boolean process(PyTargetExpression expression) { 52 | String keyword = expression.getName(); 53 | if (keyword != null && !isPrivate(keyword)) { 54 | // not formatted ${X}, assume scalar 55 | results.add(new VariableDto(expression, ReservedVariable.wrapToScalar(keyword), 56 | ReservedVariableScope.TestCase)); 57 | } 58 | return true; 59 | } 60 | }, 61 | true, 62 | null 63 | ); 64 | } 65 | 66 | private static boolean isPrivate(@NotNull String keyword) { 67 | // these keeps out intended private functions 68 | return keyword.startsWith(UNDERSCORE) || keyword.startsWith("ROBOT_LIBRARY_"); 69 | } 70 | 71 | protected static void addDefinedKeywords(@NotNull PyClass pythonClass, @NotNull final String namespace, @NotNull final Collection results) { 72 | pythonClass.visitMethods( 73 | new Processor() { 74 | 75 | @Override 76 | public boolean process(PyFunction function) { 77 | String keyword = functionToKeyword(function.getName()); 78 | if (keyword != null) { 79 | // Get info from @keyword 80 | PyDecoratorList decorators = function.getDecoratorList(); 81 | if (decorators != null) { 82 | PyDecorator keyword_decorator = decorators.findDecorator("keyword"); 83 | if (keyword_decorator != null) { 84 | if (keyword_decorator.hasArgumentList()) { 85 | // Get case 'name =' argument 86 | PyExpression kwa = keyword_decorator.getKeywordArgument("name"); 87 | if (kwa != null) { 88 | keyword = kwa.getText().replaceAll("^\"|\"$", ""); 89 | } 90 | else { 91 | // Otherwise, check if first argument is unnamed 92 | PyExpression[] kda = keyword_decorator.getArguments(); 93 | 94 | // Argument exists and is unnamed 95 | if (kda.length > 0 && kda[0].getName() == null) { 96 | keyword = kda[0].getText().replaceAll("^\"|\"$", ""); 97 | } 98 | } 99 | } 100 | } 101 | } 102 | results.add(new KeywordDto(function, namespace, keyword, hasArguments(function.getParameterList().getParameters()))); 103 | } 104 | return true; 105 | } 106 | }, 107 | true, 108 | null 109 | ); 110 | pythonClass.visitClassAttributes( 111 | new Processor() { 112 | 113 | @Override 114 | public boolean process(PyTargetExpression expression) { 115 | String keyword = functionToKeyword(expression.getName()); 116 | if (keyword != null) { 117 | results.add(new KeywordDto(expression, namespace, keyword, false)); 118 | } 119 | return true; 120 | } 121 | }, 122 | true, 123 | null 124 | ); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/psi/util/ReservedVariable.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.psi.util; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.PsiElement; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * @author mrubino 10 | * @since 2016-03-29 11 | */ 12 | public enum ReservedVariable { 13 | 14 | // Scope Everywhere 15 | CUR_DIR("${CUR_DIR}", ReservedVariableScope.Global), // An absolute path to the directory where the test data file is located. This variable is case-sensitive. 16 | TEMP_DIR("${TEMP_DIR}", ReservedVariableScope.Global), // An absolute path to the system temporary directory. In UNIX-like systems this is typically /tmp, and in Windows c:\Documents and Settings\\Local Settings\Temp. 17 | EXEC_DIR("${EXEC_DIR}", ReservedVariableScope.Global), // An absolute path to the directory where test execution was started from. 18 | PATH_SEPARATOR("${/}", ReservedVariableScope.Global), // The system directory path separator. / in UNIX-like systems and \ in Windows. 19 | PATH_ELEMENT("${:}", ReservedVariableScope.Global), // The system path element separator. : in UNIX-like systems and ; in Windows. 20 | NEW_LINE("${\\n}", ReservedVariableScope.Global), // The system line separator. \n in UNIX-like systems and \r\n in Windows. 21 | SPACE("${SPACE}", ReservedVariableScope.Global), // String with space: " " 22 | SUPER_SPACE("${SPACE_*_2}", ReservedVariableScope.Global), // String with two spaces: " " 23 | EMPTY("${EMPTY}", ReservedVariableScope.Global), // Empty String 24 | EMPTY_LIST("@{EMPTY}", ReservedVariableScope.Global), // Empty list 25 | EMPTY_DICTIONARY("&{EMPTY}", ReservedVariableScope.Global), // Empty dictionary 26 | TRUE("${True}", ReservedVariableScope.Global), // Boolean true 27 | FALSE("${False}", ReservedVariableScope.Global), // Boolean false 28 | NONE("${None}", ReservedVariableScope.Global), // Python None 29 | NULL("${null}", ReservedVariableScope.Global), // Java null 30 | SUITE_NAME("${SUITE_NAME}", ReservedVariableScope.Global), // The full name of the current test suite. 31 | SUITE_SOURCE("${SUITE_SOURCE}", ReservedVariableScope.Global), // An absolute path to the suite file or directory. 32 | SUITE_DOCUMENTATION("${SUITE_DOCUMENTATION}", ReservedVariableScope.Global), // The documentation of the current test suite. Can be set dynamically using using Set Suite Documentation keyword. 33 | SUITE_METADATA("&{SUITE_METADATA}", ReservedVariableScope.Global), // The free metadata of the current test suite. Can be set using Set Suite Metadata keyword. 34 | OUTPUT_DIR("${OUTPUT_DIR}", ReservedVariableScope.Global), // An absolute path to the output directory. 35 | OUTPUT_FILE("${OUTPUT_FILE}", ReservedVariableScope.Global), // An absolute path to the output file. 36 | REPORT_FILE("${REPORT_FILE}", ReservedVariableScope.Global), // An absolute path to the report file or string NONE when no report is created. 37 | LOG_FILE("${LOG_FILE}", ReservedVariableScope.Global), // An absolute path to the log file or string NONE when no log file is created. 38 | LOG_LEVEL("${LOG_LEVEL}", ReservedVariableScope.Global), // Current log level. 39 | DEBUG_FILE("${DEBUG_FILE}", ReservedVariableScope.Global), // An absolute path to the debug file or string NONE when no debug file is created. 40 | // Scope: Test Case 41 | PREV_TEST_NAME("${PREV_TEST_NAME}", ReservedVariableScope.TestCase), // The name of the previous test case, or an empty string if no tests have been executed yet. 42 | PREV_TEST_STATUS("${PREV_TEST_STATUS}", ReservedVariableScope.TestCase), // The status of the previous test case: either PASS, FAIL, or an empty string when no tests have been executed. 43 | PREV_TEST_MESSAGE("${PREV_TEST_MESSAGE}", ReservedVariableScope.TestCase), // The possible error message of the previous test case. 44 | TEST_NAME("${TEST_NAME}", ReservedVariableScope.TestCase), // The name of the current test case. 45 | TEST_TAGS("@{TEST_TAGS}", ReservedVariableScope.TestCase), // Contains the tags of the current test case in alphabetical order. Can be modified dynamically using Set Tags and Remove Tags keywords. 46 | TEST_DOCUMENTATION("${TEST_DOCUMENTATION}", ReservedVariableScope.TestCase), // The documentation of the current test case. Can be set dynamically using using Set Test Documentation keyword. 47 | // Scope Test Teardown 48 | TEST_STATUS("${TEST_STATUS}", ReservedVariableScope.TestTeardown), // The status of the current test case, either PASS or FAIL. 49 | TEST_MESSAGE("${TEST_MESSAGE}", ReservedVariableScope.TestTeardown), // The message of the current test case. 50 | // Scope: Keyword Teardown 51 | KEYWORD_STATUS("${KEYWORD_STATUS}", ReservedVariableScope.KeywordTeardown), // The status of the current keyword, either PASS or FAIL. 52 | KEYWORD_MESSAGE("${KEYWORD_MESSAGE}", ReservedVariableScope.KeywordTeardown), // The possible error message of the current keyword. 53 | // Scope: Suite Teardown 54 | SUITE_STATUS("${SUITE_STATUS}", ReservedVariableScope.SuiteTeardown), // The status of the current test suite, either PASS or FAIL. 55 | SUITE_MESSAGE("${SUITE_MESSAGE}", ReservedVariableScope.SuiteTeardown), // The full message of the current test suite, including statistics. 56 | ; 57 | 58 | private static final String SCALAR = "${%s}"; 59 | private final String variable; 60 | private final ReservedVariableScope scope; 61 | 62 | ReservedVariable(@NotNull String variable, @NotNull ReservedVariableScope scope) { 63 | this.variable = variable; 64 | this.scope = scope; 65 | } 66 | 67 | @NotNull 68 | public static String wrapToScalar(@NotNull String text) { 69 | return String.format(SCALAR, text); 70 | } 71 | 72 | @NotNull 73 | public String getVariable() { 74 | return this.variable; 75 | } 76 | 77 | @NotNull 78 | public ReservedVariableScope getScope() { 79 | return this.scope; 80 | } 81 | 82 | @Nullable 83 | public PsiElement getVariable(@NotNull Project project) { 84 | return this.scope.getVariable(project); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/execution/RobotRunConfigurationProducer.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.execution; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotFeatureFileType; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.DefinedKeyword; 5 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordDefinitionImpl; 6 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.RobotUtil; 7 | import com.intellij.execution.Location; 8 | import com.intellij.execution.actions.ConfigurationContext; 9 | import com.intellij.execution.actions.LazyRunConfigurationProducer; 10 | import com.intellij.execution.configurations.ConfigurationFactory; 11 | import com.intellij.openapi.projectRoots.Sdk; 12 | import com.intellij.openapi.roots.ProjectRootManager; 13 | import com.intellij.openapi.util.Ref; 14 | import com.intellij.openapi.vfs.VirtualFile; 15 | import com.intellij.psi.PsiElement; 16 | import com.jetbrains.python.run.PythonConfigurationType; 17 | import com.jetbrains.python.run.PythonRunConfiguration; 18 | import org.jetbrains.annotations.NotNull; 19 | 20 | import java.util.Collection; 21 | 22 | public class RobotRunConfigurationProducer extends LazyRunConfigurationProducer { 23 | 24 | @Override 25 | protected boolean setupConfigurationFromContext(@NotNull PythonRunConfiguration runConfig, 26 | @NotNull ConfigurationContext context, 27 | @NotNull Ref sourceElement) { 28 | if (isValidRobotExecutableScript(context)) { 29 | String runParam = getRunParameters(context); 30 | runConfig.setUseModuleSdk(false); 31 | runConfig.setModuleMode(true); 32 | runConfig.setScriptName("robot.run"); 33 | runConfig.setWorkingDirectory(context.getProject().getBasePath()); 34 | runConfig.setScriptParameters(runParam); 35 | Sdk sdk = ProjectRootManager.getInstance(context.getProject()).getProjectSdk(); 36 | if (sdk != null) { 37 | runConfig.setSdkHome(sdk.getHomePath()); 38 | } 39 | runConfig.setName(getRunDisplayName(context)); 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | @NotNull 46 | private static String getRunParameters(ConfigurationContext context) { 47 | String suiteName = getSuiteName(context); 48 | String testCaseName = getTestCaseName(context); 49 | return !testCaseName.equals("") ? "--test \"" + suiteName + "." + testCaseName + "\" ." : 50 | "--suite \"" + suiteName + "\" ."; 51 | } 52 | 53 | @NotNull 54 | private static String getRunDisplayName(ConfigurationContext context) { 55 | Location location = context.getLocation(); 56 | assert location != null; 57 | VirtualFile file = location.getVirtualFile(); 58 | assert file != null; 59 | String testCaseName = getTestCaseName(context); 60 | return !testCaseName.equals("") ? testCaseName : file.getName(); 61 | } 62 | 63 | @NotNull 64 | private static String getSuiteName(ConfigurationContext context) { 65 | String projectName = context.getProject().getName(); 66 | Location location = context.getLocation(); 67 | assert location != null; 68 | VirtualFile file = location.getVirtualFile(); 69 | assert file != null; 70 | String suitePathName = file.getPath() 71 | .replace(context.getProject().getBasePath() + "/", "") 72 | .replace("/", "."); 73 | suitePathName = suitePathName.substring(0, suitePathName.lastIndexOf('.')); 74 | return projectName + "." + suitePathName; 75 | } 76 | 77 | @Override 78 | public boolean isConfigurationFromContext(@NotNull PythonRunConfiguration runConfig, 79 | @NotNull ConfigurationContext context) { 80 | if (isValidRobotExecutableScript(context)) { 81 | String runParam = getRunParameters(context); 82 | boolean ret = runParam.trim(). 83 | equals(runConfig.getScriptParameters().trim()); 84 | if (ret) { 85 | runConfig.setName(getRunDisplayName(context)); 86 | } 87 | return ret; 88 | } 89 | return false; 90 | } 91 | 92 | private boolean isValidRobotExecutableScript(@NotNull ConfigurationContext context) { 93 | Location location = context.getLocation(); 94 | if (location == null) { 95 | return false; 96 | } 97 | PsiElement psiElement = location.getPsiElement(); 98 | VirtualFile file = location.getVirtualFile(); 99 | if (file == null) { 100 | return false; 101 | } 102 | if (!(file.getFileType() instanceof RobotFeatureFileType)) { 103 | return false; 104 | } 105 | Collection testCases = RobotUtil.getTestCasesFromElement(psiElement); 106 | // do not have test case 107 | return !testCases.isEmpty(); 108 | } 109 | 110 | @NotNull 111 | private static String getTestCaseName(@NotNull ConfigurationContext context) { 112 | Location location = context.getLocation(); 113 | if (location != null) { 114 | return getKeywordNameFromAnyElement(location.getPsiElement()); 115 | } 116 | return ""; 117 | } 118 | 119 | @NotNull 120 | private static String getKeywordNameFromAnyElement(PsiElement element) { 121 | while (true) { 122 | if (element instanceof KeywordDefinitionImpl) { 123 | return ((KeywordDefinitionImpl) element).getKeywordName(); 124 | } 125 | element = element.getParent(); 126 | if (element == null) { 127 | return ""; 128 | } 129 | } 130 | } 131 | 132 | 133 | @NotNull 134 | @Override 135 | public ConfigurationFactory getConfigurationFactory() { 136 | return PythonConfigurationType.getInstance().getConfigurationFactories()[0]; 137 | } 138 | } -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/structure/RobotStructureViewElement.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.structure; 2 | 3 | 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.*; 5 | import com.intellij.ide.structureView.StructureViewTreeElement; 6 | import com.intellij.navigation.ColoredItemPresentation; 7 | import com.intellij.navigation.ItemPresentation; 8 | import com.intellij.openapi.editor.colors.TextAttributesKey; 9 | import com.intellij.pom.Navigatable; 10 | import com.intellij.psi.PsiElement; 11 | import com.intellij.psi.util.PsiTreeUtil; 12 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.*; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import javax.swing.*; 17 | import java.util.ArrayList; 18 | import java.util.Collection; 19 | 20 | /** 21 | * @author mrubino 22 | * @since 2015-11-23 23 | */ 24 | public class RobotStructureViewElement implements StructureViewTreeElement { 25 | 26 | private static final String UNKNOWN = "Unknown"; 27 | private static final StructureViewTreeElement[] EMPTY = {}; 28 | 29 | private final PsiElement element; 30 | private final RobotViewElementType type; 31 | 32 | protected RobotStructureViewElement(PsiElement element) { 33 | this(element, RobotViewElementType.File); 34 | } 35 | 36 | private RobotStructureViewElement(PsiElement element, RobotViewElementType type) { 37 | this.element = element; 38 | this.type = type; 39 | } 40 | 41 | protected StructureViewTreeElement createChild(PsiElement element, RobotViewElementType type) { 42 | return new RobotStructureViewElement(element, type); 43 | } 44 | 45 | @Override 46 | public PsiElement getValue() { 47 | return this.element; 48 | } 49 | 50 | @Override 51 | public void navigate(boolean requestFocus) { 52 | if (this.element instanceof Navigatable) { 53 | ((Navigatable) this.element).navigate(requestFocus); 54 | } 55 | } 56 | 57 | @Override 58 | public boolean canNavigate() { 59 | return this.type != RobotViewElementType.File && 60 | this.element instanceof Navigatable && ((Navigatable) this.element).canNavigate(); 61 | } 62 | 63 | @Override 64 | public boolean canNavigateToSource() { 65 | return this.type != RobotViewElementType.File && 66 | this.element instanceof Navigatable && ((Navigatable) this.element).canNavigateToSource(); 67 | } 68 | 69 | @Override 70 | public boolean equals(Object o) { 71 | if (o instanceof RobotStructureViewElement) { 72 | String name = getDisplayName(); 73 | String otherName = ((RobotStructureViewElement) o).getDisplayName(); 74 | return name.equals(otherName); 75 | } 76 | return false; 77 | } 78 | 79 | @Override 80 | public int hashCode() { 81 | return getDisplayName().hashCode(); 82 | } 83 | 84 | @NotNull 85 | public StructureViewTreeElement[] getChildren() { 86 | if (this.element instanceof RobotFile) { 87 | Collection children = new ArrayList(); 88 | Heading[] headings = PsiTreeUtil.getChildrenOfType(this.element, Heading.class); 89 | if (headings != null) { 90 | for (Heading heading : headings) { 91 | children.add(createChild(heading, RobotViewElementType.Heading)); 92 | for (DefinedKeyword keyword : heading.getDefinedKeywords()) { 93 | if (keyword instanceof KeywordDefinition) { 94 | children.add(createChild((KeywordDefinition) keyword, RobotViewElementType.Keyword)); 95 | } 96 | } 97 | for (DefinedKeyword keyword : heading.getTestCases()) { 98 | if (keyword instanceof KeywordDefinition) { 99 | children.add(createChild((KeywordDefinition) keyword, RobotViewElementType.TestCase)); 100 | } 101 | } 102 | for (DefinedVariable variable : heading.getDefinedVariables()) { 103 | if (variable instanceof VariableDefinition) { 104 | children.add(createChild((VariableDefinition) variable, RobotViewElementType.Variable)); 105 | } 106 | } 107 | } 108 | } 109 | return children.toArray(new StructureViewTreeElement[children.size()]); 110 | } else { 111 | return EMPTY; 112 | } 113 | } 114 | 115 | @NotNull 116 | private String getDisplayName() { 117 | if (this.element instanceof RobotFile) { 118 | return ((RobotFile) this.element).getName(); 119 | } else if (this.element instanceof RobotStatement) { 120 | return ((RobotStatement) this.element).getPresentableText(); 121 | } else { 122 | return UNKNOWN; 123 | } 124 | } 125 | 126 | @NotNull 127 | public RobotViewElementType getType() { 128 | return this.type; 129 | } 130 | 131 | @Nullable 132 | private Icon getDisplayIcon() { 133 | return this.type.getIcon(this.element); 134 | } 135 | 136 | @NotNull 137 | @Override 138 | public ItemPresentation getPresentation() { 139 | return new ColoredItemPresentation() { 140 | @Nullable 141 | @Override 142 | public String getPresentableText() { 143 | return getDisplayName(); 144 | } 145 | 146 | @Nullable 147 | @Override 148 | public TextAttributesKey getTextAttributesKey() { 149 | return null; 150 | } 151 | 152 | @Nullable 153 | @Override 154 | public String getLocationString() { 155 | return null; 156 | } 157 | 158 | @Nullable 159 | @Override 160 | public Icon getIcon(boolean open) { 161 | return getDisplayIcon(); 162 | } 163 | }; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/main/java/com/github/jnhyperion/hyperrobotframeworkplugin/ide/search/RobotPythonReferenceSearch.java: -------------------------------------------------------------------------------- 1 | package com.github.jnhyperion.hyperrobotframeworkplugin.ide.search; 2 | 3 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PatternUtil; 4 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceCollector; 5 | import com.intellij.openapi.application.QueryExecutorBase; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.vfs.VirtualFile; 8 | import com.intellij.psi.*; 9 | import com.intellij.psi.search.*; 10 | import com.intellij.psi.search.searches.ReferencesSearch; 11 | import com.intellij.util.Processor; 12 | import com.github.jnhyperion.hyperrobotframeworkplugin.ide.config.RobotOptionsProvider; 13 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.RobotFeatureFileType; 14 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordDefinition; 15 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.KeywordInvokable; 16 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.RobotFile; 17 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.element.RobotStatement; 18 | import com.github.jnhyperion.hyperrobotframeworkplugin.psi.util.PerformanceEntity; 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.Collection; 22 | import java.util.HashSet; 23 | 24 | /** 25 | * @author mrubino 26 | * @since 2016-01-04 27 | */ 28 | public class RobotPythonReferenceSearch extends QueryExecutorBase { 29 | 30 | public RobotPythonReferenceSearch() { 31 | super(true); 32 | } 33 | 34 | @Override 35 | public void processQuery(ReferencesSearch.@NotNull SearchParameters params, @NotNull Processor processor) { 36 | SearchScope searchScope = params.getEffectiveSearchScope(); 37 | boolean localScope = false; 38 | if (searchScope instanceof GlobalSearchScope) { 39 | searchScope = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope) searchScope, RobotFeatureFileType.getInstance()); 40 | } else if (searchScope instanceof LocalSearchScope) { 41 | localScope = true; 42 | } 43 | 44 | PsiElement element = params.getElementToSearch(); 45 | if (element instanceof PsiNameIdentifierOwner) { 46 | if (element instanceof KeywordDefinition) { 47 | KeywordDefinition definition = (KeywordDefinition) element; 48 | // this should really be part of the search options 49 | boolean enableInlineSearch = RobotOptionsProvider.getInstance(params.getProject()).inlineVariableSearch(); 50 | if (definition.hasInlineVariables() && (localScope || enableInlineSearch)) { 51 | processKeywordWithInline(definition, searchScope, processor, params.getProject()); 52 | } else { 53 | processRobotStatement(definition, params, searchScope); 54 | } 55 | } else { 56 | processPython((PsiNameIdentifierOwner) element, params, searchScope); 57 | } 58 | } else if (element instanceof RobotStatement) { 59 | processRobotStatement((RobotStatement) element, params, searchScope); 60 | } 61 | } 62 | 63 | private void processPython(@NotNull PsiNameIdentifierOwner element, 64 | @NotNull ReferencesSearch.SearchParameters params, 65 | @NotNull SearchScope searchScope) { 66 | PsiElement identifier = element.getNameIdentifier(); 67 | if (identifier != null) { 68 | String text = identifier.getText(); 69 | params.getOptimizer().searchWord(text, searchScope, UsageSearchContext.ANY, false, element); 70 | String keyword = PatternUtil.functionToKeyword(text); 71 | params.getOptimizer().searchWord(keyword, searchScope, UsageSearchContext.ANY, false, element); 72 | } 73 | } 74 | 75 | private void processRobotStatement(@NotNull RobotStatement element, 76 | @NotNull ReferencesSearch.SearchParameters params, 77 | @NotNull SearchScope searchScope) { 78 | String text = element.getPresentableText(); 79 | params.getOptimizer().searchWord(text, searchScope, UsageSearchContext.ANY, false, element); 80 | } 81 | 82 | private void processKeywordWithInline(@NotNull KeywordDefinition element, 83 | @NotNull SearchScope searchScope, 84 | @NotNull Processor processor, 85 | @NotNull Project project) { 86 | Collection files; 87 | 88 | if (searchScope instanceof LocalSearchScope) { 89 | files = new HashSet(); 90 | for (PsiElement scopeElement : ((LocalSearchScope) searchScope).getScope()) { 91 | files.add(scopeElement.getContainingFile().getVirtualFile()); 92 | } 93 | } else { 94 | files = FileTypeIndex.getFiles(RobotFeatureFileType.getInstance(), 95 | GlobalSearchScope.projectScope(project)); 96 | } 97 | processKeywordWithInline(element, processor, project, files); 98 | } 99 | 100 | private void processKeywordWithInline(@NotNull KeywordDefinition element, 101 | @NotNull Processor processor, 102 | @NotNull Project project, 103 | @NotNull Collection files) { 104 | PerformanceCollector debug = new PerformanceCollector((PerformanceEntity) element, "ReferenceSearch"); 105 | boolean process = true; 106 | for (VirtualFile file : files) { 107 | final PsiFile psiFile = PsiManager.getInstance(project).findFile(file); 108 | if (psiFile instanceof RobotFile) { 109 | Collection keywords = ((RobotFile) psiFile).getKeywordReferences(element); 110 | for (KeywordInvokable keyword : keywords) { 111 | PsiReference reference = keyword.getReference(); 112 | if (reference != null && reference.isReferenceTo(element)) { 113 | process = processor.process(reference); 114 | } 115 | // abort if we do not want to process more 116 | if (!process) { 117 | break; 118 | } 119 | } 120 | } 121 | // abort if we do not want to process more 122 | if (!process) { 123 | break; 124 | } 125 | } 126 | debug.complete(); 127 | } 128 | } 129 | --------------------------------------------------------------------------------