├── .gitignore ├── LICENSE ├── META-INF └── plugin.xml ├── README.md ├── intellibot.jar ├── resources ├── images │ ├── robot_icon.png │ └── robot_icon@2x.png └── inspectionDescriptions │ ├── RobotGherkinInspection.html │ ├── RobotImportNotFound.html │ ├── RobotImportNotUsed.html │ ├── RobotKeywordDefinitionStartingWithGherkin.html │ ├── RobotKeywordNotFound.html │ ├── RobotNestedVariable.html │ ├── RobotNestedVariableDefinition.html │ └── RobotVariableNotFound.html ├── src └── com │ └── millennialmedia │ └── intellibot │ ├── RobotBundle.java │ ├── RobotBundle.properties │ ├── ide │ ├── RobotCommenter.java │ ├── RobotCompletionContributor.java │ ├── RobotFoldingBuilder.java │ ├── config │ │ ├── RobotColorsPage.java │ │ ├── RobotConfiguration.form │ │ ├── RobotConfiguration.java │ │ └── RobotOptionsProvider.java │ ├── icons │ │ └── RobotIcons.java │ ├── inspections │ │ ├── SimpleInspection.java │ │ ├── SimpleInspectionVisitor.java │ │ ├── SimpleRobotInspection.java │ │ ├── cleanup │ │ │ └── RobotImportNotUsed.java │ │ ├── compilation │ │ │ ├── RobotImportNotFound.java │ │ │ ├── RobotKeywordNotFound.java │ │ │ └── RobotVariableNotFound.java │ │ ├── complexity │ │ │ ├── RobotNestedVariable.java │ │ │ └── RobotNestedVariableDefinition.java │ │ └── readability │ │ │ ├── RobotGherkinInspection.java │ │ │ └── RobotKeywordDefinitionStartingWithGherkin.java │ ├── search │ │ └── RobotPythonReferenceSearch.java │ ├── structure │ │ ├── RobotStructureViewElement.java │ │ ├── RobotStructureViewFactory.java │ │ ├── RobotStructureViewModel.java │ │ ├── RobotTypeFilter.java │ │ ├── RobotTypeSorter.java │ │ └── RobotViewElementType.java │ └── usage │ │ ├── RobotFindUsagesProvider.java │ │ ├── RobotKeywordGroupingRuleProvider.java │ │ └── RobotWordScanner.java │ └── psi │ ├── RecommendationWord.java │ ├── RobotElementType.java │ ├── RobotFeatureFileType.java │ ├── RobotFileTypeHandler.java │ ├── RobotHighlighter.java │ ├── RobotKeywordProvider.java │ ├── RobotKeywordTable.java │ ├── RobotLanguage.java │ ├── RobotLexer.java │ ├── RobotParser.java │ ├── RobotParserDefinition.java │ ├── RobotPsiManager.java │ ├── RobotSyntaxHighlightingFactory.java │ ├── RobotTokenTypes.java │ ├── dto │ ├── ImportType.java │ ├── KeywordDto.java │ └── VariableDto.java │ ├── element │ ├── Argument.java │ ├── ArgumentImpl.java │ ├── BracketSetting.java │ ├── BracketSettingImpl.java │ ├── DefinedKeyword.java │ ├── DefinedVariable.java │ ├── Heading.java │ ├── HeadingImpl.java │ ├── Import.java │ ├── ImportImpl.java │ ├── KeywordDefinition.java │ ├── KeywordDefinitionId.java │ ├── KeywordDefinitionIdImpl.java │ ├── KeywordDefinitionImpl.java │ ├── KeywordFile.java │ ├── KeywordInvokable.java │ ├── KeywordInvokableImpl.java │ ├── KeywordStatement.java │ ├── KeywordStatementImpl.java │ ├── RobotFile.java │ ├── RobotFileImpl.java │ ├── RobotPsiElementBase.java │ ├── RobotStatement.java │ ├── Setting.java │ ├── SettingImpl.java │ ├── Variable.java │ ├── VariableDefinition.java │ ├── VariableDefinitionId.java │ ├── VariableDefinitionIdImpl.java │ ├── VariableDefinitionImpl.java │ └── VariableImpl.java │ ├── manip │ ├── ArgumentManipulator.java │ ├── KeywordInvokableManipulator.java │ └── VariableManipulator.java │ ├── ref │ ├── PythonResolver.java │ ├── ResolverUtils.java │ ├── RobotArgumentReference.java │ ├── RobotFileManager.java │ ├── RobotKeywordReference.java │ ├── RobotPythonClass.java │ ├── RobotPythonFile.java │ ├── RobotPythonWrapper.java │ └── RobotVariableReference.java │ └── util │ ├── PatternBuilder.java │ ├── PatternUtil.java │ ├── PerformanceCollector.java │ ├── PerformanceEntity.java │ ├── ReservedVariable.java │ └── ReservedVariableScope.java ├── test └── com │ └── millennialmedia │ └── intellibot │ ├── ResourceLoader.java │ ├── ide │ ├── AbstractRobotIdeTest.java │ ├── RobotFindUsagesTest.java │ ├── RobotFoldingTest.java │ └── RobotHighlightTest.java │ └── psi │ ├── RobotLexerTest.java │ ├── RobotParserTest.java │ ├── element │ └── KeywordDefinitionTest.java │ ├── ref │ └── RobotFileManagerTest.java │ └── util │ ├── KeywordParserTest.java │ ├── PatternUtilBuildPatternTest.java │ └── PatternUtilGetPresentableTextTest.java ├── testData ├── ide │ ├── folding │ │ └── keywordFolding.robot │ └── usages │ │ ├── findInlineKeywordByDefinition.robot │ │ ├── findInlineKeywordByUsage.robot │ │ ├── findInlineVariableByDefinition.robot │ │ ├── findInlineVariableByUsage.robot │ │ ├── findKeywordByDefinition.robot │ │ ├── findKeywordByUsage.robot │ │ ├── findVariableByDefinition.robot │ │ └── findVariableByUsage.robot └── samples │ ├── Demo.lexer.txt │ ├── Demo.robot │ ├── Demo.txt │ ├── EmptyHeaders.lexer.txt │ ├── EmptyHeaders.robot │ ├── EmptyHeaders.txt │ ├── Junk.lexer.txt │ ├── Junk.robot │ ├── Junk.txt │ ├── ParsingTestData.lexer.txt │ ├── ParsingTestData.robot │ ├── ParsingTestData.txt │ ├── TrimmedVariables.robot │ ├── TrimmedVariables.txt │ ├── Variables.lexer.txt │ ├── Variables.robot │ └── Variables.txt └── wiki ├── dev_setup ├── intellij_sdk.png ├── plugin_config.png └── python_library.png ├── features ├── code_folding.png ├── demo_complete.png ├── find_usages.png ├── jump_to_source.png ├── keyword_recommendation.png ├── structure.png └── undefined_keyword.png ├── python_interpreter ├── intellij │ ├── module_interpreter.png │ ├── project_sdk.png │ └── python_plugin.png └── pycharm │ ├── console_interpreter.png │ └── project_interpreter.png ├── robot_options ├── event_log.png └── options.png ├── test_debugging └── debug_settings.png └── using_txt_files └── txt_file_type.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | out/ 3 | target/ 4 | *.iml -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 millenialmedia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## IntelliJ/PyCharm Plugin for Robot Automation Framework 2 | 3 | This is a work in progress (the product of a 24 hour hack match), though at this point I have devoted far more time than that. 4 | Related feature request to JetBrains: [IDEA-97678](http://youtrack.jetbrains.com/issue/IDEA-97678). 5 | **Here is a growing list of [features](https://github.com/millennialmedia/intellibot/wiki/Features).** 6 | 7 | ![Sample](/wiki/features/demo_complete.png) 8 | 9 | ### Installation & Usage 10 | 11 | Note that this plugin should work in either IntelliJ or PyCharm, but that PyCharm is far less used (and thus tested) personally. 12 | 13 | **The plugin is now hosted in the JetBrains [repositories](http://plugins.jetbrains.com/plugin/7386?pr=github).** 14 | This means you can install it directly form your IDE. 15 | Just search for 'Intellibot' under 'Browse Repositories...'. 16 | 17 | You can also install the plugin manually. 18 | To do so you can either download and [compile](https://github.com/millennialmedia/intellibot/wiki/Development-Setup) the project yourself. 19 | Or download the [intellibot.jar](https://github.com/millennialmedia/intellibot/raw/master/intellibot.jar) file in the project. 20 | You can then install this plugin to your IDE by using the 'Install plugin from disk...' option. 21 | This version may be slightly ahead of the JetBrains repository though potentially slightly less stable. 22 | 23 | The plugin will, by default, operate against any ".robot" file in the project. 24 | **You can add ".txt" support by following these [instructions](https://github.com/millennialmedia/intellibot/wiki/Supporting-.txt-Files).** 25 | If you are using PyCharm then any Python libraries should be detected when you setup your interpreter. 26 | If you are using IntelliJ then you can install the Python plugin. 27 | Both instructions can be found in this [wiki page](https://github.com/millennialmedia/intellibot/wiki/Python-Interpreter). 28 | -------------------------------------------------------------------------------- /intellibot.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/intellibot.jar -------------------------------------------------------------------------------- /resources/images/robot_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/resources/images/robot_icon.png -------------------------------------------------------------------------------- /resources/images/robot_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/resources/images/robot_icon@2x.png -------------------------------------------------------------------------------- /resources/inspectionDescriptions/RobotGherkinInspection.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This inspection triggers when the format of the gherkin text is off (GIVEN, when, tHeN). 5 | Scenarios will generally read better if you keep your structure sentence-like. 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/inspectionDescriptions/RobotImportNotFound.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This inspection triggers when the library or resource is not defined. 5 | 6 | 7 | -------------------------------------------------------------------------------- /resources/inspectionDescriptions/RobotImportNotUsed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This inspection triggers when the resource is not used. 5 | Note that this does not currently cover libraries. 6 |

