├── .idea ├── .name ├── ant.xml ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── haxe.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── libraries │ └── KotlinJavaRuntime.xml ├── misc.xml ├── modules.xml ├── scopes │ └── scope_settings.xml ├── uiDesigner.xml └── vcs.xml ├── META-INF └── plugin.xml ├── README.md ├── angularjs-plugin.iml ├── lib └── kotlin-runtime.jar ├── ng-attributes.txt ├── resources └── liveTemplates │ └── AngularJS.xml └── src ├── intentionDescriptions └── OpenInDocsIntention │ ├── after.java.template │ ├── before.java.template │ └── description.html └── org └── angularjs ├── AngularAttributeDescriptor.kt ├── AngularBracesInterpolationTypedHandler.kt ├── AngularCompletionContributor.java ├── AngularInspection.java ├── AngularItem.java ├── AngularJS.kt ├── AngularJSConfig.kt ├── AngularJSConfigAnnotationPatch.java ├── AngularJSConfigTemp.java ├── AngularJSConfigurationPage.form ├── AngularJSConfigurationPage.java ├── AngularJSCustomAttributeDescriptorsProvider.kt ├── AngularJSTemplatesProvider.kt ├── DirectiveCompletionContributor.kt ├── GotoAngularAction.java ├── GotoAngularModel.java └── OpenInDocsIntention.kt /.idea/.name: -------------------------------------------------------------------------------- 1 | angularjs-plugin -------------------------------------------------------------------------------- /.idea/ant.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/haxe.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/libraries/KotlinJavaRuntime.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 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 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | AngularJS 3 | Support for AngularJS 4 | 0.1.9 5 | johnlindquist 6 | 8 |
9 |
0.1.9
10 |
Added a setting for whitespace between braces
11 |
0.1.8
12 |
Fixing bug introduced by autocomplete with invalid elements (had to "revert" to old method of autocomplete, so I need to find a new approach for invalid elements
13 |
0.1.7
14 |
Focusing on WebStorm 7 compatibility
15 |
0.1.6
16 |
Adding navigation, auto-closing {{, attribute autocomplete on all elements, and "jump to docs"
17 |
0.1.5
18 |
Adding "href" and "disabled" to the descriptors list
19 |
0.1.4
20 |
Bundling live templates thanks to Powel Kozlowski
21 |
0.1.3
22 |
Adding the mouse events and a couple other missing directives
23 |
0.1.2
24 |
Works with any doctype (not just !doctype html).
25 |
0.1.1
26 |
Changed Autocomplete approach to "provide" custom autocompletes through a provider extension point. I'll 27 | revisit a custom DTD after more discussion/thought with other developers. 28 |
29 |
0.1
30 |
Basic ng attribute autocompletion based on an included DTD.
31 |
32 | 33 | ]]> 34 |
35 | 36 | 37 | 38 | 39 | 40 | JavaScript 41 | com.intellij.modules.platform 42 | 43 | 44 | 45 | org.angularjs.AngularJS 46 | 47 | 48 | 49 | 50 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.angularjs.OpenInDocsIntention 73 | HTML 74 | HTML 75 | 76 | 81 | 82 | 83 |
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AngularJS Support for the Intellij Platform (WebStorm, PhpStorm, Rubymine, Intellij, etc) 2 | 3 | ## Installing the AngularJS plugin for Webstorm 4 | 5 | - Navigate to File->Settings->Plugins 6 | - Click "Browse Repositories" 7 | - Select "AngularJS" 8 | - Double-click (or right-click) and, when prompted, choose "Yes" 9 | - Restart WebStorm 10 | -------------------------------------------------------------------------------- /angularjs-plugin.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /lib/kotlin-runtime.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnlindquist/angularjs-plugin/e7d5f80e9e3d321e48091f34a434b178a2c24e97/lib/kotlin-runtime.jar -------------------------------------------------------------------------------- /ng-attributes.txt: -------------------------------------------------------------------------------- 1 | ng-app,ng-bind,ng-bind-html-unsafe,ng-bind-template,ng-class,ng-class-even,ng-class-odd,ng-cloak,ng-controller,ng-form,ng-hide,ng-include,ng-init,ng-non-bindable,ng-pluralize,ng-repeat,ng-show,ng-submit,ng-style,ng-switch,ng-switch-when,ng-switch-default,ng-options,ng-view,ng-transclude,ng-model,ng-list,ng-change,ng-value,ng-required,required -------------------------------------------------------------------------------- /resources/liveTemplates/AngularJS.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 37 | 56 | 75 | 93 | 110 | 111 | 128 | 146 | 163 | 180 | 181 | 199 | 217 | 236 | 254 | 272 | 291 | 292 | 311 | 330 | 347 | 348 | 366 | 384 | 401 | 418 | 436 | 454 | 472 | 473 | 474 | -------------------------------------------------------------------------------- /src/intentionDescriptions/OpenInDocsIntention/after.java.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnlindquist/angularjs-plugin/e7d5f80e9e3d321e48091f34a434b178a2c24e97/src/intentionDescriptions/OpenInDocsIntention/after.java.template -------------------------------------------------------------------------------- /src/intentionDescriptions/OpenInDocsIntention/before.java.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnlindquist/angularjs-plugin/e7d5f80e9e3d321e48091f34a434b178a2c24e97/src/intentionDescriptions/OpenInDocsIntention/before.java.template -------------------------------------------------------------------------------- /src/intentionDescriptions/OpenInDocsIntention/description.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This intention opens the docs for an AngularJS directive 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularAttributeDescriptor.kt: -------------------------------------------------------------------------------- 1 | package org.angularjs 2 | 3 | import com.intellij.xml.impl.schema.AnyXmlAttributeDescriptor 4 | import com.intellij.psi.PsiElement 5 | 6 | /** 7 | * Created by johnlindquist on 6/26/13. 8 | */ 9 | public class AngularAttributeDescriptor(attrName: String?): AnyXmlAttributeDescriptor(attrName) { 10 | val attrName = attrName 11 | 12 | public override fun getDeclaration(): PsiElement? { 13 | //TODO: implement looking up declarations... 14 | return null 15 | } 16 | 17 | 18 | } -------------------------------------------------------------------------------- /src/org/angularjs/AngularBracesInterpolationTypedHandler.kt: -------------------------------------------------------------------------------- 1 | package org.angularjs 2 | 3 | import com.intellij.codeInsight.editorActions.TypedHandlerDelegate 4 | import com.intellij.ide.highlighter.HtmlFileType 5 | import com.intellij.openapi.editor.Document 6 | import com.intellij.openapi.editor.Editor 7 | import com.intellij.openapi.editor.EditorModificationUtil 8 | import com.intellij.openapi.fileTypes.FileType 9 | import com.intellij.openapi.project.Project 10 | import com.intellij.psi.PsiFile 11 | 12 | /** 13 | * Heavily borrow from @dcheryasov's work on Django braces 14 | */ 15 | public open class AngularBracesInterpolationTypedHandler(): TypedHandlerDelegate() { 16 | public override fun beforeCharTyped(c: Char, project: Project?, editor: Editor?, file: PsiFile?, fileType: FileType?): TypedHandlerDelegate.Result? { 17 | if(!AngularJSConfig.braceEnabled) return TypedHandlerDelegate.Result.DEFAULT; 18 | if (file?.getFileType() == HtmlFileType.INSTANCE) 19 | { 20 | if (c == '{') 21 | { 22 | val addWhiteSpaceBetweenBraces = AngularJSConfig.whiteSpace 23 | val document: Document? = editor?.getDocument() 24 | val offset: Int = editor?.getCaretModel()?.getOffset()!! 25 | var chars: CharSequence? = document?.getCharsSequence() 26 | if (offset > 0 && (chars?.charAt(offset - 1)) == '{') 27 | { 28 | if (offset < 2 || (chars?.charAt(offset - 2)) != '{') 29 | { 30 | if (alreadyHasEnding(chars, c, offset)) 31 | { 32 | return TypedHandlerDelegate.Result.CONTINUE 33 | } 34 | else 35 | { 36 | var interpolation: String? = null 37 | if (c == '{') 38 | { 39 | if(addWhiteSpaceBetweenBraces) 40 | { 41 | interpolation = "{ }" 42 | 43 | } 44 | else{ 45 | interpolation = "{}" 46 | } 47 | } 48 | 49 | if (interpolation != null) 50 | { 51 | if (offset == (chars?.length()) || (offset < (chars?.length())!! && (chars?.charAt(offset)) != '}')) 52 | { 53 | interpolation += "}" 54 | } 55 | 56 | var move = 2 57 | if(!addWhiteSpaceBetweenBraces) move = 1 58 | 59 | typeInStringAndMoveCaret(editor, offset + move, interpolation) 60 | return TypedHandlerDelegate.Result.STOP 61 | } 62 | 63 | } 64 | } 65 | 66 | } 67 | 68 | } 69 | 70 | } 71 | 72 | return TypedHandlerDelegate.Result.CONTINUE 73 | } 74 | 75 | class object { 76 | open fun typeInStringAndMoveCaret(editor: Editor?, offset: Int, str: String?): Unit { 77 | EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(editor, str, true) 78 | editor?.getCaretModel()?.moveToOffset(offset) 79 | } 80 | private open fun alreadyHasEnding(chars: CharSequence?, c: Char, offset: Int): Boolean { 81 | var i: Int = offset 82 | var endChar: Char 83 | if (c == '{') 84 | { 85 | endChar = '}' 86 | } 87 | else 88 | { 89 | endChar = c 90 | } 91 | while (i < (chars?.length())!! && ((chars?.charAt(i)) != '{' && (chars?.charAt(i)) != endChar && (chars?.charAt(i)) != '\n')) 92 | { 93 | i++ 94 | } 95 | if (i + 1 < (chars?.length())!! && (chars?.charAt(i)) == endChar && (chars?.charAt(i + 1)) == '}') 96 | { 97 | return true 98 | } 99 | 100 | return false 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularCompletionContributor.java: -------------------------------------------------------------------------------- 1 | package org.angularjs; 2 | 3 | import com.intellij.codeInsight.completion.CompletionContributor; 4 | import com.intellij.codeInsight.completion.CompletionParameters; 5 | import com.intellij.codeInsight.completion.CompletionResultSet; 6 | import com.intellij.codeInsight.lookup.LookupElementBuilder; 7 | import com.intellij.find.FindManager; 8 | import com.intellij.find.FindModel; 9 | import com.intellij.find.impl.FindInProjectUtil; 10 | import com.intellij.lang.javascript.psi.ecmal4.JSQualifiedNamedElement; 11 | import com.intellij.openapi.application.ApplicationManager; 12 | import com.intellij.openapi.editor.Document; 13 | import com.intellij.openapi.project.Project; 14 | import com.intellij.openapi.util.Segment; 15 | import com.intellij.lang.javascript.psi.resolve.JSResolveUtil; 16 | import com.intellij.psi.PsiDirectory; 17 | import com.intellij.psi.PsiElement; 18 | import com.intellij.psi.PsiManager; 19 | import com.intellij.psi.search.GlobalSearchScope; 20 | import com.intellij.psi.search.ProjectScope; 21 | import com.intellij.psi.util.PsiUtilBase; 22 | import com.intellij.usageView.UsageInfo; 23 | import com.intellij.usages.FindUsagesProcessPresentation; 24 | import com.intellij.usages.Usage; 25 | import com.intellij.usages.UsageInfo2UsageAdapter; 26 | import com.intellij.util.AdapterProcessor; 27 | import com.intellij.util.CommonProcessors; 28 | import com.intellij.util.Processor; 29 | 30 | import java.util.Collection; 31 | 32 | public class AngularCompletionContributor extends CompletionContributor { 33 | @Override 34 | public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet result) { 35 | result.addElement(LookupElementBuilder.create("huzzah")); 36 | 37 | final Project project = parameters.getOriginalFile().getProject(); 38 | 39 | GlobalSearchScope scope = ProjectScope.getProjectScope(project); 40 | 41 | Collection scopes = JSResolveUtil.findElementsByName("$scope", project, scope); 42 | 43 | 44 | String s = "\\$scope\\.(\\w*)"; 45 | 46 | final FindManager findManager = FindManager.getInstance(project); 47 | final FindModel findModel = (FindModel) findManager.getFindInFileModel().clone(); 48 | 49 | 50 | findModel.setRegularExpressions(true); 51 | findModel.setFileFilter("*.js, *.html"); 52 | 53 | findModel.setStringToFind(s); 54 | findModel.setStringToReplace("$1"); 55 | 56 | CommonProcessors.CollectProcessor collectProcessor = new CommonProcessors.CollectProcessor(); 57 | 58 | PsiDirectory directory = PsiManager.getInstance(project).findDirectory(project.getBaseDir()); 59 | FindInProjectUtil.findUsages(findModel, directory, project, 60 | true, new AdapterProcessor(collectProcessor, UsageInfo2UsageAdapter.CONVERTER), new FindUsagesProcessPresentation()); 61 | 62 | 63 | final Collection usages = collectProcessor.getResults(); 64 | 65 | //todo: needs code review. There must be a better way to do this 66 | Runnable runnable = new Runnable() { 67 | public void run() { 68 | for (final Usage r : usages) { 69 | 70 | final UsageInfo2UsageAdapter usage = (UsageInfo2UsageAdapter) r; 71 | //avoid angular source files. Is there a better way to do this? 72 | if (usage.getFile().getName().startsWith("angular")) continue; 73 | 74 | usage.processRangeMarkers(new Processor() { 75 | @Override 76 | public boolean process(Segment segment) { 77 | try { 78 | final int textOffset = segment.getStartOffset(); 79 | 80 | final int textEndOffset = segment.getEndOffset(); 81 | Document document = usage.getDocument(); 82 | CharSequence charsSequence = document.getCharsSequence(); 83 | final CharSequence foundString = charsSequence.subSequence(textOffset, textEndOffset); 84 | String s = foundString.toString(); 85 | String regExMatch = FindManager.getInstance(project).getStringToReplace(s, findModel, textOffset, document.getText()); 86 | System.out.println(regExMatch); 87 | PsiElement element = PsiUtilBase.getElementAtOffset(((UsageInfo2UsageAdapter) r).getUsageInfo().getFile(), textOffset + 1); 88 | PsiElement propElement = PsiUtilBase.getElementAtOffset(((UsageInfo2UsageAdapter) r).getUsageInfo().getFile(), textOffset + 1 + "$scope".length()); 89 | String elementText = element.getText(); 90 | System.out.println(elementText + ": " + regExMatch + " - " + s); 91 | 92 | result.addElement(LookupElementBuilder.create(propElement, propElement.getText())); 93 | 94 | return true; 95 | } catch (FindManager.MalformedReplacementStringException e1) { 96 | e1.printStackTrace(); 97 | } 98 | 99 | return false; 100 | } 101 | }); 102 | } 103 | 104 | result.addLookupAdvertisement("Results based on all '$scope's"); 105 | GlobalSearchScope scope = ProjectScope.getProjectScope(project); 106 | 107 | } 108 | }; 109 | 110 | ApplicationManager.getApplication().runReadAction(runnable); 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularInspection.java: -------------------------------------------------------------------------------- 1 | package org.angularjs; 2 | 3 | import com.intellij.codeInspection.ProblemsHolder; 4 | import com.intellij.codeInspection.htmlInspections.HtmlLocalInspectionTool; 5 | import com.intellij.psi.xml.XmlAttribute; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Created with IntelliJ IDEA. 10 | * User: johnlindquist 11 | * Date: 4/8/13 12 | * Time: 3:22 PM 13 | * To change this template use File | Settings | File Templates. 14 | */ 15 | public class AngularInspection extends HtmlLocalInspectionTool { 16 | @Override 17 | protected void checkAttribute(@NotNull XmlAttribute attribute, @NotNull ProblemsHolder holder, boolean isOnTheFly) { 18 | super.checkAttribute(attribute, holder, isOnTheFly); //To change body of overridden methods use File | Settings | File Templates. 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularItem.java: -------------------------------------------------------------------------------- 1 | package org.angularjs; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.usages.Usage; 5 | 6 | /** 7 | * Created with IntelliJ IDEA. 8 | * User: johnlindquist 9 | * Date: 3/27/13 10 | * Time: 9:56 AM 11 | * To change this template use File | Settings | File Templates. 12 | */ 13 | public class AngularItem { 14 | private String itemName; 15 | private String key; 16 | 17 | public Usage getUsage() { 18 | return usage; 19 | } 20 | 21 | private Usage usage; 22 | private PsiElement element; 23 | private final String itemType; 24 | 25 | public PsiElement getElement() { 26 | return element; 27 | } 28 | 29 | AngularItem(String key, String itemName, Usage usage, PsiElement element, String itemType) { 30 | this.key = key; 31 | this.itemName = itemName; 32 | this.usage = usage; 33 | this.element = element; 34 | this.itemType = itemType; 35 | } 36 | 37 | 38 | public String getItemName() { 39 | return itemName; 40 | } 41 | 42 | public String getItemType() { 43 | return itemType; 44 | } 45 | 46 | public String getKey() { 47 | return key; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularJS.kt: -------------------------------------------------------------------------------- 1 | package org.angularjs 2 | 3 | import com.intellij.openapi.components.ProjectComponent 4 | import kotlin.properties.Delegates 5 | import java.util.HashMap 6 | import com.intellij.xml.XmlAttributeDescriptor 7 | import com.intellij.openapi.project.Project 8 | import com.intellij.openapi.components.AbstractProjectComponent 9 | 10 | /** 11 | * Created by johnlindquist on 6/28/13. 12 | */ 13 | open class AngularJS(project:Project):AbstractProjectComponent(project){ 14 | val directiveNames: Array = array( 15 | "animate", 16 | "app", 17 | "bind", 18 | "bind-html-unsafe", 19 | "bind-template", 20 | "change", 21 | "checked", 22 | "class", 23 | "class-even", 24 | "class-odd", 25 | "click", 26 | "cloak", 27 | "controller", 28 | "csp", 29 | "dblclick", 30 | "disabled", 31 | "false-value", 32 | "form", 33 | "hide", 34 | "href", 35 | "if", 36 | "include", 37 | "init", 38 | "keypress", 39 | "list", 40 | "minlength", 41 | "maxlength", 42 | "model", 43 | "mousedown", 44 | "mouseup", 45 | "mouseover", 46 | "mouseout", 47 | "mousemove", 48 | "mouseenter", 49 | "mouseleave", 50 | "multiple", 51 | "non-bindable", 52 | "options", 53 | "pattern", 54 | "pluralize", 55 | "readonly", 56 | "repeat", 57 | "required", 58 | "selected", 59 | "show", 60 | "src", 61 | "srcset", 62 | "submit", 63 | "style", 64 | "swipe", 65 | "switch", 66 | "switch-when", 67 | "switch-default", 68 | "transclude", 69 | "true-value", 70 | "value", 71 | "view") 72 | var attrs:jet.List by Delegates.notNull() 73 | val attrLookup:HashMap = hashMapOf() 74 | var attrArray:Array by Delegates.notNull() 75 | 76 | class object{ 77 | fun getInstance(project : Project?) : AngularJS { 78 | return project?.getComponent(javaClass())!! 79 | } 80 | } 81 | 82 | public override fun initComponent() { 83 | 84 | attrs = directiveNames.map { name -> AngularAttributeDescriptor("ng-" + name)} 85 | attrs.forEach { 86 | descriptor -> attrLookup.put(descriptor.getName()!!, descriptor) 87 | } 88 | attrArray = attrs.toArray(array()) 89 | } 90 | public override fun disposeComponent() { 91 | 92 | } 93 | org.jetbrains.annotations.NonNls public override fun getComponentName(): String { 94 | return "AngularJSProjectComponent" 95 | } 96 | public override fun projectOpened() { 97 | 98 | } 99 | public override fun projectClosed() { 100 | 101 | } 102 | } -------------------------------------------------------------------------------- /src/org/angularjs/AngularJSConfig.kt: -------------------------------------------------------------------------------- 1 | package org.angularjs 2 | 3 | import com.intellij.openapi.options.SearchableConfigurable 4 | import com.intellij.openapi.application.ApplicationManager 5 | import com.intellij.ide.util.PropertiesComponent 6 | 7 | /** 8 | * Created by johnlindquist on 7/10/13. 9 | */ 10 | public abstract class AngularJSConfig() { 11 | class object { 12 | var componentName: String = "AngularJSConfig" 13 | val addWhiteSpaceName: String = "AngularJSConfig.addWhitespaceBetweenBraces" 14 | val braceEnabledName: String = "AngularJSConfig.braceEnabled" 15 | var whiteSpace: Boolean 16 | get(){ 17 | return PropertiesComponent.getInstance()!!.getBoolean(addWhiteSpaceName, false) 18 | } 19 | set(value: Boolean) { 20 | var str:String = "true" 21 | if(!value) str = "false" 22 | PropertiesComponent.getInstance()!!.setValue(addWhiteSpaceName, str) 23 | } 24 | var braceEnabled: Boolean 25 | get(){ 26 | return PropertiesComponent.getInstance()!!.getBoolean(braceEnabledName, false) 27 | } 28 | set(value: Boolean) { 29 | var str:String = "true" 30 | if(!value) str = "false" 31 | PropertiesComponent.getInstance()!!.setValue(braceEnabledName, str) 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/org/angularjs/AngularJSConfigAnnotationPatch.java: -------------------------------------------------------------------------------- 1 | package org.angularjs; 2 | 3 | import com.intellij.openapi.components.State; 4 | import com.intellij.openapi.components.Storage; 5 | import com.intellij.openapi.components.StoragePathMacros; 6 | 7 | /** 8 | * Created by johnlindquist on 7/11/13. 9 | */ 10 | @State( 11 | name = "JavaCodeFoldingSettings", 12 | storages = { 13 | @Storage( 14 | file = StoragePathMacros.APP_CONFIG + "/angularjs.xml" 15 | )} 16 | ) 17 | public class AngularJSConfigAnnotationPatch { 18 | } 19 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularJSConfigTemp.java: -------------------------------------------------------------------------------- 1 | package org.angularjs; 2 | 3 | import com.intellij.openapi.components.*; 4 | import com.intellij.openapi.options.Configurable; 5 | import com.intellij.openapi.options.ConfigurationException; 6 | import com.intellij.util.xmlb.XmlSerializerUtil; 7 | import org.jetbrains.annotations.Nls; 8 | import org.jetbrains.annotations.NonNls; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import javax.swing.*; 13 | import java.awt.*; 14 | 15 | /** 16 | * Created by johnlindquist on 7/11/13. 17 | * 18 | * This class is a temporary fix until Kotlin supports nested annotations 19 | */ 20 | @State( 21 | name="AngularJS", 22 | storages= { 23 | @Storage( 24 | file = StoragePathMacros.APP_CONFIG + "/angularjs.xml" 25 | )} 26 | ) 27 | public class AngularJSConfigTemp extends AngularJSConfig implements Configurable, PersistentStateComponent, ApplicationComponent { 28 | @Override 29 | public void initComponent() { 30 | 31 | } 32 | 33 | @Override 34 | public void disposeComponent() { 35 | 36 | } 37 | 38 | @Nls 39 | @Override 40 | public String getDisplayName() { 41 | return "AngularJS"; 42 | } 43 | 44 | @Nullable 45 | @Override 46 | public String getHelpTopic() { 47 | return "settings.angularjs"; 48 | } 49 | 50 | @NotNull 51 | @Override 52 | public String getComponentName() { 53 | return AngularJSConfig.object$.getComponentName(); 54 | } 55 | 56 | @Nullable 57 | @Override 58 | public AngularJSConfig getState() { 59 | return this; 60 | } 61 | 62 | @Override 63 | public void loadState(AngularJSConfig state) { 64 | XmlSerializerUtil.copyBean(state, this); 65 | } 66 | 67 | @Nullable 68 | @Override 69 | public JComponent createComponent() { 70 | return null; 71 | } 72 | 73 | @Override 74 | public boolean isModified() { 75 | return false; 76 | } 77 | 78 | @Override 79 | public void apply() throws ConfigurationException { 80 | 81 | } 82 | 83 | @Override 84 | public void reset() { 85 | 86 | } 87 | 88 | @Override 89 | public void disposeUIResources() { 90 | 91 | } 92 | 93 | public static class UIImpl extends JPanel implements Configurable { 94 | 95 | 96 | private final JCheckBox addWhitespaceBetweenBraces; 97 | 98 | 99 | public UIImpl() { 100 | setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 101 | addWhitespaceBetweenBraces = new JCheckBox("Add Whitespace Between Braces"); 102 | addWhitespaceBetweenBraces.setMnemonic('A'); 103 | addWhitespaceBetweenBraces.setSelected(AngularJSConfig.object$.getWhiteSpace()); 104 | 105 | add(addWhitespaceBetweenBraces); 106 | 107 | final JPanel jPanel = new JPanel(new BorderLayout()); 108 | jPanel.add(Box.createVerticalGlue(), BorderLayout.CENTER); 109 | 110 | final JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER)); 111 | jPanel.add(panel, BorderLayout.SOUTH); 112 | jPanel.setAlignmentX(0); 113 | add(jPanel); 114 | } 115 | 116 | @Nls 117 | public String getDisplayName() { 118 | return "AngularJS"; 119 | } 120 | 121 | @Nullable 122 | @NonNls 123 | public String getHelpTopic() { 124 | return "settings.angularjs"; 125 | } 126 | 127 | public void disposeUIResources() { 128 | } 129 | 130 | public JComponent createComponent() { 131 | return this; 132 | } 133 | 134 | public boolean isModified() { 135 | return AngularJSConfig.object$.getWhiteSpace() != addWhitespaceBetweenBraces.isSelected(); 136 | } 137 | 138 | public void apply() { 139 | boolean oldValue = AngularJSConfig.object$.getWhiteSpace(); 140 | 141 | AngularJSConfig.object$.setWhiteSpace(addWhitespaceBetweenBraces.isSelected()); 142 | 143 | // TODO: make this a ConfigListener 144 | if (oldValue != AngularJSConfig.object$.getWhiteSpace()) { 145 | } 146 | } 147 | 148 | public void reset() { 149 | } 150 | 151 | @NotNull 152 | public String getId() { 153 | return getHelpTopic(); 154 | } 155 | 156 | public Runnable enableSearch(String option) { 157 | return null; 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularJSConfigurationPage.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 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularJSConfigurationPage.java: -------------------------------------------------------------------------------- 1 | package org.angularjs; 2 | 3 | import com.intellij.openapi.options.ConfigurationException; 4 | import com.intellij.openapi.options.SearchableConfigurable; 5 | import org.jetbrains.annotations.Nls; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.*; 10 | import java.awt.event.ItemEvent; 11 | import java.awt.event.ItemListener; 12 | 13 | /** 14 | * Created by johnlindquist on 9/23/13. 15 | */ 16 | public class AngularJSConfigurationPage implements SearchableConfigurable { 17 | private JCheckBox includeWhitespaceBetweenBracesCheckBox; 18 | private JPanel myPanel; 19 | private JCheckBox enableAutomaticBraceInsertionCheckBox; 20 | 21 | @NotNull 22 | @Override 23 | public String getId() { 24 | return "editor.preferences.AngularJS"; 25 | } 26 | 27 | @Nullable 28 | @Override 29 | public Runnable enableSearch(String option) { 30 | return null; 31 | } 32 | 33 | @Nls 34 | @Override 35 | public String getDisplayName() { 36 | return "AngularJS"; 37 | } 38 | 39 | @Nullable 40 | @Override 41 | public String getHelpTopic() { 42 | return null; 43 | } 44 | 45 | @Nullable 46 | @Override 47 | public JComponent createComponent() { 48 | includeWhitespaceBetweenBracesCheckBox.setSelected(AngularJSConfig.object$.getWhiteSpace()); 49 | includeWhitespaceBetweenBracesCheckBox.addItemListener(new ItemListener() { 50 | @Override 51 | public void itemStateChanged(ItemEvent itemEvent) { 52 | boolean selected = includeWhitespaceBetweenBracesCheckBox.isSelected(); 53 | AngularJSConfig.object$.setWhiteSpace(selected); 54 | } 55 | }); 56 | 57 | enableAutomaticBraceInsertionCheckBox.setSelected(AngularJSConfig.object$.getBraceEnabled()); 58 | enableAutomaticBraceInsertionCheckBox.addItemListener(new ItemListener() { 59 | @Override 60 | public void itemStateChanged(ItemEvent itemEvent) { 61 | boolean selected = enableAutomaticBraceInsertionCheckBox.isSelected(); 62 | AngularJSConfig.object$.setBraceEnabled(selected); 63 | } 64 | }); 65 | 66 | 67 | return myPanel; 68 | } 69 | 70 | @Override 71 | public boolean isModified() { 72 | return false; 73 | } 74 | 75 | @Override 76 | public void apply() throws ConfigurationException { 77 | 78 | } 79 | 80 | @Override 81 | public void reset() { 82 | 83 | } 84 | 85 | @Override 86 | public void disposeUIResources() { 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularJSCustomAttributeDescriptorsProvider.kt: -------------------------------------------------------------------------------- 1 | package org.angularjs 2 | 3 | import com.intellij.psi.xml.XmlTag 4 | import com.intellij.xml.XmlAttributeDescriptor 5 | import com.intellij.xml.XmlAttributeDescriptorsProvider 6 | import com.intellij.xml.impl.schema.AnyXmlAttributeDescriptor 7 | import java.util.ArrayList 8 | import com.intellij.xml.impl.dom.DomAttributeXmlDescriptor 9 | import com.intellij.util.xml.DomElement 10 | import com.intellij.util.xml.DomManager 11 | import com.intellij.util.xml.reflect.DomAttributeChildDescription 12 | import java.util.HashMap 13 | import kotlin.properties.Delegates 14 | 15 | public open class AngularJSCustomAttributeDescriptorsProvider(): XmlAttributeDescriptorsProvider { 16 | var angularjs:AngularJS? = null 17 | 18 | public override fun getAttributeDescriptors(tag: XmlTag?): Array? { 19 | if(angularjs == null) angularjs = AngularJS.getInstance(tag?.getProject()) 20 | 21 | if (tag == null) 22 | { 23 | return XmlAttributeDescriptor.EMPTY 24 | } 25 | 26 | return angularjs?.attrArray 27 | } 28 | public override fun getAttributeDescriptor(attributeName: String?, context: XmlTag?): XmlAttributeDescriptor? { 29 | if (context != null) 30 | { 31 | val descriptor = angularjs?.attrLookup?.get(attributeName) 32 | if(descriptor == null) return null 33 | return descriptor 34 | } 35 | 36 | return null 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/org/angularjs/AngularJSTemplatesProvider.kt: -------------------------------------------------------------------------------- 1 | package org.angularjs 2 | 3 | import com.intellij.codeInsight.template.impl.DefaultLiveTemplatesProvider 4 | 5 | public open class AngularJSTemplatesProvider(): DefaultLiveTemplatesProvider { 6 | public override fun getDefaultLiveTemplateFiles(): Array? { 7 | return array("liveTemplates/AngularJS") 8 | } 9 | public override fun getHiddenLiveTemplateFiles(): Array? { 10 | return null 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/org/angularjs/DirectiveCompletionContributor.kt: -------------------------------------------------------------------------------- 1 | package org.angularjs 2 | 3 | import com.intellij.codeInsight.completion.CompletionContributor 4 | import com.intellij.codeInsight.completion.CompletionParameters 5 | import com.intellij.codeInsight.completion.CompletionResultSet 6 | import com.intellij.codeInsight.lookup.LookupElementBuilder 7 | import com.intellij.codeInsight.completion.CompletionType 8 | import com.intellij.codeInsight.completion.CompletionProvider 9 | import com.intellij.util.ProcessingContext 10 | import com.intellij.patterns.XmlPatterns 11 | import com.intellij.patterns.PlatformPatterns 12 | import com.intellij.codeInsight.completion.XmlAttributeInsertHandler 13 | 14 | public open class DirectiveCompletionContributor(): CompletionContributor() { 15 | { 16 | //attribute value 17 | extend(CompletionType.BASIC, PlatformPatterns.psiElement()?.inside(XmlPatterns.xmlAttributeValue()!!), object : CompletionProvider() { 18 | protected override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext?, result: CompletionResultSet): Unit { 19 | if (parameters.getCompletionType() != CompletionType.BASIC) 20 | return 21 | 22 | 23 | } 24 | }) 25 | 26 | extend(CompletionType.BASIC, PlatformPatterns.psiElement()?.inside(XmlPatterns.xmlAttribute()!!), object : CompletionProvider() { 27 | protected override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext?, result: CompletionResultSet): Unit { 28 | if (parameters.getCompletionType() != CompletionType.BASIC) 29 | return 30 | 31 | directiveNames.forEach { 32 | name -> 33 | result.addElement(LookupElementBuilder.create("ng-" + name)!!.withInsertHandler(XmlAttributeInsertHandler.INSTANCE)!!) 34 | } 35 | } 36 | }) 37 | //will come back to tag autocomplete later... 38 | /* extend(CompletionType.BASIC, PlatformPatterns.psiElement()?.inside(XmlPatterns.xmlTag()!!), object : CompletionProvider() { 39 | protected override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext?, result: CompletionResultSet): Unit { 40 | if (parameters.getCompletionType() != CompletionType.BASIC) 41 | return 42 | 43 | result.addElement(LookupElementBuilder.create("johntag")!!.withInsertHandler(XmlAttributeInsertHandler.INSTANCE)!!) 44 | } 45 | })*/ 46 | } 47 | 48 | val directiveNames = array( 49 | "animate", 50 | "app", 51 | "bind", 52 | "bind-html-unsafe", 53 | "bind-template", 54 | "change", 55 | "checked", 56 | "class", 57 | "class-even", 58 | "class-odd", 59 | "click", 60 | "cloak", 61 | "controller", 62 | "csp", 63 | "dblclick", 64 | "disabled", 65 | "false-value", 66 | "form", 67 | "hide", 68 | "href", 69 | "if", 70 | "include", 71 | "init", 72 | "keypress", 73 | "list", 74 | "minlength", 75 | "maxlength", 76 | "model", 77 | "mousedown", 78 | "mouseup", 79 | "mouseover", 80 | "mouseout", 81 | "mousemove", 82 | "mouseenter", 83 | "mouseleave", 84 | "multiple", 85 | "non-bindable", 86 | "options", 87 | "pattern", 88 | "pluralize", 89 | "readonly", 90 | "repeat", 91 | "required", 92 | "selected", 93 | "show", 94 | "src", 95 | "srcset", 96 | "submit", 97 | "style", 98 | "swipe", 99 | "switch", 100 | "switch-when", 101 | "switch-default", 102 | "transclude", 103 | "true-value", 104 | "value", 105 | "view") 106 | 107 | // 108 | // public override fun fillCompletionVariants(parameters: CompletionParameters?, result: CompletionResultSet?): Unit { 109 | // result?.addElement(LookupElementBuilder.create("ng-click")!!) 110 | // } 111 | // 112 | // 113 | // public override fun beforeCompletion(context: CompletionInitializationContext) { 114 | // super.beforeCompletion(context) 115 | // 116 | // val offset: Int = context.getStartOffset() 117 | // val attributeValue = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), offset, javaClass(), true) 118 | // if (attributeValue != null && offset == (attributeValue.getTextRange()?.getStartOffset())!!) 119 | // { 120 | // context.setDummyIdentifier("") 121 | // } 122 | // } 123 | } 124 | -------------------------------------------------------------------------------- /src/org/angularjs/GotoAngularAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2012 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.angularjs; 17 | 18 | import com.intellij.codeInsight.navigation.NavigationUtil; 19 | import com.intellij.find.FindManager; 20 | import com.intellij.find.FindModel; 21 | import com.intellij.find.impl.FindInProjectUtil; 22 | import com.intellij.ide.IdeBundle; 23 | import com.intellij.ide.actions.GotoActionBase; 24 | import com.intellij.ide.util.gotoByName.ChooseByNameFilter; 25 | import com.intellij.ide.util.gotoByName.ChooseByNamePopup; 26 | import com.intellij.openapi.actionSystem.AnActionEvent; 27 | import com.intellij.openapi.actionSystem.DataContext; 28 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 29 | import com.intellij.openapi.application.ApplicationManager; 30 | import com.intellij.openapi.editor.Document; 31 | import com.intellij.openapi.project.Project; 32 | import com.intellij.openapi.util.Segment; 33 | import com.intellij.psi.PsiDirectory; 34 | import com.intellij.psi.PsiDocumentManager; 35 | import com.intellij.psi.PsiElement; 36 | import com.intellij.psi.PsiManager; 37 | import com.intellij.psi.util.PsiUtilBase; 38 | import com.intellij.usageView.UsageInfo; 39 | import com.intellij.usages.FindUsagesProcessPresentation; 40 | import com.intellij.usages.Usage; 41 | import com.intellij.usages.UsageInfo2UsageAdapter; 42 | import com.intellij.util.AdapterProcessor; 43 | import com.intellij.util.CommonProcessors; 44 | import com.intellij.util.Processor; 45 | import org.jetbrains.annotations.NotNull; 46 | 47 | import java.util.ArrayList; 48 | import java.util.Collection; 49 | import java.util.List; 50 | 51 | public class GotoAngularAction extends GotoActionBase { 52 | private static final int MODULE_METHODS = 0; 53 | private static final int CTRL_CONVENTIONS = 1; 54 | private static final int NG_CONTROLLER = 2; 55 | 56 | public GotoAngularAction() { 57 | getTemplatePresentation().setText(IdeBundle.message("goto.inspection.action.text")); 58 | } 59 | 60 | @Override 61 | protected void gotoActionPerformed(final AnActionEvent e) { 62 | final Project project = e.getData(PlatformDataKeys.PROJECT); 63 | if (project == null) return; 64 | 65 | PsiDocumentManager.getInstance(project).commitAllDocuments(); 66 | 67 | final DataContext dataContext = e.getDataContext(); 68 | 69 | final FindManager findManager = FindManager.getInstance(project); 70 | final FindModel findModel = (FindModel) findManager.getFindInFileModel().clone(); 71 | 72 | 73 | final List validResults = new ArrayList(); 74 | 75 | findModel.setRegularExpressions(true); 76 | findModel.setFileFilter("*.js, *.html"); 77 | 78 | findModel.setStringToFind("\\.(controller|filter|service|factory|module|value|constant|directive|provider)\\(\\s*(\"|')([^(\"|')]+)(\"|')"); 79 | findModel.setStringToReplace("$3"); 80 | final Collection moduleMethodUsages = getAngularUsages(project, dataContext, findModel); 81 | List moduleMethodResults = getValidResults(project, findModel, moduleMethodUsages, MODULE_METHODS); 82 | validResults.addAll(moduleMethodResults); 83 | 84 | findModel.setStringToFind("Ctrl\\(\\s*\\$scope"); 85 | findModel.setStringToReplace("$0"); 86 | final Collection ctrlByConventionUsages = getAngularUsages(project, dataContext, findModel); 87 | List ctrlByConventionResults = getValidResults(project, findModel, ctrlByConventionUsages, CTRL_CONVENTIONS); 88 | validResults.addAll(ctrlByConventionResults); 89 | 90 | 91 | findModel.setStringToFind("ng\\-controller\\=\"([^(\"]+)\""); 92 | findModel.setStringToReplace("$1"); 93 | final Collection ngControllerUsages = getAngularUsages(project, dataContext, findModel); 94 | List ngControllerResults = getValidResults(project, findModel, ngControllerUsages, NG_CONTROLLER); 95 | validResults.addAll(ngControllerResults); 96 | 97 | 98 | 99 | 100 | final GotoAngularModel model = new GotoAngularModel(project, validResults); 101 | showNavigationPopup(e, model, new GotoActionBase.GotoActionCallback() { 102 | @Override 103 | protected ChooseByNameFilter createFilter(@NotNull ChooseByNamePopup popup) { 104 | popup.setSearchInAnyPlace(true); 105 | popup.setShowListForEmptyPattern(true); 106 | popup.setMaximumListSizeLimit(255); 107 | return super.createFilter(popup); 108 | } 109 | 110 | @Override 111 | public void elementChosen(ChooseByNamePopup popup, final Object element) { 112 | ApplicationManager.getApplication().invokeLater(new Runnable() { 113 | public void run() { 114 | PsiElement psi = ((AngularItem) element).getElement(); 115 | NavigationUtil.activateFileWithPsiElement(psi.getNavigationElement()); 116 | } 117 | }); 118 | } 119 | }); 120 | } 121 | 122 | private List getValidResults(final Project project, final FindModel findModel, final Collection usages, final int type) { 123 | final List validResults = new ArrayList(); 124 | 125 | //todo: needs code review. There must be a better way to do this 126 | Runnable runnable = new Runnable() { 127 | public void run() { 128 | for (final Usage result : usages) { 129 | 130 | final UsageInfo2UsageAdapter usage = (UsageInfo2UsageAdapter) result; 131 | //avoid angular source files. Is there a better way to do this? 132 | if (usage.getFile().getName().startsWith("angular")) continue; 133 | 134 | usage.processRangeMarkers(new Processor() { 135 | @Override 136 | public boolean process(Segment segment) { 137 | try { 138 | final int textOffset = segment.getStartOffset(); 139 | 140 | final int textEndOffset = segment.getEndOffset(); 141 | Document document = usage.getDocument(); 142 | CharSequence charsSequence = document.getCharsSequence(); 143 | final CharSequence foundString = charsSequence.subSequence(textOffset, textEndOffset); 144 | String s = foundString.toString(); 145 | String regExMatch = FindManager.getInstance(project).getStringToReplace(s, findModel, textOffset, document.getText()); 146 | System.out.println(regExMatch); 147 | PsiElement element = PsiUtilBase.getElementAtOffset(((UsageInfo2UsageAdapter) result).getUsageInfo().getFile(), textOffset + 1); 148 | String elementText = element.getText(); 149 | System.out.println(elementText + ": " + regExMatch + " - " + s); 150 | //hack to block weird css matches (I have no idea how many edge cases I'll have :/ ) 151 | // if(regExMatch.length() > 20) return true; 152 | 153 | switch (type) { 154 | case CTRL_CONVENTIONS: 155 | validResults.add(new AngularItem(s, elementText, result, element, "controller")); 156 | break; 157 | 158 | case MODULE_METHODS: 159 | validResults.add(new AngularItem(s, regExMatch, result, element, element.getText())); 160 | break; 161 | 162 | case NG_CONTROLLER: 163 | validResults.add(new AngularItem(s, regExMatch, result, element, "ng-controller")); 164 | break; 165 | } 166 | 167 | return true; 168 | } catch (FindManager.MalformedReplacementStringException e1) { 169 | e1.printStackTrace(); 170 | } 171 | 172 | return false; 173 | } 174 | }); 175 | } 176 | } 177 | }; 178 | 179 | ApplicationManager.getApplication().runReadAction(runnable); 180 | return validResults; 181 | } 182 | 183 | private Collection getAngularUsages(Project project, DataContext dataContext, FindModel findModel) { 184 | 185 | FindInProjectUtil.setDirectoryName(findModel, dataContext); 186 | 187 | CommonProcessors.CollectProcessor collectProcessor = new CommonProcessors.CollectProcessor(); 188 | 189 | PsiDirectory directory = PsiManager.getInstance(project).findDirectory(project.getBaseDir()); 190 | FindInProjectUtil.findUsages(findModel, directory, project, 191 | true, new AdapterProcessor(collectProcessor, UsageInfo2UsageAdapter.CONVERTER), new FindUsagesProcessPresentation()); 192 | 193 | 194 | return collectProcessor.getResults(); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/org/angularjs/GotoAngularModel.java: -------------------------------------------------------------------------------- 1 | package org.angularjs; 2 | 3 | import com.intellij.ide.util.gotoByName.ChooseByNameBase; 4 | import com.intellij.ide.util.gotoByName.SimpleChooseByNameModel; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.ui.JBColor; 7 | import com.intellij.ui.SimpleColoredComponent; 8 | import com.intellij.ui.SimpleTextAttributes; 9 | import com.intellij.ui.speedSearch.SpeedSearchUtil; 10 | import com.intellij.util.ArrayUtil; 11 | import com.intellij.util.ui.UIUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import javax.swing.*; 16 | import java.awt.*; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * Created with IntelliJ IDEA. 22 | * User: johnlindquist 23 | * Date: 3/26/13 24 | * Time: 1:38 PM 25 | * To change this template use File | Settings | File Templates. 26 | */ 27 | public class GotoAngularModel extends SimpleChooseByNameModel{ 28 | 29 | private final List angularItems; 30 | 31 | public GotoAngularModel(@NotNull Project project, List angularItems) { 32 | super(project, "AngularJS", "Help id"); 33 | this.angularItems = angularItems; 34 | } 35 | 36 | //these are searched 37 | @Override 38 | public String[] getNames() { 39 | List strings = new ArrayList(); 40 | for (AngularItem angularItem : angularItems) { 41 | strings.add(angularItem.getKey()); 42 | } 43 | 44 | return ArrayUtil.toStringArray(strings); 45 | } 46 | 47 | //list provided to the item renderer 48 | @Override 49 | protected Object[] getElementsByName(String name, String pattern) { 50 | for (AngularItem angularItem : angularItems) { 51 | if (angularItem.getKey().equals(name)) { 52 | return new Object[]{angularItem}; 53 | } 54 | } 55 | 56 | return ArrayUtil.EMPTY_OBJECT_ARRAY; 57 | } 58 | 59 | @Override 60 | public ListCellRenderer getListCellRenderer() { 61 | return new GotoAngularCellRenderer(); 62 | } 63 | 64 | @Nullable 65 | @Override 66 | public String getElementName(Object element) { 67 | return "Element name!"; 68 | } 69 | 70 | protected class GotoAngularCellRenderer implements ListCellRenderer { 71 | private final SimpleTextAttributes SELECTED; 72 | private final SimpleTextAttributes PLAIN; 73 | 74 | 75 | public GotoAngularCellRenderer() { 76 | SELECTED = new SimpleTextAttributes(UIUtil.getListSelectionBackground(), 77 | UIUtil.getListSelectionForeground(), 78 | JBColor.RED, 79 | SimpleTextAttributes.STYLE_PLAIN); 80 | PLAIN = new SimpleTextAttributes(UIUtil.getListBackground(), 81 | UIUtil.getListForeground(), 82 | JBColor.RED, 83 | SimpleTextAttributes.STYLE_PLAIN); 84 | 85 | } 86 | 87 | @Override 88 | public Component getListCellRendererComponent(JList jList, Object value, int i, boolean sel, boolean focus) { 89 | JPanel jPanel = new JPanel(new BorderLayout()); 90 | jPanel.setOpaque(true); 91 | 92 | final Color bg = sel ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground(); 93 | final Color fg = sel ? UIUtil.getListSelectionForeground() : UIUtil.getListForeground(); 94 | jPanel.setBackground(bg); 95 | jPanel.setForeground(fg); 96 | 97 | SimpleTextAttributes attr = sel ? SELECTED : PLAIN; 98 | if (value instanceof AngularItem) { 99 | AngularItem item = (AngularItem) value; 100 | final SimpleColoredComponent c = new SimpleColoredComponent(); 101 | SpeedSearchUtil.appendColoredFragmentForMatcher(" " + item.getItemName(), c, attr, null, bg, sel); 102 | jPanel.add(c, BorderLayout.WEST); 103 | 104 | final SimpleColoredComponent group = new SimpleColoredComponent(); 105 | SpeedSearchUtil.appendColoredFragmentForMatcher(item.getItemType() + " ", group, attr, null, bg, sel); 106 | final JPanel right = new JPanel(new BorderLayout()); 107 | right.setBackground(bg); 108 | right.setForeground(fg); 109 | right.add(group, BorderLayout.CENTER); 110 | jPanel.add(right, BorderLayout.EAST); 111 | } 112 | else { 113 | // E.g. "..." item 114 | return ChooseByNameBase.renderNonPrefixSeparatorComponent(UIUtil.getListBackground()); 115 | } 116 | 117 | return jPanel; 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/org/angularjs/OpenInDocsIntention.kt: -------------------------------------------------------------------------------- 1 | package org.angularjs 2 | 3 | import com.intellij.ide.BrowserUtil 4 | import com.intellij.openapi.project.Project 5 | import com.intellij.openapi.editor.Editor 6 | import com.intellij.psi.PsiFile 7 | import com.intellij.codeInsight.intention.impl.QuickEditAction 8 | import com.intellij.psi.util.PsiUtilBase 9 | import com.intellij.lang.xml.XMLLanguage 10 | 11 | public class OpenInDocsIntention: QuickEditAction() { 12 | public override fun getText(): String { 13 | return "Open Angular Docs" 14 | } 15 | 16 | public override fun getFamilyName(): String { 17 | return "OpenInDocsIntention" 18 | } 19 | 20 | public override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean { 21 | val element = PsiUtilBase.getElementAtCaret(editor!!) 22 | 23 | return element is com.intellij.psi.impl.source.xml.XmlTokenImpl && 24 | element.getLanguage() == XMLLanguage.INSTANCE && 25 | element.getText()?.startsWith("ng")!! 26 | } 27 | 28 | public override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { 29 | val psiElement = PsiUtilBase.getElementAtCaret(editor!!) 30 | 31 | 32 | var string = psiElement?.getText()!! 33 | val strings = string.split("-") 34 | 35 | var result = "ng" 36 | for(i in strings.indices){ 37 | val s = strings.get(i) 38 | if(s == "ng") continue 39 | result += s.capitalize() 40 | } 41 | 42 | 43 | val url = "http://docs.angularjs.org/api/ng.directive:" + result 44 | BrowserUtil.launchBrowser(url) 45 | } 46 | } --------------------------------------------------------------------------------