7 | Note that this can be a false positive regarding keywords that take keywords as an argument. 8 |
9 | 10 | -------------------------------------------------------------------------------- /resources/inspectionDescriptions/RobotKeywordDefinitionStartingWithGherkin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This inspection triggers when a keyword definition starts with gherkin. 5 | This is often redundant and so can be removed. 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/inspectionDescriptions/RobotKeywordNotFound.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This inspection triggers when the keyword is not defined. 5 | This includes imports of the current file; including python if configured. 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/inspectionDescriptions/RobotNestedVariable.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This inspection triggers when nested variables are used (${variable${nested}}). 5 | This generally makes the code much harder to read and debug. 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/inspectionDescriptions/RobotNestedVariableDefinition.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This inspection triggers when nested variable definitions are used (${variable${nested}}). 5 | This generally makes the code much harder to read and debug. 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/inspectionDescriptions/RobotVariableNotFound.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This inspection triggers when the variable is not defined. 5 | This includes imports of the current file; including python if configured. 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/RobotBundle.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot; 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 = "com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/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.heading=Heading 7 | color.settings.import=Import 8 | color.settings.keyword=Keyword 9 | color.settings.keywordDefinition=Keyword Definition 10 | color.settings.setting=Setting 11 | color.settings.variable=Variable 12 | color.settings.variableDefinition=Variable Definition 13 | 14 | # Python Support Warning 15 | plugin.python.missing=If you configure a python interpreter you will be able to get code completion around imported libraries in your robot files. 16 | plugin.python.missing.title=Intellibot: No Python Support for Robot 17 | 18 | # Structure 19 | action.structureView.show.files=Shows Files 20 | action.structureView.show.headings=Show Headings 21 | action.structureView.show.testCases=Show Test Cases 22 | action.structureView.show.keywords=Show Keywords 23 | action.structureView.show.variables=Show Variables 24 | action.structureView.sort.type=Sort by Type 25 | 26 | # Find Usages 27 | usage.declaration=Declaration 28 | usage.descriptive.argument=argument 29 | usage.descriptive.import=resource 30 | usage.descriptive.keyword=keyword 31 | usage.descriptive.variable=variable 32 | 33 | # Inspections 34 | # Inspection Groups 35 | INSP.GROUP.complexity=Complexity 36 | INSP.GROUP.readability=Readability 37 | INSP.GROUP.compilation=Compilation 38 | INSP.GROUP.cleanup=Clean Up 39 | # RobotGherkinInspection 40 | INSP.NAME.gherkin.format=Gherkin format 41 | INSP.gherkin.format=Incorrect gherkin format 42 | INSP.OPT.gherkin.format.upper=Allow all uppercase gherkin 43 | # RobotKeywordDefinitionStartingWithGherkin 44 | INSP.NAME.define.keyword.gherkin.start=Keyword starting with gherkin 45 | INSP.define.keyword.gherkin.start=Keyword starting with gherkin 46 | # RobotKeywordNotFound 47 | INSP.NAME.keyword.undefined=Undefined keyword 48 | INSP.keyword.undefined=Keyword definition not found 49 | # RobotVariableNotFound 50 | INSP.NAME.variable.undefined=Undefined variable 51 | INSP.variable.undefined=Variable definition not found 52 | # RobotImportNotFound 53 | INSP.NAME.import.undefined=Import not found 54 | INSP.import.undefined=Import file not found 55 | # RobotImportNotUsed 56 | INSP.NAME.import.unused=Import not used 57 | INSP.import.unused=Unused import statement 58 | # RobotNestedVariable 59 | INSP.NAME.variable.nested=Nested variable 60 | INSP.variable.nested=Usage of a nested variable 61 | # RobotNestedVariableDefinition 62 | INSP.NAME.variableDefinition.nested=Nested variable definition 63 | INSP.variableDefinition.nested=Usage of a nested variable definition -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/RobotCommenter.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/RobotFoldingBuilder.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.psi.RobotTokenTypes; 12 | import com.millennialmedia.intellibot.psi.element.Heading; 13 | import com.millennialmedia.intellibot.psi.element.KeywordDefinition; 14 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/config/RobotColorsPage.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.RobotBundle; 9 | import com.millennialmedia.intellibot.psi.RobotFeatureFileType; 10 | import com.millennialmedia.intellibot.psi.RobotHighlighter; 11 | import com.millennialmedia.intellibot.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.variable"), RobotHighlighter.VARIABLE), 67 | new AttributesDescriptor(RobotBundle.message("color.settings.variableDefinition"), RobotHighlighter.VARIABLE_DEFINITION), 68 | new AttributesDescriptor(RobotBundle.message("color.settings.keyword"), RobotHighlighter.KEYWORD), 69 | new AttributesDescriptor(RobotBundle.message("color.settings.keywordDefinition"), RobotHighlighter.KEYWORD_DEFINITION), 70 | new AttributesDescriptor(RobotBundle.message("color.settings.bracketSetting"), RobotHighlighter.BRACKET_SETTING), 71 | new AttributesDescriptor(RobotBundle.message("color.settings.setting"), RobotHighlighter.SETTING), 72 | new AttributesDescriptor(RobotBundle.message("color.settings.import"), RobotHighlighter.IMPORT) 73 | }; 74 | 75 | @Nullable 76 | @Override 77 | public Icon getIcon() { 78 | return RobotFeatureFileType.getInstance().getIcon(); 79 | } 80 | 81 | @NotNull 82 | @Override 83 | public SyntaxHighlighter getHighlighter() { 84 | return new RobotHighlighter(RobotKeywordProvider.getInstance()); 85 | } 86 | 87 | @NotNull 88 | @Override 89 | public String getDemoText() { 90 | return DEMO_TEXT; 91 | } 92 | 93 | @Nullable 94 | @Override 95 | public Map getAdditionalHighlightingTagToDescriptorMap() { 96 | return null; 97 | } 98 | 99 | @NotNull 100 | @Override 101 | public AttributesDescriptor[] getAttributeDescriptors() { 102 | return ATTRIBUTES; 103 | } 104 | 105 | @NotNull 106 | @Override 107 | public ColorDescriptor[] getColorDescriptors() { 108 | return COLORS; 109 | } 110 | 111 | @NotNull 112 | @Override 113 | public String getDisplayName() { 114 | return NAME; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/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/com/millennialmedia/intellibot/ide/config/RobotConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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 org.jetbrains.annotations.Nls; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import javax.swing.*; 11 | 12 | /** 13 | * @author mrubino 14 | * @since 2014-06-26 15 | */ 16 | public class RobotConfiguration implements SearchableConfigurable, Configurable.NoScroll { 17 | 18 | private RobotOptionsProvider provider; 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 | public RobotConfiguration(@NotNull RobotOptionsProvider provider) { 28 | this.provider = provider; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getId() { 34 | return getHelpTopic(); 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Runnable enableSearch(String s) { 40 | return null; 41 | } 42 | 43 | @Nls 44 | @Override 45 | public String getDisplayName() { 46 | return "Robot Options"; 47 | } 48 | 49 | @NotNull 50 | @Override 51 | public String getHelpTopic() { 52 | return "reference.idesettings.robot"; 53 | } 54 | 55 | @Nullable 56 | @Override 57 | public JComponent createComponent() { 58 | return this.panel; 59 | } 60 | 61 | @Override 62 | public boolean isModified() { 63 | return this.provider.isDebug() != this.enableDebug.isSelected() || 64 | this.provider.allowTransitiveImports() != this.allowTransitiveImports.isSelected() || 65 | this.provider.allowGlobalVariables() != this.allowGlobalVariables.isSelected() || 66 | this.provider.capitalizeKeywords() != this.capitalizeKeywords.isSelected() || 67 | this.provider.inlineVariableSearch() != this.inlineVariableSearch.isSelected(); 68 | } 69 | 70 | @Override 71 | public void apply() throws ConfigurationException { 72 | this.provider.setDebug(this.enableDebug.isSelected()); 73 | this.provider.setTransitiveImports(this.allowTransitiveImports.isSelected()); 74 | this.provider.setGlobalVariables(this.allowGlobalVariables.isSelected()); 75 | this.provider.setCapitalizeKeywords(this.capitalizeKeywords.isSelected()); 76 | this.provider.setInlineVariableSearch(this.inlineVariableSearch.isSelected()); 77 | } 78 | 79 | @Override 80 | public void reset() { 81 | this.enableDebug.setSelected(this.provider.isDebug()); 82 | this.allowTransitiveImports.setSelected(this.provider.allowTransitiveImports()); 83 | this.allowGlobalVariables.setSelected(this.provider.allowGlobalVariables()); 84 | this.capitalizeKeywords.setSelected(this.provider.capitalizeKeywords()); 85 | this.inlineVariableSearch.setSelected(this.provider.inlineVariableSearch()); 86 | } 87 | 88 | @Override 89 | public void disposeUIResources() { 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/config/RobotOptionsProvider.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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(file = 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 = false; 24 | public boolean inlineVariableSearch = false; 25 | } 26 | 27 | private 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/com/millennialmedia/intellibot/ide/icons/RobotIcons.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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_icon.png"); 15 | public static final Icon HEADING = AllIcons.Nodes.Tag; 16 | public static final Icon KEYWORD_DEFINITION = AllIcons.Nodes.Method; 17 | public static final Icon TEST_CASE = AllIcons.RunConfigurations.Junit; 18 | public static final Icon VARIABLE_DEFINITION = AllIcons.Nodes.Variable; 19 | 20 | private RobotIcons() { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/inspections/SimpleInspection.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/inspections/SimpleInspectionVisitor.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/inspections/SimpleRobotInspection.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/inspections/cleanup/RobotImportNotUsed.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.inspections.cleanup; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiFile; 5 | import com.intellij.psi.PsiReference; 6 | import com.millennialmedia.intellibot.RobotBundle; 7 | import com.millennialmedia.intellibot.ide.inspections.SimpleRobotInspection; 8 | import com.millennialmedia.intellibot.psi.RobotTokenTypes; 9 | import com.millennialmedia.intellibot.psi.element.Argument; 10 | import com.millennialmedia.intellibot.psi.element.Import; 11 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/inspections/compilation/RobotImportNotFound.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.inspections.compilation; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiReference; 5 | import com.millennialmedia.intellibot.RobotBundle; 6 | import com.millennialmedia.intellibot.ide.inspections.SimpleRobotInspection; 7 | import com.millennialmedia.intellibot.psi.RobotTokenTypes; 8 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/inspections/compilation/RobotKeywordNotFound.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.inspections.compilation; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiReference; 5 | import com.millennialmedia.intellibot.RobotBundle; 6 | import com.millennialmedia.intellibot.ide.inspections.SimpleRobotInspection; 7 | import com.millennialmedia.intellibot.psi.element.KeywordInvokable; 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 class RobotKeywordNotFound extends SimpleRobotInspection { 16 | 17 | @Nls 18 | @NotNull 19 | @Override 20 | public String getDisplayName() { 21 | return RobotBundle.message("INSP.NAME.keyword.undefined"); 22 | } 23 | 24 | @Override 25 | public boolean skip(PsiElement element) { 26 | if (element instanceof KeywordInvokable) { 27 | PsiReference reference = element.getReference(); 28 | if (reference != null && reference.resolve() != null) { 29 | return true; 30 | } 31 | 32 | String text = ((KeywordInvokable) element).getPresentableText(); 33 | if (text.startsWith(":")) { 34 | // TODO: for loops 35 | return true; 36 | } else if (text.startsWith("\\")) { 37 | // TODO: for loops 38 | return true; 39 | } 40 | return false; 41 | } else { 42 | return true; 43 | } 44 | } 45 | 46 | @Override 47 | public String getMessage() { 48 | return RobotBundle.message("INSP.keyword.undefined"); 49 | } 50 | 51 | @NotNull 52 | @Override 53 | protected String getGroupNameKey() { 54 | return "INSP.GROUP.compilation"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/inspections/compilation/RobotVariableNotFound.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.inspections.compilation; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiReference; 5 | import com.millennialmedia.intellibot.RobotBundle; 6 | import com.millennialmedia.intellibot.ide.inspections.SimpleRobotInspection; 7 | import com.millennialmedia.intellibot.psi.element.Argument; 8 | import com.millennialmedia.intellibot.psi.element.KeywordInvokable; 9 | import com.millennialmedia.intellibot.psi.element.KeywordStatement; 10 | import com.millennialmedia.intellibot.psi.element.Variable; 11 | import org.jetbrains.annotations.Nls; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * @author mrubino 18 | * @since 2014-06-18 19 | */ 20 | public class RobotVariableNotFound extends SimpleRobotInspection { 21 | 22 | @Nls 23 | @NotNull 24 | @Override 25 | public String getDisplayName() { 26 | return RobotBundle.message("INSP.NAME.variable.undefined"); 27 | } 28 | 29 | @Override 30 | public boolean skip(PsiElement element) { 31 | if (element instanceof Variable) { 32 | PsiReference reference = element.getReference(); 33 | if (reference != null && reference.resolve() != null) { 34 | return true; 35 | } 36 | if (((Variable) element).isNested()) { 37 | // TODO: nested variables 38 | return true; 39 | } 40 | 41 | // TODO: what is needed below this point... 42 | PsiElement container = element.getParent(); 43 | element = container; 44 | if (container instanceof Argument) { 45 | container = container.getParent(); 46 | } 47 | if (container instanceof KeywordStatement) { 48 | KeywordInvokable invokable = ((KeywordStatement) container).getInvokable(); 49 | String text = invokable == null ? null : invokable.getPresentableText(); 50 | if (text != null) { 51 | if (text.startsWith(":")) { 52 | // TODO: for loops 53 | return true; 54 | } else if (text.startsWith("\\")) { 55 | // TODO: for loops 56 | return true; 57 | } 58 | } 59 | // this is the case where we have a 'set test variable' call with more than one arg 60 | // the first is the variable name, the second is the value 61 | // if there is only one argument then we might want to see where it was created 62 | if (((KeywordStatement) container).getGlobalVariable() != null) { 63 | List arguments = ((KeywordStatement) container).getArguments(); 64 | if (arguments.size() > 1 && element == arguments.get(0)) { 65 | return true; 66 | } 67 | } 68 | } 69 | return false; 70 | } else { 71 | return true; 72 | } 73 | } 74 | 75 | @Override 76 | public String getMessage() { 77 | return RobotBundle.message("INSP.variable.undefined"); 78 | } 79 | 80 | @NotNull 81 | @Override 82 | protected String getGroupNameKey() { 83 | return "INSP.GROUP.compilation"; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/inspections/complexity/RobotNestedVariable.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.inspections.complexity; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.millennialmedia.intellibot.RobotBundle; 5 | import com.millennialmedia.intellibot.ide.inspections.SimpleRobotInspection; 6 | import com.millennialmedia.intellibot.psi.RobotTokenTypes; 7 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/inspections/complexity/RobotNestedVariableDefinition.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.inspections.complexity; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.millennialmedia.intellibot.RobotBundle; 5 | import com.millennialmedia.intellibot.ide.inspections.SimpleRobotInspection; 6 | import com.millennialmedia.intellibot.psi.RobotTokenTypes; 7 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/inspections/readability/RobotGherkinInspection.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.inspections.readability; 2 | 3 | import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; 4 | import com.intellij.psi.PsiElement; 5 | import com.millennialmedia.intellibot.RobotBundle; 6 | import com.millennialmedia.intellibot.ide.inspections.SimpleInspection; 7 | import com.millennialmedia.intellibot.ide.inspections.SimpleRobotInspection; 8 | import com.millennialmedia.intellibot.psi.RobotKeywordProvider; 9 | import com.millennialmedia.intellibot.psi.RobotTokenTypes; 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/com/millennialmedia/intellibot/ide/inspections/readability/RobotKeywordDefinitionStartingWithGherkin.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.inspections.readability; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.millennialmedia.intellibot.RobotBundle; 5 | import com.millennialmedia.intellibot.ide.inspections.SimpleRobotInspection; 6 | import com.millennialmedia.intellibot.psi.RobotKeywordProvider; 7 | import com.millennialmedia.intellibot.psi.RobotTokenTypes; 8 | import com.millennialmedia.intellibot.psi.element.KeywordDefinition; 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 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/structure/RobotStructureViewFactory.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/structure/RobotStructureViewModel.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.psi.element.KeywordDefinition; 11 | import com.millennialmedia.intellibot.psi.element.RobotFile; 12 | import com.millennialmedia.intellibot.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 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/structure/RobotTypeFilter.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/structure/RobotTypeSorter.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/structure/RobotViewElementType.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.structure; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.millennialmedia.intellibot.RobotBundle; 5 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/ide/usage/RobotFindUsagesProvider.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.usage; 2 | 3 | import com.intellij.lang.cacheBuilder.WordsScanner; 4 | import com.intellij.lang.findUsages.FindUsagesProvider; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiNamedElement; 7 | import com.millennialmedia.intellibot.RobotBundle; 8 | import com.millennialmedia.intellibot.psi.element.*; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | /** 13 | * @author Stephen Abrams 14 | */ 15 | public class RobotFindUsagesProvider implements FindUsagesProvider { 16 | 17 | @Nullable 18 | @Override 19 | public WordsScanner getWordsScanner() { 20 | return new RobotWordScanner(); 21 | } 22 | 23 | @Override 24 | public boolean canFindUsagesFor(@NotNull PsiElement element) { 25 | if (element instanceof Argument && element.getParent() instanceof Import) { 26 | // if the Argument is the first child of Import, then it is the file reference 27 | // everything else will be covered by Variables 28 | return element == element.getParent().getFirstChild(); 29 | } 30 | return element instanceof PsiNamedElement; 31 | } 32 | 33 | @Nullable 34 | @Override 35 | public String getHelpId(@NotNull PsiElement element) { 36 | return null; 37 | } 38 | 39 | @NotNull 40 | @Override 41 | public String getType(@NotNull PsiElement element) { 42 | return RobotBundle.message("usage.declaration"); 43 | } 44 | 45 | @NotNull 46 | @Override 47 | public String getDescriptiveName(@NotNull PsiElement element) { 48 | // this is what appears in the find usages dialog 49 | if (element instanceof KeywordDefinition) { 50 | return RobotBundle.message("usage.descriptive.keyword"); 51 | } else if (element instanceof VariableDefinition) { 52 | return RobotBundle.message("usage.descriptive.variable"); 53 | } else if (element instanceof RobotFile) { 54 | return RobotBundle.message("usage.descriptive.import"); 55 | } else if (element instanceof Argument) { 56 | return RobotBundle.message("usage.descriptive.argument"); 57 | } 58 | return ""; 59 | } 60 | 61 | @NotNull 62 | @Override 63 | public String getNodeText(@NotNull PsiElement element, boolean useFullName) { 64 | // TODO: if variable definition get value set to variable 65 | return ""; 66 | // if (element instanceof SimpleProperty) { 67 | // return ((SimpleProperty) element).getKey() + ":" + ((SimpleProperty) element).getValue(); 68 | // } else { 69 | // return ""; 70 | // } 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/usage/RobotKeywordGroupingRuleProvider.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.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(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 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/ide/usage/RobotWordScanner.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide.usage; 2 | 3 | import com.intellij.lang.cacheBuilder.DefaultWordsScanner; 4 | import com.intellij.psi.tree.TokenSet; 5 | import com.millennialmedia.intellibot.psi.RobotKeywordProvider; 6 | import com.millennialmedia.intellibot.psi.RobotLexer; 7 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/RecommendationWord.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/RobotElementType.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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, com.millennialmedia.intellibot.psi.RobotLanguage.INSTANCE); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/RobotFeatureFileType.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi; 2 | 3 | import com.intellij.openapi.fileTypes.LanguageFileType; 4 | import com.millennialmedia.intellibot.ide.icons.RobotIcons; 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/com/millennialmedia/intellibot/psi/RobotFileTypeHandler.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/RobotHighlighter.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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 ERROR = TextAttributesKey.createTextAttributesKey( 87 | RobotTokenTypes.ERROR.toString(), 88 | DefaultLanguageHighlighterColors.INVALID_STRING_ESCAPE 89 | ); 90 | 91 | static { 92 | keys1 = new THashMap(); 93 | keys2 = new THashMap(); 94 | 95 | keys1.put(RobotTokenTypes.HEADING, HEADING); 96 | keys1.put(RobotTokenTypes.COMMENT, COMMENT); 97 | keys1.put(RobotTokenTypes.ARGUMENT, ARGUMENT); 98 | keys1.put(RobotTokenTypes.ERROR, ERROR); 99 | keys1.put(RobotTokenTypes.GHERKIN, GHERKIN); 100 | keys1.put(RobotTokenTypes.VARIABLE, VARIABLE); 101 | keys1.put(RobotTokenTypes.VARIABLE_DEFINITION, VARIABLE_DEFINITION); 102 | keys1.put(RobotTokenTypes.KEYWORD, KEYWORD); 103 | keys1.put(RobotTokenTypes.KEYWORD_DEFINITION, KEYWORD_DEFINITION); 104 | keys1.put(RobotTokenTypes.BRACKET_SETTING, BRACKET_SETTING); 105 | keys1.put(RobotTokenTypes.SETTING, SETTING); 106 | keys1.put(RobotTokenTypes.IMPORT, IMPORT); 107 | } 108 | 109 | @NotNull 110 | public TextAttributesKey[] getTokenHighlights(IElementType tokenType) { 111 | return pack(keys1.get(tokenType), keys2.get(tokenType)); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/RobotKeywordTable.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/RobotLanguage.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/RobotParserDefinition.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.lang.ParserDefinition; 5 | import com.intellij.lang.PsiParser; 6 | import com.intellij.lexer.Lexer; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.psi.FileViewProvider; 9 | import com.intellij.psi.PsiElement; 10 | import com.intellij.psi.PsiFile; 11 | import com.intellij.psi.tree.IFileElementType; 12 | import com.intellij.psi.tree.TokenSet; 13 | import com.intellij.psi.util.PsiUtilCore; 14 | import com.millennialmedia.intellibot.psi.element.*; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | /** 18 | * @author Stephen Abrams 19 | */ 20 | public class RobotParserDefinition implements ParserDefinition { 21 | 22 | private static final TokenSet WHITESPACE_SET = TokenSet.create(RobotTokenTypes.WHITESPACE); 23 | private static final TokenSet COMMENTS_SET = TokenSet.create(RobotTokenTypes.COMMENT); 24 | private static final TokenSet STRING_SET = TokenSet.create(RobotTokenTypes.GHERKIN); 25 | 26 | @NotNull 27 | @Override 28 | public Lexer createLexer(Project project) { 29 | return new RobotLexer(RobotKeywordProvider.getInstance()); 30 | } 31 | 32 | @Override 33 | public PsiParser createParser(Project project) { 34 | return new RobotParser(); 35 | } 36 | 37 | @Override 38 | public IFileElementType getFileNodeType() { 39 | return RobotTokenTypes.FILE; 40 | } 41 | 42 | @NotNull 43 | @Override 44 | public TokenSet getWhitespaceTokens() { 45 | return WHITESPACE_SET; 46 | } 47 | 48 | @NotNull 49 | @Override 50 | public TokenSet getCommentTokens() { 51 | return COMMENTS_SET; 52 | } 53 | 54 | @NotNull 55 | @Override 56 | public TokenSet getStringLiteralElements() { 57 | return STRING_SET; 58 | } 59 | 60 | @NotNull 61 | @Override 62 | public PsiElement createElement(ASTNode node) { 63 | if (node.getElementType() == RobotTokenTypes.KEYWORD_DEFINITION) return new KeywordDefinitionImpl(node); 64 | if (node.getElementType() == RobotTokenTypes.KEYWORD_DEFINITION_ID) return new KeywordDefinitionIdImpl(node); 65 | if (node.getElementType() == RobotTokenTypes.KEYWORD_STATEMENT) return new KeywordStatementImpl(node); 66 | if (node.getElementType() == RobotTokenTypes.KEYWORD) return new KeywordInvokableImpl(node); 67 | if (node.getElementType() == RobotTokenTypes.VARIABLE_DEFINITION) return new VariableDefinitionImpl(node); 68 | if (node.getElementType() == RobotTokenTypes.VARIABLE_DEFINITION_ID) return new VariableDefinitionIdImpl(node); 69 | if (node.getElementType() == RobotTokenTypes.HEADING) return new HeadingImpl(node); 70 | if (node.getElementType() == RobotTokenTypes.ARGUMENT) return new ArgumentImpl(node); 71 | if (node.getElementType() == RobotTokenTypes.VARIABLE) return new VariableImpl(node); 72 | if (node.getElementType() == RobotTokenTypes.IMPORT) return new ImportImpl(node); 73 | if (node.getElementType() == RobotTokenTypes.SETTING) return new SettingImpl(node); 74 | if (node.getElementType() == RobotTokenTypes.BRACKET_SETTING) return new BracketSettingImpl(node); 75 | 76 | return PsiUtilCore.NULL_PSI_ELEMENT; 77 | 78 | } 79 | 80 | @Override 81 | public PsiFile createFile(FileViewProvider viewProvider) { 82 | return new RobotFileImpl(viewProvider); 83 | } 84 | 85 | @Override 86 | public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) { 87 | // TODO: guessing this is for code cleanup 88 | return null; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/RobotPsiManager.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi; 2 | 3 | import com.intellij.openapi.components.ProjectComponent; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.impl.AbstractModificationTracker; 6 | import com.intellij.psi.impl.PsiManagerImpl; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * @author mrubino 11 | */ 12 | public class RobotPsiManager extends AbstractModificationTracker implements ProjectComponent { 13 | 14 | public RobotPsiManager(PsiManagerImpl psiManager) { 15 | super(psiManager); 16 | } 17 | 18 | @Override 19 | protected boolean isInsideCodeBlock(PsiElement element) { 20 | // TODO: usage? 21 | return false; 22 | } 23 | 24 | public void projectOpened() { 25 | // nothing 26 | } 27 | 28 | public void projectClosed() { 29 | // nothing 30 | } 31 | 32 | public void initComponent() { 33 | // nothing 34 | } 35 | 36 | public void disposeComponent() { 37 | // nothing 38 | } 39 | 40 | @NotNull 41 | public String getComponentName() { 42 | return "RobotPsiManager"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/RobotSyntaxHighlightingFactory.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/RobotTokenTypes.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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 KEYWORD_STATEMENT = new RobotElementType("KEYWORD_STATEMENT"); 23 | 24 | RobotElementType ERROR = new RobotElementType("ERROR"); 25 | RobotElementType WHITESPACE = new RobotElementType("WHITESPACE"); 26 | } 27 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/dto/ImportType.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/dto/KeywordDto.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.dto; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.millennialmedia.intellibot.psi.element.DefinedKeyword; 5 | import com.millennialmedia.intellibot.psi.util.PatternBuilder; 6 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/dto/VariableDto.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.dto; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.millennialmedia.intellibot.psi.element.DefinedVariable; 5 | import com.millennialmedia.intellibot.psi.util.PatternUtil; 6 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/Argument.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/ArgumentImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiReference; 5 | import com.millennialmedia.intellibot.psi.ref.RobotArgumentReference; 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/com/millennialmedia/intellibot/psi/element/BracketSetting.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/BracketSettingImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/DefinedKeyword.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/DefinedVariable.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/Heading.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/Import.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/ImportImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/KeywordDefinition.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/element/KeywordDefinitionId.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | /** 4 | * @author mrubino 5 | * @since 2016-01-07 6 | */ 7 | public interface KeywordDefinitionId extends RobotStatement { 8 | } 9 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/element/KeywordDefinitionIdImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/KeywordFile.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/KeywordInvokable.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/KeywordInvokableImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiReference; 6 | import com.millennialmedia.intellibot.psi.ref.RobotKeywordReference; 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/com/millennialmedia/intellibot/psi/element/KeywordStatement.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/KeywordStatementImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import com.millennialmedia.intellibot.psi.dto.VariableDto; 6 | import com.millennialmedia.intellibot.psi.util.PatternUtil; 7 | import com.millennialmedia.intellibot.psi.util.PerformanceCollector; 8 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/RobotFile.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/RobotFileImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.intellij.extapi.psi.PsiFileBase; 4 | import com.intellij.openapi.fileTypes.FileType; 5 | import com.intellij.psi.FileViewProvider; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiFile; 8 | import com.millennialmedia.intellibot.psi.RobotFeatureFileType; 9 | import com.millennialmedia.intellibot.psi.RobotLanguage; 10 | import com.millennialmedia.intellibot.psi.dto.ImportType; 11 | import com.millennialmedia.intellibot.psi.util.PerformanceCollector; 12 | import com.millennialmedia.intellibot.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 | private 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/com/millennialmedia/intellibot/psi/element/RobotPsiElementBase.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.intellij.extapi.psi.ASTWrapperPsiElement; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.navigation.ItemPresentation; 6 | import com.intellij.openapi.util.Iconable; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.util.IncorrectOperationException; 9 | import com.millennialmedia.intellibot.psi.util.PatternUtil; 10 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/RobotStatement.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/Setting.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/SettingImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/Variable.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/VariableDefinition.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/VariableDefinitionId.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | /** 4 | * @author mrubino 5 | * @since 2016-04-01 6 | */ 7 | public interface VariableDefinitionId extends RobotStatement { 8 | } 9 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/element/VariableDefinitionIdImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/element/VariableDefinitionImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiNameIdentifierOwner; 7 | import com.intellij.psi.util.PsiTreeUtil; 8 | import com.millennialmedia.intellibot.ide.icons.RobotIcons; 9 | import com.millennialmedia.intellibot.psi.util.PatternUtil; 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/com/millennialmedia/intellibot/psi/element/VariableImpl.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | import com.intellij.psi.PsiReference; 6 | import com.millennialmedia.intellibot.psi.ref.RobotVariableReference; 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 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/manip/ArgumentManipulator.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/manip/KeywordInvokableManipulator.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.psi.element.KeywordInvokable; 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/com/millennialmedia/intellibot/psi/manip/VariableManipulator.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/ref/RobotArgumentReference.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.ref; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiReferenceBase; 5 | import com.millennialmedia.intellibot.psi.element.Argument; 6 | import com.millennialmedia.intellibot.psi.element.Import; 7 | import com.millennialmedia.intellibot.psi.element.KeywordStatement; 8 | import com.millennialmedia.intellibot.psi.util.PerformanceCollector; 9 | import com.millennialmedia.intellibot.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 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/ref/RobotKeywordReference.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.ref; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiReferenceBase; 5 | import com.millennialmedia.intellibot.psi.element.KeywordInvokable; 6 | import com.millennialmedia.intellibot.psi.util.PerformanceCollector; 7 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/ref/RobotPythonClass.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.ref; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.jetbrains.python.psi.PyClass; 5 | import com.millennialmedia.intellibot.psi.dto.ImportType; 6 | import com.millennialmedia.intellibot.psi.element.DefinedKeyword; 7 | import com.millennialmedia.intellibot.psi.element.DefinedVariable; 8 | import com.millennialmedia.intellibot.psi.element.KeywordFile; 9 | import com.millennialmedia.intellibot.psi.util.PerformanceCollector; 10 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/ref/RobotPythonFile.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.ref; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.jetbrains.python.psi.PyClass; 5 | import com.jetbrains.python.psi.PyFile; 6 | import com.jetbrains.python.psi.PyFunction; 7 | import com.jetbrains.python.psi.PyTargetExpression; 8 | import com.millennialmedia.intellibot.psi.dto.ImportType; 9 | import com.millennialmedia.intellibot.psi.dto.KeywordDto; 10 | import com.millennialmedia.intellibot.psi.dto.VariableDto; 11 | import com.millennialmedia.intellibot.psi.element.DefinedKeyword; 12 | import com.millennialmedia.intellibot.psi.element.DefinedVariable; 13 | import com.millennialmedia.intellibot.psi.element.KeywordFile; 14 | import com.millennialmedia.intellibot.psi.util.PerformanceCollector; 15 | import com.millennialmedia.intellibot.psi.util.PerformanceEntity; 16 | import com.millennialmedia.intellibot.psi.util.ReservedVariable; 17 | import org.jetbrains.annotations.NotNull; 18 | 19 | import java.util.Collection; 20 | import java.util.Collections; 21 | import java.util.HashSet; 22 | 23 | /** 24 | * @author mrubino 25 | * @since 2014-06-17 26 | */ 27 | public class RobotPythonFile extends RobotPythonWrapper implements KeywordFile, PerformanceEntity { 28 | 29 | private static final String EMPTY = ""; 30 | 31 | private final String library; 32 | private final PyFile pythonFile; 33 | private final ImportType importType; 34 | 35 | public RobotPythonFile(@NotNull String library, @NotNull PyFile pythonFile, @NotNull ImportType importType) { 36 | this.library = library; 37 | this.pythonFile = pythonFile; 38 | this.importType = importType; 39 | } 40 | 41 | @NotNull 42 | @Override 43 | public Collection getDefinedKeywords() { 44 | PerformanceCollector debug = new PerformanceCollector(this, "get defined keywords"); 45 | Collection results = new HashSet(); 46 | for (PyFunction function : this.pythonFile.getTopLevelFunctions()) { 47 | String keyword = functionToKeyword(function.getName()); 48 | if (keyword != null) { 49 | results.add(new KeywordDto(function, this.library, keyword, hasArguments(function.getParameterList().getParameters()))); 50 | } 51 | } 52 | for (PyTargetExpression expression : this.pythonFile.getTopLevelAttributes()) { 53 | String keyword = functionToKeyword(expression.getName()); 54 | if (keyword != null) { 55 | results.add(new KeywordDto(expression, this.library, keyword, false)); 56 | } 57 | } 58 | for (PyClass subClass : this.pythonFile.getTopLevelClasses()) { 59 | String namespace = subClass.getQualifiedName() == null ? EMPTY : subClass.getQualifiedName(); 60 | addDefinedKeywords(subClass, namespace, results); 61 | } 62 | debug.complete(); 63 | return results; 64 | } 65 | 66 | @NotNull 67 | @Override 68 | public Collection getDefinedVariables() { 69 | PerformanceCollector debug = new PerformanceCollector(this, "get defined variables"); 70 | final Collection results = new HashSet(); 71 | for (PyTargetExpression expression : this.pythonFile.getTopLevelAttributes()) { 72 | String keyword = expression.getName(); 73 | if (keyword != null) { 74 | // not formatted ${X}, assume scalar 75 | results.add(new VariableDto(expression, ReservedVariable.wrapToScalar(keyword), null)); 76 | } 77 | } 78 | for (PyClass subClass : this.pythonFile.getTopLevelClasses()) { 79 | addDefinedVariables(subClass, results); 80 | } 81 | debug.complete(); 82 | return results; 83 | } 84 | 85 | @NotNull 86 | @Override 87 | public ImportType getImportType() { 88 | return this.importType; 89 | } 90 | 91 | @NotNull 92 | @Override 93 | public Collection getImportedFiles(boolean includeTransitive) { 94 | return Collections.emptyList(); 95 | } 96 | 97 | @Override 98 | public boolean equals(Object o) { 99 | if (this == o) return true; 100 | if (o == null || getClass() != o.getClass()) return false; 101 | 102 | RobotPythonFile that = (RobotPythonFile) o; 103 | return this.library.equals(that.library) && this.pythonFile.equals(that.pythonFile); 104 | } 105 | 106 | @Override 107 | public int hashCode() { 108 | int result = this.library.hashCode(); 109 | result = 31 * result + this.pythonFile.hashCode(); 110 | return result; 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return this.library; 116 | } 117 | 118 | @NotNull 119 | @Override 120 | public String getDebugFileName() { 121 | return toString(); 122 | } 123 | 124 | @NotNull 125 | @Override 126 | public String getDebugText() { 127 | return this.pythonFile.getContainingFile().getVirtualFile().getName(); 128 | } 129 | 130 | @NotNull 131 | @Override 132 | public Project getProject() { 133 | return this.pythonFile.getProject(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/ref/RobotPythonWrapper.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.ref; 2 | 3 | import com.intellij.util.Processor; 4 | import com.jetbrains.python.psi.*; 5 | import com.millennialmedia.intellibot.psi.dto.KeywordDto; 6 | import com.millennialmedia.intellibot.psi.dto.VariableDto; 7 | import com.millennialmedia.intellibot.psi.element.DefinedKeyword; 8 | import com.millennialmedia.intellibot.psi.element.DefinedVariable; 9 | import com.millennialmedia.intellibot.psi.util.ReservedVariable; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.Collection; 14 | 15 | /** 16 | * @author mrubino 17 | * @since 2014-06-17 18 | */ 19 | public abstract class RobotPythonWrapper { 20 | 21 | private static final String UNDERSCORE = "_"; 22 | private static final String SELF = "self"; 23 | 24 | protected static boolean hasArguments(@Nullable PyParameter[] parameters) { 25 | if (parameters == null || parameters.length == 0) { 26 | return false; 27 | } 28 | 29 | for (PyParameter parameter : parameters) { 30 | String name = parameter.getName(); 31 | if (name != null && !SELF.equalsIgnoreCase(name)) { 32 | return true; 33 | } 34 | } 35 | return false; 36 | } 37 | 38 | protected static String functionToKeyword(@Nullable String function) { 39 | if (function == null || isPrivate(function)) { 40 | return null; 41 | } else { 42 | return function; 43 | } 44 | } 45 | 46 | protected static void addDefinedVariables(@NotNull PyClass pythonClass, @NotNull final Collection results) { 47 | pythonClass.visitClassAttributes( 48 | new Processor() { 49 | @Override 50 | public boolean process(PyTargetExpression expression) { 51 | String keyword = expression.getName(); 52 | if (keyword != null && !isPrivate(keyword)) { 53 | // not formatted ${X}, assume scalar 54 | results.add(new VariableDto(expression, ReservedVariable.wrapToScalar(keyword), null)); 55 | } 56 | return true; 57 | } 58 | }, 59 | true, 60 | null 61 | ); 62 | } 63 | 64 | private static boolean isPrivate(@NotNull String keyword) { 65 | // these keeps out intended private functions 66 | return keyword.startsWith(UNDERSCORE) || keyword.startsWith("ROBOT_LIBRARY_"); 67 | } 68 | 69 | protected static void addDefinedKeywords(@NotNull PyClass pythonClass, @NotNull final String namespace, @NotNull final Collection results) { 70 | pythonClass.visitMethods( 71 | new Processor() { 72 | 73 | @Override 74 | public boolean process(PyFunction function) { 75 | String keyword = functionToKeyword(function.getName()); 76 | if (keyword != null) { 77 | // Get info from @keyword 78 | PyDecoratorList decorators = function.getDecoratorList(); 79 | if (decorators != null) { 80 | PyDecorator keyword_decorator = decorators.findDecorator("keyword"); 81 | if (keyword_decorator != null) { 82 | if (keyword_decorator.hasArgumentList()) { 83 | // Get case 'name =' argument 84 | PyExpression kwa = keyword_decorator.getKeywordArgument("name"); 85 | if (kwa != null) { 86 | keyword = kwa.getText().replaceAll("^\"|\"$", ""); 87 | } 88 | else { 89 | // Otherwise, check if first argument is unnamed 90 | PyExpression[] kda = keyword_decorator.getArguments(); 91 | 92 | // Argument exists and is unnamed 93 | if (kda.length > 0 && kda[0].getName() == null) { 94 | keyword = kda[0].getText().replaceAll("^\"|\"$", ""); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | results.add(new KeywordDto(function, namespace, keyword, hasArguments(function.getParameterList().getParameters()))); 101 | } 102 | return true; 103 | } 104 | }, 105 | true, 106 | null 107 | ); 108 | pythonClass.visitClassAttributes( 109 | new Processor() { 110 | 111 | @Override 112 | public boolean process(PyTargetExpression expression) { 113 | String keyword = functionToKeyword(expression.getName()); 114 | if (keyword != null) { 115 | results.add(new KeywordDto(expression, namespace, keyword, false)); 116 | } 117 | return true; 118 | } 119 | }, 120 | true, 121 | null 122 | ); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/com/millennialmedia/intellibot/psi/ref/RobotVariableReference.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.ref; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiFile; 5 | import com.intellij.psi.PsiReferenceBase; 6 | import com.millennialmedia.intellibot.ide.config.RobotOptionsProvider; 7 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/util/PatternBuilder.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/util/PatternUtil.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/util/PerformanceCollector.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.util; 2 | 3 | import com.intellij.notification.*; 4 | import com.millennialmedia.intellibot.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/com/millennialmedia/intellibot/psi/util/PerformanceEntity.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.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 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/ResourceLoader.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot; 2 | 3 | import java.net.URL; 4 | 5 | /** 6 | * @author mrubino 7 | * @since 2014-06-19 8 | */ 9 | public class ResourceLoader { 10 | 11 | private ResourceLoader() { 12 | } 13 | 14 | public static String getResourcePath(String path) { 15 | URL resource = ResourceLoader.class.getClassLoader().getResource(path); 16 | return resource == null ? null : resource.getFile(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/ide/AbstractRobotIdeTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide; 2 | 3 | import com.intellij.testFramework.fixtures.CodeInsightTestFixture; 4 | import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; 5 | import com.millennialmedia.intellibot.ResourceLoader; 6 | 7 | /** 8 | * @author mrubino 9 | * @since 2016-06-01 10 | */ 11 | public abstract class AbstractRobotIdeTest extends LightPlatformCodeInsightFixtureTestCase { 12 | 13 | protected final String getTestFile() { 14 | return String.format("%s%s.robot", getTestDataPath(), getTestName(true)); 15 | } 16 | 17 | @Override 18 | protected abstract String getBasePath(); 19 | 20 | @Override 21 | protected final String getTestDataPath() { 22 | return ResourceLoader.getResourcePath(getBasePath()); 23 | } 24 | 25 | protected final CodeInsightTestFixture getFixture() { 26 | return this.myFixture; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/ide/RobotFindUsagesTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.usageView.UsageInfo; 5 | import com.millennialmedia.intellibot.ide.config.RobotOptionsProvider; 6 | 7 | import java.util.*; 8 | 9 | /** 10 | * @author mrubino 11 | * @since 2016-06-01 12 | */ 13 | public class RobotFindUsagesTest extends AbstractRobotIdeTest { 14 | 15 | public void testFindKeywordByDefinition() { 16 | assertUsages( 17 | doTest(getTestFile()), 18 | "calculator has been cleared", 19 | "calculator has been cleared" 20 | ); 21 | } 22 | 23 | public void testFindKeywordByUsage() { 24 | assertUsages( 25 | doTest(getTestFile()), 26 | "calculator has been cleared", 27 | "calculator has been cleared" 28 | ); 29 | } 30 | 31 | public void testFindInlineKeywordByDefinition() { 32 | assertUsages( 33 | doTest(getTestFile()), 34 | "user types \"1 + 1\"", 35 | "user types \"2 - 1\"" 36 | ); 37 | } 38 | 39 | public void testFindInlineKeywordByUsage() { 40 | assertUsages( 41 | doTest(getTestFile()), 42 | "user types \"1 + 1\"", 43 | "user types \"2 - 1\"" 44 | ); 45 | } 46 | 47 | public void testFindVariableByDefinition() { 48 | assertUsages( 49 | doTest(getTestFile()), 50 | "${var2}" 51 | ); 52 | } 53 | 54 | public void testFindVariableByUsage() { 55 | assertUsages( 56 | doTest(getTestFile()), 57 | "${var2}" 58 | ); 59 | } 60 | 61 | public void testFindInlineVariableByDefinition() { 62 | assertUsages( 63 | doTest(getTestFile()), 64 | "${expression}" 65 | ); 66 | } 67 | 68 | public void testFindInlineVariableByUsage() { 69 | assertUsages( 70 | doTest(getTestFile()), 71 | "${expression}" 72 | ); 73 | } 74 | 75 | private Collection doTest(String... files) { 76 | // TODO: seems bit hacky 77 | RobotOptionsProvider.getInstance(getFixture().getProject()).setInlineVariableSearch(true); 78 | return getFixture().testFindUsages(files); 79 | } 80 | 81 | /** 82 | * Checks that the usage info that we get for the test file matches our expectations. This 83 | * will sort the given usages based on appearance in file to ensure consistency. 84 | * 85 | * @param usages the results to check. 86 | * @param expected the expectations. 87 | */ 88 | private void assertUsages(Collection usages, String... expected) { 89 | assertNotNull(usages); 90 | assertEquals(expected.length, usages.size()); 91 | List sorted = sortUsages(usages); 92 | for (int i = 0; i < expected.length; i++) { 93 | assertEquals(expected[i], getUsageText(sorted.get(i))); 94 | } 95 | } 96 | 97 | private List sortUsages(Collection usages) { 98 | List sorted = new ArrayList(usages); 99 | Collections.sort(sorted, new Comparator() { 100 | @Override 101 | public int compare(UsageInfo o1, UsageInfo o2) { 102 | PsiElement e1 = o1.getElement(); 103 | PsiElement e2 = o2.getElement(); 104 | assertNotNull(e1); 105 | assertNotNull(e2); 106 | return Integer.compare(e1.getTextOffset(), e2.getTextOffset()); 107 | } 108 | }); 109 | return sorted; 110 | } 111 | 112 | private String getUsageText(UsageInfo usage) { 113 | PsiElement element = usage.getElement(); 114 | assertNotNull(element); 115 | int start = element.getTextOffset(); 116 | return getFixture().getFile().getText().substring(start, start + element.getTextLength()); 117 | } 118 | 119 | @Override 120 | protected String getBasePath() { 121 | return "ide/usages/"; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/ide/RobotFoldingTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide; 2 | 3 | /** 4 | * @author mrubino 5 | * @since 2016-06-01 6 | */ 7 | public class RobotFoldingTest extends AbstractRobotIdeTest { 8 | 9 | public void testKeywordFolding() { 10 | doTest(); 11 | } 12 | 13 | private void doTest() { 14 | getFixture().testFoldingWithCollapseStatus(getTestFile()); 15 | } 16 | 17 | @Override 18 | protected String getBasePath() { 19 | return "ide/folding/"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/ide/RobotHighlightTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.ide; 2 | 3 | import com.intellij.openapi.editor.markup.RangeHighlighter; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.Comparator; 8 | import java.util.List; 9 | 10 | /** 11 | * @author mrubino 12 | * @since 2016-06-01 13 | */ 14 | public class RobotHighlightTest extends AbstractRobotIdeTest { 15 | 16 | public void testFindKeywordByDefinition() { 17 | assertHighlights( 18 | doTest(getTestFile()), 19 | "calculator has been cleared", 20 | "calculator has been cleared", 21 | "Calculator has been cleared" 22 | ); 23 | } 24 | 25 | public void testFindKeywordByUsage() { 26 | assertHighlights( 27 | doTest(getTestFile()), 28 | "calculator has been cleared", 29 | "calculator has been cleared", 30 | "Calculator has been cleared" 31 | ); 32 | } 33 | 34 | public void testFindInlineKeywordByDefinition() { 35 | assertHighlights( 36 | doTest(getTestFile()), 37 | "user types \"1 + 1\"", 38 | "user types \"2 - 1\"", 39 | "User types \"${expression}\"" 40 | ); 41 | } 42 | 43 | public void testFindInlineKeywordByUsage() { 44 | assertHighlights( 45 | doTest(getTestFile()), 46 | "user types \"1 + 1\"", 47 | "user types \"2 - 1\"", 48 | "User types \"${expression}\"" 49 | ); 50 | } 51 | 52 | public void testFindVariableByDefinition() { 53 | assertHighlights( 54 | doTest(getTestFile()), 55 | "${var2}", 56 | "${var2}" 57 | ); 58 | } 59 | 60 | public void testFindVariableByUsage() { 61 | assertHighlights( 62 | doTest(getTestFile()), 63 | "${var2}", 64 | "${var2}" 65 | ); 66 | } 67 | 68 | public void testFindInlineVariableByDefinition() { 69 | assertHighlights( 70 | doTest(getTestFile()), 71 | "${expression}", 72 | "${expression}" 73 | ); 74 | } 75 | 76 | public void testFindInlineVariableByUsage() { 77 | assertHighlights( 78 | doTest(getTestFile()), 79 | "${expression}", 80 | "${expression}" 81 | ); 82 | } 83 | 84 | private RangeHighlighter[] doTest(String... files) { 85 | return getFixture().testHighlightUsages(files); 86 | } 87 | 88 | 89 | /** 90 | * Checks that the highlights that we get for the test file matches our expectations. This 91 | * will sort the given highlights based on appearance in file to ensure consistency. 92 | * 93 | * @param highlights the results to check. 94 | * @param expected the expectations. 95 | */ 96 | private void assertHighlights(RangeHighlighter[] highlights, String... expected) { 97 | assertNotNull(highlights); 98 | assertEquals(expected.length, highlights.length); 99 | List sorted = sortHighlights(highlights); 100 | for (int i = 0; i < expected.length; i++) { 101 | assertEquals(expected[i], getHighlightText(sorted.get(i))); 102 | } 103 | } 104 | 105 | private List sortHighlights(RangeHighlighter[] highlights) { 106 | List sorted = new ArrayList(highlights.length); 107 | Collections.addAll(sorted, highlights); 108 | Collections.sort(sorted, new Comparator() { 109 | @Override 110 | public int compare(RangeHighlighter o1, RangeHighlighter o2) { 111 | return Integer.compare(o1.getStartOffset(), o2.getStartOffset()); 112 | } 113 | }); 114 | return sorted; 115 | } 116 | 117 | private String getHighlightText(RangeHighlighter highlight) { 118 | return getFixture().getFile().getText().substring(highlight.getStartOffset(), highlight.getEndOffset()); 119 | } 120 | 121 | @Override 122 | protected String getBasePath() { 123 | return "ide/usages/"; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/psi/RobotParserTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi; 2 | 3 | import com.intellij.testFramework.ParsingTestCase; 4 | import com.millennialmedia.intellibot.ResourceLoader; 5 | import org.junit.Test; 6 | 7 | @SuppressWarnings("JUnit4AnnotatedMethodInJUnit3TestCase") 8 | public class RobotParserTest extends ParsingTestCase { 9 | 10 | public RobotParserTest() { 11 | super("", "robot", new RobotParserDefinition()); 12 | } 13 | 14 | @Test 15 | public void testParsingTestData() { 16 | doTest(true); 17 | } 18 | 19 | @Test 20 | public void testJunk() { 21 | doTest(true); 22 | } 23 | 24 | @Test 25 | public void testVariables() { 26 | doTest(true); 27 | } 28 | 29 | @Test 30 | public void testTrimmedVariables() { 31 | doTest(true); 32 | } 33 | 34 | @Test 35 | public void testEmptyHeaders() { 36 | doTest(true); 37 | } 38 | 39 | @Test 40 | public void testDemo() { 41 | doTest(true); 42 | } 43 | 44 | @Override 45 | protected String getTestDataPath() { 46 | return ResourceLoader.getResourcePath("samples"); 47 | } 48 | 49 | @Override 50 | protected boolean skipSpaces() { 51 | return true; 52 | } 53 | 54 | @Override 55 | protected boolean includeRanges() { 56 | return true; 57 | } 58 | } -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/psi/element/KeywordDefinitionTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.element; 2 | 3 | import com.intellij.psi.impl.source.DummyHolderElement; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.Parameterized; 7 | 8 | import java.lang.reflect.InvocationTargetException; 9 | import java.lang.reflect.Method; 10 | import java.util.Arrays; 11 | import java.util.Collection; 12 | import java.util.regex.Pattern; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.assertTrue; 16 | 17 | /** 18 | * @author mrubino 19 | * @since 2014-06-08 20 | */ 21 | @RunWith(Parameterized.class) 22 | public class KeywordDefinitionTest { 23 | 24 | private String namespace; 25 | private String keyword; 26 | private String pattern; 27 | 28 | public KeywordDefinitionTest(String namespace, String keyword, String pattern) { 29 | this.namespace = namespace; 30 | this.keyword = keyword; 31 | this.pattern = pattern; 32 | } 33 | 34 | @Test 35 | public void testBuildPattern() { 36 | try { 37 | Method method = KeywordDefinitionImpl.class.getDeclaredMethod("buildPattern", String.class, String.class); 38 | method.setAccessible(true); 39 | String actual = (String) method.invoke(new KeywordDefinitionImpl(new DummyHolderElement("dummy")), this.namespace, this.keyword); 40 | assertEquals(this.pattern, actual); 41 | 42 | assertTrue(Pattern.compile(actual).matcher(this.keyword).matches()); 43 | String temp = this.keyword.replace("${variable1}", "junk") 44 | .replace("${variable2}", "junk2") 45 | .replace("${date_range}", "Yesterday"); 46 | assertTrue(Pattern.compile(actual).matcher(temp).matches()); 47 | assertTrue(Pattern.compile(actual).matcher(this.namespace + "." + temp).matches()); 48 | } catch (InvocationTargetException e) { 49 | throw new RuntimeException(e); 50 | } catch (NoSuchMethodException e) { 51 | throw new RuntimeException(e); 52 | } catch (IllegalAccessException e) { 53 | throw new RuntimeException(e); 54 | } 55 | } 56 | 57 | @Parameterized.Parameters 58 | public static Collection patterns() { 59 | return Arrays.asList(new Object[][]{ 60 | {"my_file", "This is a test keyword", "(\\Qmy_file.\\E)?\\QThis is a test keyword\\E"}, 61 | {"my_file", "This is a test keyword with some ${crap in it", "(\\Qmy_file.\\E)?\\QThis is a test keyword with some ${crap in it\\E"}, 62 | {"my_file", "This is a ${variable1} keyword", "(\\Qmy_file.\\E)?\\QThis is a \\E.*?\\Q keyword\\E"}, 63 | {"my_file", "Set the date range to \"${date_range}\"", "(\\Qmy_file.\\E)?\\QSet the date range to \"\\E.*?\\Q\"\\E"}, 64 | {"my_file", "This is a keyword with a ${variable1}", "(\\Qmy_file.\\E)?\\QThis is a keyword with a \\E.*?"}, 65 | {"my_file", "${variable1} keyword am I", "(\\Qmy_file.\\E)?.*?\\Q keyword am I\\E"}, 66 | {"my_file", "This is a ${variable1} keyword times ${variable2}", "(\\Qmy_file.\\E)?\\QThis is a \\E.*?\\Q keyword times \\E.*?"} 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/psi/ref/RobotFileManagerTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.ref; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.Parameterized; 6 | 7 | import java.lang.reflect.InvocationTargetException; 8 | import java.lang.reflect.Method; 9 | import java.util.Arrays; 10 | import java.util.Collection; 11 | 12 | import static junit.framework.TestCase.assertNotNull; 13 | import static org.junit.Assert.assertEquals; 14 | 15 | /** 16 | * @author mrubino 17 | * @since 2014-06-18 18 | */ 19 | @RunWith(Parameterized.class) 20 | public class RobotFileManagerTest { 21 | 22 | private String path; 23 | private String suffix; 24 | private String[] expected; 25 | 26 | public RobotFileManagerTest(String path, String suffix, String[] expected) { 27 | this.path = path; 28 | this.suffix = suffix; 29 | this.expected = expected; 30 | } 31 | 32 | 33 | @Test 34 | public void testGetFilename() { 35 | try { 36 | Method method = RobotFileManager.class.getDeclaredMethod("getFilename", String.class, String.class); 37 | method.setAccessible(true); 38 | String[] actual = (String[]) method.invoke(null, this.path, this.suffix); 39 | assertNotNull(actual); 40 | assertEquals(2, actual.length); 41 | assertEquals(this.expected[0], actual[0]); 42 | assertEquals(this.expected[1], actual[1]); 43 | } catch (InvocationTargetException e) { 44 | throw new RuntimeException(e); 45 | } catch (NoSuchMethodException e) { 46 | throw new RuntimeException(e); 47 | } catch (IllegalAccessException e) { 48 | throw new RuntimeException(e); 49 | } 50 | } 51 | 52 | @Parameterized.Parameters 53 | public static Collection files() { 54 | return Arrays.asList(new Object[][]{ 55 | {"google_response_files_utils.robot", "", new String[]{"", "google_response_files_utils.robot"}}, 56 | {"kyle/web/ui_login_page.robot", "", new String[]{"kyle/web/", "ui_login_page.robot"}}, 57 | {"utils", ".py", new String[] {"", "utils.py"}}, 58 | {"utils.py", ".py", new String[] {"", "utils.py"}}, 59 | {"kyle/data/archive/users", ".py", new String[] {"kyle/data/archive/", "users.py"}}, 60 | {"kyle/data/archive/users.py", ".py", new String[] {"kyle/data/archive/", "users.py"}} 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/psi/util/KeywordParserTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.util; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.Parameterized; 6 | 7 | import java.util.Arrays; 8 | import java.util.Collection; 9 | import java.util.regex.Pattern; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertTrue; 13 | 14 | @RunWith(Parameterized.class) 15 | public class KeywordParserTest { 16 | 17 | private String namespace; 18 | private String keyword; 19 | private String pattern; 20 | 21 | public KeywordParserTest(String namespace, String keyword, String pattern) { 22 | this.namespace = namespace; 23 | this.keyword = keyword; 24 | this.pattern = pattern; 25 | } 26 | 27 | @Test 28 | public void testBuildPattern() throws Throwable { 29 | String actual = PatternBuilder.parseNamespaceKeyword(namespace, keyword); 30 | assertEquals(pattern, actual); 31 | 32 | assertTrue(Pattern.compile(actual).matcher(keyword).matches()); 33 | String temp = keyword.replace("${variable1}", "junk") 34 | .replace("${variable2}", "junk2") 35 | .replace("${date_range}", "Yesterday"); 36 | assertTrue(Pattern.compile(actual).matcher(temp).matches()); 37 | assertTrue(Pattern.compile(actual).matcher(namespace + "." + temp).matches()); 38 | } 39 | 40 | @Parameterized.Parameters 41 | public static Collection patterns() { 42 | return Arrays.asList(new Object[][]{ 43 | {"my_file", "This is a test keyword", "(\\Qmy_file.\\E)?\\QThis is a test keyword\\E"}, 44 | {"my_file", "This is a test keyword with some ${crap in it", "(\\Qmy_file.\\E)?\\QThis is a test keyword with some ${crap in it\\E"}, 45 | {"my_file", "This is a ${variable1} keyword", "(\\Qmy_file.\\E)?\\QThis is a \\E.*?\\Q keyword\\E"}, 46 | {"my_file", "Set the date range to \"${date_range}\"", "(\\Qmy_file.\\E)?\\QSet the date range to \"\\E.*?\\Q\"\\E"}, 47 | {"my_file", "This is a keyword with a ${variable1}", "(\\Qmy_file.\\E)?\\QThis is a keyword with a \\E.*?"}, 48 | {"my_file", "${variable1} keyword am I", "(\\Qmy_file.\\E)?.*?\\Q keyword am I\\E"}, 49 | {"my_file", "This is a ${variable1} keyword times ${variable2}", "(\\Qmy_file.\\E)?\\QThis is a \\E.*?\\Q keyword times \\E.*?"} 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/psi/util/PatternUtilBuildPatternTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.util; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.Parameterized; 6 | 7 | import java.util.Arrays; 8 | import java.util.Collection; 9 | import java.util.regex.Pattern; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertTrue; 13 | 14 | /** 15 | * @author mrubino 16 | * @since 2014-06-19 17 | */ 18 | @RunWith(Parameterized.class) 19 | public class PatternUtilBuildPatternTest { 20 | 21 | private static final String EXPECTED = "[\\$\\@\\%\\&]\\{[ _]*?\\Qv\\E[ _]*?\\Qa\\E[ _]*?\\Qr\\E[ _]*?\\Qi\\E[ _]*?\\Qa\\E[ _]*?\\Qb\\E[ _]*?\\Ql\\E[ _]*?\\Qe\\E[ _]*?((\\..*?)*?(\\[.*?\\])*?)*?\\}(\\[\\d+\\])?"; 22 | private String name; 23 | private String expected; 24 | 25 | public PatternUtilBuildPatternTest(String name, String expected) { 26 | this.name = name; 27 | this.expected = expected; 28 | } 29 | 30 | @Parameterized.Parameters 31 | public static Collection patterns() { 32 | return Arrays.asList(new Object[][]{ 33 | {"variable", EXPECTED}, 34 | {"${variable}", EXPECTED}, 35 | {"${var_i able}", EXPECTED}, 36 | {"${variable}=", EXPECTED}, 37 | {"${variable} =", EXPECTED}, 38 | {" ${variable} = ", EXPECTED}, 39 | {"@{variable}", EXPECTED}, 40 | {"@{var_i able}", EXPECTED}, 41 | {"@{variable}=", EXPECTED}, 42 | {"@{variable} =", EXPECTED}, 43 | {" @{variable} = ", EXPECTED}, 44 | {"%{variable}", EXPECTED}, 45 | {"%{var_i able}", EXPECTED}, 46 | {"%{variable}=", EXPECTED}, 47 | {"%{variable} =", EXPECTED}, 48 | {" %{variable} = ", EXPECTED}, 49 | {"&{variable}", EXPECTED}, 50 | {"&{var_i able}", EXPECTED}, 51 | {"&{variable}=", EXPECTED}, 52 | {"&{variable} =", EXPECTED}, 53 | {" &{variable} = ", EXPECTED}, 54 | }); 55 | } 56 | 57 | @Test 58 | public void testBuildPattern() { 59 | String actual = PatternUtil.getVariablePattern(this.name); 60 | assertEquals(this.expected, actual); 61 | Pattern pattern = Pattern.compile(actual); 62 | // TODO: asserts that either [@,$,%,&] are interchangeable in terms of variable matching/linking; acceptable? 63 | assertTrue(pattern.matcher("${variable}").matches()); 64 | assertTrue(pattern.matcher("${var i_able}").matches()); 65 | assertTrue(pattern.matcher("${var i__able}").matches()); 66 | assertTrue(pattern.matcher("${variable['a']['b']}").matches()); 67 | assertTrue(pattern.matcher("${variable['a'].name}").matches()); 68 | assertTrue(pattern.matcher("${variable.name}").matches()); 69 | assertTrue(pattern.matcher("${variable.name['a']}").matches()); 70 | 71 | assertTrue(pattern.matcher("@{variable}").matches()); 72 | assertTrue(pattern.matcher("@{var i_able}").matches()); 73 | assertTrue(pattern.matcher("@{var i__able}").matches()); 74 | assertTrue(pattern.matcher("@{variable['a']['b']}").matches()); 75 | assertTrue(pattern.matcher("@{variable['a'].name}").matches()); 76 | assertTrue(pattern.matcher("@{variable.name}").matches()); 77 | assertTrue(pattern.matcher("@{variable.name['a']}").matches()); 78 | 79 | assertTrue(pattern.matcher("%{variable}").matches()); 80 | assertTrue(pattern.matcher("%{var i_able}").matches()); 81 | assertTrue(pattern.matcher("%{var i__able}").matches()); 82 | assertTrue(pattern.matcher("%{variable['a']['b']}").matches()); 83 | assertTrue(pattern.matcher("%{variable['a'].name}").matches()); 84 | assertTrue(pattern.matcher("%{variable.name}").matches()); 85 | assertTrue(pattern.matcher("%{variable.name['a']}").matches()); 86 | 87 | assertTrue(pattern.matcher("&{variable}").matches()); 88 | assertTrue(pattern.matcher("&{var i_able}").matches()); 89 | assertTrue(pattern.matcher("&{var i__able}").matches()); 90 | assertTrue(pattern.matcher("&{variable['a']['b']}").matches()); 91 | assertTrue(pattern.matcher("&{variable['a'].name}").matches()); 92 | assertTrue(pattern.matcher("&{variable.name}").matches()); 93 | assertTrue(pattern.matcher("&{variable.name['a']}").matches()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/com/millennialmedia/intellibot/psi/util/PatternUtilGetPresentableTextTest.java: -------------------------------------------------------------------------------- 1 | package com.millennialmedia.intellibot.psi.util; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.Parameterized; 6 | 7 | import java.util.Arrays; 8 | import java.util.Collection; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | 12 | /** 13 | * @author mrubino 14 | * @since 2014-06-19 15 | */ 16 | @RunWith(Parameterized.class) 17 | public class PatternUtilGetPresentableTextTest { 18 | 19 | private String text; 20 | private String expected; 21 | 22 | public PatternUtilGetPresentableTextTest(String text, String expected) { 23 | this.text = text; 24 | this.expected = expected; 25 | } 26 | 27 | @Test 28 | public void testPresentableTest() { 29 | String actual = PatternUtil.getPresentableText(this.text); 30 | assertEquals(this.expected, actual); 31 | } 32 | 33 | @Parameterized.Parameters 34 | public static Collection patterns() { 35 | return Arrays.asList(new Object[][]{ 36 | {null, ""}, 37 | {"", ""}, 38 | {" ", ""}, 39 | {" ", ""}, 40 | {" ", ""}, 41 | {"\t", ""}, 42 | {"\n", ""}, 43 | {"word", "word"}, 44 | {"this is a sentence", "this is a sentence"}, 45 | {"this is a sentence with an argument", "this is a sentence"}, 46 | {"this is a sentence with an argument", "this is a sentence"}, 47 | {"this is a sentence\twith an argument", "this is a sentence"}, 48 | {"this is a sentence\nwith another sentence", "this is a sentence"}, 49 | {" this is a sentence \nwith another sentence", "this is a sentence"}, 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /testData/ide/folding/keywordFolding.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | #Subtraction 19 | # [Tags] Calculator 20 | # TODO: implement me 21 | 22 | *** Keywords *** 23 | Calculator has been cleared 24 | Push button C 25 | 26 | User types "${expression}" 27 | Push buttons ${expression} 28 | 29 | User pushes equals 30 | Push button = 31 | 32 | Result is "${result}" 33 | Result should be ${result} -------------------------------------------------------------------------------- /testData/ide/usages/findInlineKeywordByDefinition.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | Subtraction 19 | [Tags] Calculator 20 | Given calculator has been cleared 21 | When user types "2 - 1" 22 | And user pushes equals 23 | Then result is "1" 24 | 25 | *** Keywords *** 26 | Calculator has been cleared 27 | Push button C 28 | 29 | User types "${expression}" 30 | Push buttons ${expression} 31 | 32 | User pushes equals 33 | Push button = 34 | 35 | Result is "${result}" 36 | Result should be ${result} -------------------------------------------------------------------------------- /testData/ide/usages/findInlineKeywordByUsage.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | Subtraction 19 | [Tags] Calculator 20 | Given calculator has been cleared 21 | When user types "2 - 1" 22 | And user pushes equals 23 | Then result is "1" 24 | 25 | *** Keywords *** 26 | Calculator has been cleared 27 | Push button C 28 | 29 | User types "${expression}" 30 | Push buttons ${expression} 31 | 32 | User pushes equals 33 | Push button = 34 | 35 | Result is "${result}" 36 | Result should be ${result} -------------------------------------------------------------------------------- /testData/ide/usages/findInlineVariableByDefinition.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | Subtraction 19 | [Tags] Calculator 20 | Given calculator has been cleared 21 | When user types "2 - 1" 22 | And user pushes equals 23 | Then result is "1" 24 | 25 | *** Keywords *** 26 | Calculator has been cleared 27 | Push button C 28 | Log ${var2} 29 | 30 | User types "${expression}" 31 | Push buttons ${expression} 32 | 33 | User pushes equals 34 | Push button = 35 | 36 | Result is "${result}" 37 | Result should be ${result} -------------------------------------------------------------------------------- /testData/ide/usages/findInlineVariableByUsage.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | Subtraction 19 | [Tags] Calculator 20 | Given calculator has been cleared 21 | When user types "2 - 1" 22 | And user pushes equals 23 | Then result is "1" 24 | 25 | *** Keywords *** 26 | Calculator has been cleared 27 | Push button C 28 | Log ${var2} 29 | 30 | User types "${expression}" 31 | Push buttons ${expression} 32 | 33 | User pushes equals 34 | Push button = 35 | 36 | Result is "${result}" 37 | Result should be ${result} -------------------------------------------------------------------------------- /testData/ide/usages/findKeywordByDefinition.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | Subtraction 19 | [Tags] Calculator 20 | Given calculator has been cleared 21 | When user types "2 - 1" 22 | And user pushes equals 23 | Then result is "1" 24 | 25 | *** Keywords *** 26 | Calculator has been cleared 27 | Push button C 28 | 29 | User types "${expression}" 30 | Push buttons ${expression} 31 | 32 | User pushes equals 33 | Push button = 34 | 35 | Result is "${result}" 36 | Result should be ${result} -------------------------------------------------------------------------------- /testData/ide/usages/findKeywordByUsage.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | Subtraction 19 | [Tags] Calculator 20 | Given calculator has been cleared 21 | When user types "2 - 1" 22 | And user pushes equals 23 | Then result is "1" 24 | 25 | *** Keywords *** 26 | Calculator has been cleared 27 | Push button C 28 | 29 | User types "${expression}" 30 | Push buttons ${expression} 31 | 32 | User pushes equals 33 | Push button = 34 | 35 | Result is "${result}" 36 | Result should be ${result} -------------------------------------------------------------------------------- /testData/ide/usages/findVariableByDefinition.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | Subtraction 19 | [Tags] Calculator 20 | Given calculator has been cleared 21 | When user types "2 - 1" 22 | And user pushes equals 23 | Then result is "1" 24 | 25 | *** Keywords *** 26 | Calculator has been cleared 27 | Push button C 28 | Log ${var2} 29 | 30 | User types "${expression}" 31 | Push buttons ${expression} 32 | 33 | User pushes equals 34 | Push button = 35 | 36 | Result is "${result}" 37 | Result should be ${result} -------------------------------------------------------------------------------- /testData/ide/usages/findVariableByUsage.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | Subtraction 19 | [Tags] Calculator 20 | Given calculator has been cleared 21 | When user types "2 - 1" 22 | And user pushes equals 23 | Then result is "1" 24 | 25 | *** Keywords *** 26 | Calculator has been cleared 27 | Push button C 28 | Log ${var2} 29 | 30 | User types "${expression}" 31 | Push buttons ${expression} 32 | 33 | User pushes equals 34 | Push button = 35 | 36 | Result is "${result}" 37 | Result should be ${result} -------------------------------------------------------------------------------- /testData/samples/Demo.lexer.txt: -------------------------------------------------------------------------------- 1 | "invalid", RobotTokenTypes.COMMENT, 0 2 | "\n", RobotTokenTypes.WHITESPACE, 0 3 | "*** Settings ***", RobotTokenTypes.HEADING, 1 4 | "\n", RobotTokenTypes.WHITESPACE, 1 5 | "Documentation", RobotTokenTypes.SETTING, 5 6 | " ", RobotTokenTypes.WHITESPACE, 5 7 | "This is some demo text", RobotTokenTypes.ARGUMENT, 5 8 | "\n", RobotTokenTypes.WHITESPACE, 1 9 | "Library", RobotTokenTypes.IMPORT, 5 10 | " ", RobotTokenTypes.WHITESPACE, 5 11 | "CalculatorLibrary", RobotTokenTypes.ARGUMENT, 5 12 | "\n", RobotTokenTypes.WHITESPACE, 1 13 | "\n", RobotTokenTypes.WHITESPACE, 1 14 | "*** Variables ***", RobotTokenTypes.HEADING, 4 15 | "\n", RobotTokenTypes.WHITESPACE, 4 16 | "${var1}", RobotTokenTypes.VARIABLE_DEFINITION, 9 17 | " ", RobotTokenTypes.WHITESPACE, 9 18 | "12345", RobotTokenTypes.ARGUMENT, 9 19 | "\n", RobotTokenTypes.WHITESPACE, 4 20 | "${var2}", RobotTokenTypes.VARIABLE_DEFINITION, 9 21 | " ", RobotTokenTypes.WHITESPACE, 9 22 | "another variable", RobotTokenTypes.ARGUMENT, 9 23 | "\n", RobotTokenTypes.WHITESPACE, 4 24 | "\n", RobotTokenTypes.WHITESPACE, 4 25 | "*** Test Cases ***", RobotTokenTypes.HEADING, 2 26 | "\n", RobotTokenTypes.WHITESPACE, 2 27 | "Addition", RobotTokenTypes.KEYWORD_DEFINITION, 8 28 | "\n", RobotTokenTypes.WHITESPACE, 8 29 | " ", RobotTokenTypes.WHITESPACE, 8 30 | "[Tags]", RobotTokenTypes.BRACKET_SETTING, 5 31 | " ", RobotTokenTypes.WHITESPACE, 5 32 | "Calculator", RobotTokenTypes.ARGUMENT, 5 33 | "\n", RobotTokenTypes.WHITESPACE, 8 34 | " ", RobotTokenTypes.WHITESPACE, 8 35 | "Given", RobotTokenTypes.GHERKIN, 11 36 | " ", RobotTokenTypes.WHITESPACE, 8 37 | "calculator has been cleared", RobotTokenTypes.KEYWORD, 6 38 | "\n", RobotTokenTypes.WHITESPACE, 8 39 | " ", RobotTokenTypes.WHITESPACE, 8 40 | "When", RobotTokenTypes.GHERKIN, 11 41 | " ", RobotTokenTypes.WHITESPACE, 8 42 | "user types "1 + 1"", RobotTokenTypes.KEYWORD, 6 43 | "\n", RobotTokenTypes.WHITESPACE, 8 44 | " ", RobotTokenTypes.WHITESPACE, 8 45 | "And", RobotTokenTypes.GHERKIN, 11 46 | " ", RobotTokenTypes.WHITESPACE, 8 47 | "user pushes equals", RobotTokenTypes.KEYWORD, 6 48 | "\n", RobotTokenTypes.WHITESPACE, 8 49 | " ", RobotTokenTypes.WHITESPACE, 8 50 | "Then", RobotTokenTypes.GHERKIN, 11 51 | " ", RobotTokenTypes.WHITESPACE, 8 52 | "result is "2"", RobotTokenTypes.KEYWORD, 6 53 | "\n", RobotTokenTypes.WHITESPACE, 6 54 | "\n", RobotTokenTypes.WHITESPACE, 6 55 | "#Subtraction", RobotTokenTypes.COMMENT, 6 56 | "\n", RobotTokenTypes.WHITESPACE, 6 57 | "# [Tags] Calculator", RobotTokenTypes.COMMENT, 6 58 | "\n", RobotTokenTypes.WHITESPACE, 6 59 | "# TODO: implement me", RobotTokenTypes.COMMENT, 6 60 | "\n", RobotTokenTypes.WHITESPACE, 8 61 | "\n", RobotTokenTypes.WHITESPACE, 2 62 | "*** Keywords ***", RobotTokenTypes.HEADING, 3 63 | "\n", RobotTokenTypes.WHITESPACE, 3 64 | "Calculator has been cleared", RobotTokenTypes.KEYWORD_DEFINITION, 8 65 | "\n", RobotTokenTypes.WHITESPACE, 8 66 | " ", RobotTokenTypes.WHITESPACE, 8 67 | "Push button", RobotTokenTypes.KEYWORD, 6 68 | " ", RobotTokenTypes.WHITESPACE, 6 69 | "C", RobotTokenTypes.ARGUMENT, 6 70 | "\n", RobotTokenTypes.WHITESPACE, 8 71 | "\n", RobotTokenTypes.WHITESPACE, 3 72 | "User types "", RobotTokenTypes.KEYWORD_DEFINITION, 3 73 | "${expression}", RobotTokenTypes.VARIABLE_DEFINITION, 3 74 | """, RobotTokenTypes.KEYWORD_DEFINITION, 8 75 | "\n", RobotTokenTypes.WHITESPACE, 8 76 | " ", RobotTokenTypes.WHITESPACE, 8 77 | "Push buttons", RobotTokenTypes.KEYWORD, 6 78 | " ", RobotTokenTypes.WHITESPACE, 6 79 | "${expression}", RobotTokenTypes.VARIABLE, 6 80 | "\n", RobotTokenTypes.WHITESPACE, 8 81 | "\n", RobotTokenTypes.WHITESPACE, 3 82 | "User pushes equals", RobotTokenTypes.KEYWORD_DEFINITION, 8 83 | "\n", RobotTokenTypes.WHITESPACE, 8 84 | " ", RobotTokenTypes.WHITESPACE, 8 85 | "Push button", RobotTokenTypes.KEYWORD, 6 86 | " ", RobotTokenTypes.WHITESPACE, 6 87 | "=", RobotTokenTypes.ARGUMENT, 6 88 | "\n", RobotTokenTypes.WHITESPACE, 8 89 | "\n", RobotTokenTypes.WHITESPACE, 3 90 | "Result is "", RobotTokenTypes.KEYWORD_DEFINITION, 3 91 | "${result}", RobotTokenTypes.VARIABLE_DEFINITION, 3 92 | """, RobotTokenTypes.KEYWORD_DEFINITION, 8 93 | "\n", RobotTokenTypes.WHITESPACE, 8 94 | " ", RobotTokenTypes.WHITESPACE, 8 95 | "Result should be", RobotTokenTypes.KEYWORD, 6 96 | " ", RobotTokenTypes.WHITESPACE, 6 97 | "${result}", RobotTokenTypes.VARIABLE, 6 98 | "\n", RobotTokenTypes.WHITESPACE, 3 99 | "\n", RobotTokenTypes.null, 3 100 | -------------------------------------------------------------------------------- /testData/samples/Demo.robot: -------------------------------------------------------------------------------- 1 | invalid 2 | *** Settings *** 3 | Documentation This is some demo text 4 | Library CalculatorLibrary 5 | 6 | *** Variables *** 7 | ${var1} 12345 8 | ${var2} another variable 9 | 10 | *** Test Cases *** 11 | Addition 12 | [Tags] Calculator 13 | Given calculator has been cleared 14 | When user types "1 + 1" 15 | And user pushes equals 16 | Then result is "2" 17 | 18 | #Subtraction 19 | # [Tags] Calculator 20 | # TODO: implement me 21 | 22 | *** Keywords *** 23 | Calculator has been cleared 24 | Push button C 25 | 26 | User types "${expression}" 27 | Push buttons ${expression} 28 | 29 | User pushes equals 30 | Push button = 31 | 32 | Result is "${result}" 33 | Result should be ${result} -------------------------------------------------------------------------------- /testData/samples/Demo.txt: -------------------------------------------------------------------------------- 1 | FILE(0,614) 2 | PsiComment(COMMENT)('invalid')(0,7) 3 | HeadingImpl(HEADING)(8,101) 4 | PsiElement(HEADING)('*** Settings ***')(8,24) 5 | SettingImpl(SETTING)(25,65) 6 | PsiElement(SETTING)('Documentation')(25,38) 7 | ArgumentImpl(ARGUMENT)(43,65) 8 | PsiElement(ARGUMENT)('This is some demo text')(43,65) 9 | ImportImpl(IMPORT)(66,101) 10 | PsiElement(IMPORT)('Library')(66,73) 11 | ArgumentImpl(ARGUMENT)(84,101) 12 | PsiElement(ARGUMENT)('CalculatorLibrary')(84,101) 13 | HeadingImpl(HEADING)(103,161) 14 | PsiElement(HEADING)('*** Variables ***')(103,120) 15 | VariableDefinitionImpl(VARIABLE_DEFINITION)(121,135) 16 | VariableDefinitionIdImpl(VARIABLE_DEFINITION_ID)(121,128) 17 | PsiElement(VARIABLE_DEFINITION)('${var1}')(121,128) 18 | ArgumentImpl(ARGUMENT)(130,135) 19 | PsiElement(ARGUMENT)('12345')(130,135) 20 | VariableDefinitionImpl(VARIABLE_DEFINITION)(136,161) 21 | VariableDefinitionIdImpl(VARIABLE_DEFINITION_ID)(136,143) 22 | PsiElement(VARIABLE_DEFINITION)('${var2}')(136,143) 23 | ArgumentImpl(ARGUMENT)(145,161) 24 | PsiElement(ARGUMENT)('another variable')(145,161) 25 | HeadingImpl(HEADING)(163,327) 26 | PsiElement(HEADING)('*** Test Cases ***')(163,181) 27 | KeywordDefinitionImpl(KEYWORD_DEFINITION)(182,327) 28 | KeywordDefinitionIdImpl(KEYWORD_DEFINITION_ID)(182,190) 29 | PsiElement(KEYWORD_DEFINITION)('Addition')(182,190) 30 | BracketSettingImpl(BRACKET_SETTING)(193,211) 31 | PsiElement(BRACKET_SETTING)('[Tags]')(193,199) 32 | ArgumentImpl(ARGUMENT)(201,211) 33 | PsiElement(ARGUMENT)('Calculator')(201,211) 34 | KeywordStatementImpl(KEYWORD_STATEMENT)(216,249) 35 | PsiElement(GHERKIN)('Given')(216,221) 36 | KeywordInvokableImpl(KEYWORD)(222,249) 37 | PsiElement(KEYWORD)('calculator has been cleared')(222,249) 38 | KeywordStatementImpl(KEYWORD_STATEMENT)(254,277) 39 | PsiElement(GHERKIN)('When')(254,258) 40 | KeywordInvokableImpl(KEYWORD)(259,277) 41 | PsiElement(KEYWORD)('user types "1 + 1"')(259,277) 42 | KeywordStatementImpl(KEYWORD_STATEMENT)(282,304) 43 | PsiElement(GHERKIN)('And')(282,285) 44 | KeywordInvokableImpl(KEYWORD)(286,304) 45 | PsiElement(KEYWORD)('user pushes equals')(286,304) 46 | KeywordStatementImpl(KEYWORD_STATEMENT)(309,327) 47 | PsiElement(GHERKIN)('Then')(309,313) 48 | KeywordInvokableImpl(KEYWORD)(314,327) 49 | PsiElement(KEYWORD)('result is "2"')(314,327) 50 | PsiComment(COMMENT)('#Subtraction')(329,341) 51 | PsiComment(COMMENT)('# [Tags] Calculator')(342,363) 52 | PsiComment(COMMENT)('# TODO: implement me')(364,387) 53 | HeadingImpl(HEADING)(389,614) 54 | PsiElement(HEADING)('*** Keywords ***')(389,405) 55 | KeywordDefinitionImpl(KEYWORD_DEFINITION)(406,454) 56 | KeywordDefinitionIdImpl(KEYWORD_DEFINITION_ID)(406,433) 57 | PsiElement(KEYWORD_DEFINITION)('Calculator has been cleared')(406,433) 58 | KeywordStatementImpl(KEYWORD_STATEMENT)(438,454) 59 | KeywordInvokableImpl(KEYWORD)(438,449) 60 | PsiElement(KEYWORD)('Push button')(438,449) 61 | ArgumentImpl(ARGUMENT)(453,454) 62 | PsiElement(ARGUMENT)('C')(453,454) 63 | KeywordDefinitionImpl(KEYWORD_DEFINITION)(456,516) 64 | KeywordDefinitionIdImpl(KEYWORD_DEFINITION_ID)(456,482) 65 | PsiElement(KEYWORD_DEFINITION)('User types "')(456,468) 66 | VariableDefinitionImpl(VARIABLE_DEFINITION)(468,481) 67 | VariableDefinitionIdImpl(VARIABLE_DEFINITION_ID)(468,481) 68 | PsiElement(VARIABLE_DEFINITION)('${expression}')(468,481) 69 | PsiElement(KEYWORD_DEFINITION)('"')(481,482) 70 | KeywordStatementImpl(KEYWORD_STATEMENT)(487,516) 71 | KeywordInvokableImpl(KEYWORD)(487,499) 72 | PsiElement(KEYWORD)('Push buttons')(487,499) 73 | ArgumentImpl(ARGUMENT)(503,516) 74 | VariableImpl(VARIABLE)(503,516) 75 | PsiElement(VARIABLE)('${expression}')(503,516) 76 | KeywordDefinitionImpl(KEYWORD_DEFINITION)(518,557) 77 | KeywordDefinitionIdImpl(KEYWORD_DEFINITION_ID)(518,536) 78 | PsiElement(KEYWORD_DEFINITION)('User pushes equals')(518,536) 79 | KeywordStatementImpl(KEYWORD_STATEMENT)(541,557) 80 | KeywordInvokableImpl(KEYWORD)(541,552) 81 | PsiElement(KEYWORD)('Push button')(541,552) 82 | ArgumentImpl(ARGUMENT)(556,557) 83 | PsiElement(ARGUMENT)('=')(556,557) 84 | KeywordDefinitionImpl(KEYWORD_DEFINITION)(559,614) 85 | KeywordDefinitionIdImpl(KEYWORD_DEFINITION_ID)(559,580) 86 | PsiElement(KEYWORD_DEFINITION)('Result is "')(559,570) 87 | VariableDefinitionImpl(VARIABLE_DEFINITION)(570,579) 88 | VariableDefinitionIdImpl(VARIABLE_DEFINITION_ID)(570,579) 89 | PsiElement(VARIABLE_DEFINITION)('${result}')(570,579) 90 | PsiElement(KEYWORD_DEFINITION)('"')(579,580) 91 | KeywordStatementImpl(KEYWORD_STATEMENT)(585,614) 92 | KeywordInvokableImpl(KEYWORD)(585,601) 93 | PsiElement(KEYWORD)('Result should be')(585,601) 94 | ArgumentImpl(ARGUMENT)(605,614) 95 | VariableImpl(VARIABLE)(605,614) 96 | PsiElement(VARIABLE)('${result}')(605,614) -------------------------------------------------------------------------------- /testData/samples/EmptyHeaders.lexer.txt: -------------------------------------------------------------------------------- 1 | "*** Settings ***", RobotTokenTypes.HEADING, 1 2 | "\n", RobotTokenTypes.WHITESPACE, 1 3 | "\n", RobotTokenTypes.WHITESPACE, 1 4 | "*** Variables ***", RobotTokenTypes.HEADING, 4 5 | "\n", RobotTokenTypes.WHITESPACE, 4 6 | "\n", RobotTokenTypes.WHITESPACE, 4 7 | "*** Test Cases ***", RobotTokenTypes.HEADING, 2 8 | "\n", RobotTokenTypes.WHITESPACE, 2 9 | "\n", RobotTokenTypes.WHITESPACE, 2 10 | "*** Keywords ***", RobotTokenTypes.HEADING, 3 11 | "\n", RobotTokenTypes.WHITESPACE, 3 12 | "\n", RobotTokenTypes.WHITESPACE, 3 13 | "Clean Database", RobotTokenTypes.KEYWORD_DEFINITION, 8 14 | "\n", RobotTokenTypes.WHITESPACE, 8 15 | " ", RobotTokenTypes.WHITESPACE, 8 16 | "This works", RobotTokenTypes.KEYWORD, 6 17 | "\n", RobotTokenTypes.WHITESPACE, 8 18 | " ", RobotTokenTypes.WHITESPACE, 8 19 | "I will be happy", RobotTokenTypes.KEYWORD, 6 20 | "\n", RobotTokenTypes.WHITESPACE, 8 21 | "\n", RobotTokenTypes.WHITESPACE, 3 22 | "This works", RobotTokenTypes.KEYWORD_DEFINITION, 8 23 | "\n", RobotTokenTypes.WHITESPACE, 8 24 | " ", RobotTokenTypes.WHITESPACE, 8 25 | "log", RobotTokenTypes.KEYWORD, 6 26 | " ", RobotTokenTypes.WHITESPACE, 6 27 | "a", RobotTokenTypes.ARGUMENT, 6 28 | "\n", RobotTokenTypes.WHITESPACE, 8 29 | "\n", RobotTokenTypes.WHITESPACE, 3 30 | "I will be happy", RobotTokenTypes.KEYWORD_DEFINITION, 8 31 | "\n", RobotTokenTypes.WHITESPACE, 8 32 | " ", RobotTokenTypes.WHITESPACE, 8 33 | "log", RobotTokenTypes.KEYWORD, 6 34 | " ", RobotTokenTypes.WHITESPACE, 6 35 | "b", RobotTokenTypes.ARGUMENT, 6 36 | "\n", RobotTokenTypes.WHITESPACE, 3 37 | "\n", RobotTokenTypes.null, 3 38 | -------------------------------------------------------------------------------- /testData/samples/EmptyHeaders.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | 3 | *** Variables *** 4 | 5 | *** Test Cases *** 6 | 7 | *** Keywords *** 8 | 9 | Clean Database 10 | This works 11 | I will be happy 12 | 13 | This works 14 | log a 15 | 16 | I will be happy 17 | log b -------------------------------------------------------------------------------- /testData/samples/EmptyHeaders.txt: -------------------------------------------------------------------------------- 1 | FILE(0,175) 2 | HeadingImpl(HEADING)(0,16) 3 | PsiElement(HEADING)('*** Settings ***')(0,16) 4 | HeadingImpl(HEADING)(18,35) 5 | PsiElement(HEADING)('*** Variables ***')(18,35) 6 | HeadingImpl(HEADING)(37,55) 7 | PsiElement(HEADING)('*** Test Cases ***')(37,55) 8 | HeadingImpl(HEADING)(57,175) 9 | PsiElement(HEADING)('*** Keywords ***')(57,73) 10 | KeywordDefinitionImpl(KEYWORD_DEFINITION)(75,124) 11 | KeywordDefinitionIdImpl(KEYWORD_DEFINITION_ID)(75,89) 12 | PsiElement(KEYWORD_DEFINITION)('Clean Database')(75,89) 13 | KeywordStatementImpl(KEYWORD_STATEMENT)(94,104) 14 | KeywordInvokableImpl(KEYWORD)(94,104) 15 | PsiElement(KEYWORD)('This works')(94,104) 16 | KeywordStatementImpl(KEYWORD_STATEMENT)(109,124) 17 | KeywordInvokableImpl(KEYWORD)(109,124) 18 | PsiElement(KEYWORD)('I will be happy')(109,124) 19 | KeywordDefinitionImpl(KEYWORD_DEFINITION)(126,147) 20 | KeywordDefinitionIdImpl(KEYWORD_DEFINITION_ID)(126,136) 21 | PsiElement(KEYWORD_DEFINITION)('This works')(126,136) 22 | KeywordStatementImpl(KEYWORD_STATEMENT)(141,147) 23 | KeywordInvokableImpl(KEYWORD)(141,144) 24 | PsiElement(KEYWORD)('log')(141,144) 25 | ArgumentImpl(ARGUMENT)(146,147) 26 | PsiElement(ARGUMENT)('a')(146,147) 27 | KeywordDefinitionImpl(KEYWORD_DEFINITION)(149,175) 28 | KeywordDefinitionIdImpl(KEYWORD_DEFINITION_ID)(149,164) 29 | PsiElement(KEYWORD_DEFINITION)('I will be happy')(149,164) 30 | KeywordStatementImpl(KEYWORD_STATEMENT)(169,175) 31 | KeywordInvokableImpl(KEYWORD)(169,172) 32 | PsiElement(KEYWORD)('log')(169,172) 33 | ArgumentImpl(ARGUMENT)(174,175) 34 | PsiElement(ARGUMENT)('b')(174,175) -------------------------------------------------------------------------------- /testData/samples/Junk.lexer.txt: -------------------------------------------------------------------------------- 1 | "some junk", RobotTokenTypes.COMMENT, 0 2 | "\n", RobotTokenTypes.WHITESPACE, 0 3 | "\n", RobotTokenTypes.null, 0 4 | -------------------------------------------------------------------------------- /testData/samples/Junk.robot: -------------------------------------------------------------------------------- 1 | some junk -------------------------------------------------------------------------------- /testData/samples/Junk.txt: -------------------------------------------------------------------------------- 1 | FILE(0,9) 2 | PsiComment(COMMENT)('some junk')(0,9) -------------------------------------------------------------------------------- /testData/samples/ParsingTestData.robot: -------------------------------------------------------------------------------- 1 | documentation 2 | this is a sample file 3 | 4 | *** Settings *** 5 | # fun things going on here 6 | Documentation Test the account dashboard 7 | ... 8 | ... and this goes to the next line 9 | Documentation 10 | ... all new line 11 | 12 | Resource kyle/web/db_advertiser_actions.robot 13 | Resource kyle/web/db_campaign_actions.robot 14 | Resource kyle/web/db_staff_actions.robot 15 | Resource kyle/web/ui_login_page.robot 16 | Resource kyle/web/ui_manage_accounts_page.robot 17 | Resource kyle_db_cleanup/kyle_cleanup.robot 18 | Library Selenium2Library timeout=${ENV['selenium']['timeout']} implicit_wait=${ENV['selenium']['implicit_wait']} 19 | Library db.orm.Orm 20 | Library OperatingSystem 21 | Library Collections 22 | 23 | Force Tags Kyle Advertiser Dashboard Component #Other Tag 24 | Suite Teardown This works 25 | 26 | *** Variables *** 27 | 28 | ${Total_Requests} 97,000 29 | ${kw_timeout} 20 sec 30 | ${kw_retry_interval} 0.5 sec 31 | @{some_letters} A B C 32 | 33 | *** Test Cases *** 34 | 35 | Scenario: An admin can see the conversion trend 36 | [Tags] Was Flickering 37 | [Setup] Prepare advertiser "Robot_Company" 38 | Given Advertiser has performance data 39 | And I have an Account Manager MANAGER 40 | 41 | When I login to Tapmatch as Staff ${ACCOUNT_MANAGER.user.name} ${ACCOUNT_MANAGER.user.password} 42 | Then The 7-day average should be $0.09 43 | [Teardown] Run Keywords Close All Browsers Clean Database 44 | 45 | Scenario: This is also a keyword definition 46 | [Documentation] adding another 47 | # just for fun 48 | ... keyword will be classified correctly 49 | Given this sometimes works 50 | Then I will be happy 51 | And I will be happy 12 123 52 | 53 | *** Keywords *** 54 | 55 | Clean Database 56 | [Documentation] Cleans the database 57 | [Arguments] ${defined}=${Total_Requests} 58 | ${var1} = This works 1 59 | Clean Kyle 60 | ${var2} ${var3} = This should work 2 61 | ${defined} Clean Ike 62 | # Clean Other Stuff 63 | Close All Browsers 64 | 65 | 66 | This ${rate} works 67 | its a new ${rate} keyword 68 | run keyword if ${a}=${b} equal not equal 69 | [Return] ${Total_Requests} 70 | 71 | I will be happy 72 | there is a smile on my face ... -------------------------------------------------------------------------------- /testData/samples/TrimmedVariables.robot: -------------------------------------------------------------------------------- 1 | *** Variables *** 2 | ${VAR_1} variable 1 3 | ${VAR_2} variable 2 4 | ${VAR_3} variable 3 -------------------------------------------------------------------------------- /testData/samples/TrimmedVariables.txt: -------------------------------------------------------------------------------- 1 | FILE(0,79) 2 | HeadingImpl(HEADING)(0,68) 3 | PsiElement(HEADING)('*** Variables ***')(0,17) 4 | VariableDefinitionImpl(VARIABLE_DEFINITION)(18,38) 5 | VariableDefinitionIdImpl(VARIABLE_DEFINITION_ID)(18,26) 6 | PsiElement(VARIABLE_DEFINITION)('${VAR_1}')(18,26) 7 | ArgumentImpl(ARGUMENT)(28,38) 8 | PsiElement(ARGUMENT)('variable 1')(28,38) 9 | VariableDefinitionImpl(VARIABLE_DEFINITION)(39,59) 10 | VariableDefinitionIdImpl(VARIABLE_DEFINITION_ID)(39,47) 11 | PsiElement(VARIABLE_DEFINITION)('${VAR_2}')(39,47) 12 | ArgumentImpl(ARGUMENT)(49,59) 13 | PsiElement(ARGUMENT)('variable 2')(49,59) 14 | VariableDefinitionImpl(VARIABLE_DEFINITION)(60,68) 15 | VariableDefinitionIdImpl(VARIABLE_DEFINITION_ID)(60,68) 16 | PsiElement(VARIABLE_DEFINITION)('${VAR_3}')(60,68) -------------------------------------------------------------------------------- /testData/samples/Variables.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | 3 | Library Selenium2Library ${variable} ${${variable}.length} 4 | 5 | *** Variables *** 6 | 7 | ${variable} 1234 8 | 9 | *** Test Cases *** 10 | Do It Up 11 | User types "water" 12 | User then types falls 13 | "are" is then entered by user 14 | pretty is entered by user 15 | 16 | Do It Up Again 17 | User types "${variable}" 18 | User then types ${variable} 19 | "${variable}" is then entered by user 20 | ${variable} is entered by user 21 | User types "${variable}" and "${variable}" 22 | 23 | *** Keywords *** 24 | 25 | ${a} is entered by user 26 | Enter ${a} 27 | 28 | User types "${b}" and "${c}" 29 | ${b} is entered by user 30 | ${c} is entered by user 31 | 32 | "${d}" is then entered by user 33 | Enter ${d} 34 | 35 | User then types ${e} 36 | Enter ${e} 37 | log ${${e}[0]} 38 | 39 | User types "${f}" 40 | Enter ${f} 41 | [Return] ${${f}} 42 | 43 | Enter 44 | [Arguments] ${g} 45 | ${h}= log ${g} 46 | ${${h}} ${${g}}= log stuff 47 | [Return] ${h} 48 | 49 | Leave 50 | [Arguments] ${i}=1 51 | ... ${j}=2 52 | Log ${i} ${j} -------------------------------------------------------------------------------- /wiki/dev_setup/intellij_sdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/dev_setup/intellij_sdk.png -------------------------------------------------------------------------------- /wiki/dev_setup/plugin_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/dev_setup/plugin_config.png -------------------------------------------------------------------------------- /wiki/dev_setup/python_library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/dev_setup/python_library.png -------------------------------------------------------------------------------- /wiki/features/code_folding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/features/code_folding.png -------------------------------------------------------------------------------- /wiki/features/demo_complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/features/demo_complete.png -------------------------------------------------------------------------------- /wiki/features/find_usages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/features/find_usages.png -------------------------------------------------------------------------------- /wiki/features/jump_to_source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/features/jump_to_source.png -------------------------------------------------------------------------------- /wiki/features/keyword_recommendation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/features/keyword_recommendation.png -------------------------------------------------------------------------------- /wiki/features/structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/features/structure.png -------------------------------------------------------------------------------- /wiki/features/undefined_keyword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/features/undefined_keyword.png -------------------------------------------------------------------------------- /wiki/python_interpreter/intellij/module_interpreter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/python_interpreter/intellij/module_interpreter.png -------------------------------------------------------------------------------- /wiki/python_interpreter/intellij/project_sdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/python_interpreter/intellij/project_sdk.png -------------------------------------------------------------------------------- /wiki/python_interpreter/intellij/python_plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/python_interpreter/intellij/python_plugin.png -------------------------------------------------------------------------------- /wiki/python_interpreter/pycharm/console_interpreter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/python_interpreter/pycharm/console_interpreter.png -------------------------------------------------------------------------------- /wiki/python_interpreter/pycharm/project_interpreter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/python_interpreter/pycharm/project_interpreter.png -------------------------------------------------------------------------------- /wiki/robot_options/event_log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/robot_options/event_log.png -------------------------------------------------------------------------------- /wiki/robot_options/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/robot_options/options.png -------------------------------------------------------------------------------- /wiki/test_debugging/debug_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/test_debugging/debug_settings.png -------------------------------------------------------------------------------- /wiki/using_txt_files/txt_file_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtrubs/intellibot/a0e24156fb6bc5302f9d15737f7ada5836780f7f/wiki/using_txt_files/txt_file_type.png --------------------------------------------------------------------------------